mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Simplify paginated implementation
* Remove maxAlerts parameter. * Reuse existing API responses by using omitempty in some fields Signed-off-by: Raphael Silva <rapphil@gmail.com>
This commit is contained in:
parent
bbd2f1cff8
commit
57592168b0
|
@ -170,7 +170,6 @@ type apiFuncResult struct {
|
|||
type apiFunc func(r *http.Request) apiFuncResult
|
||||
|
||||
type listRulesPaginationRequest struct {
|
||||
MaxAlerts int64
|
||||
MaxRuleGroups int64
|
||||
NextToken string
|
||||
}
|
||||
|
@ -1339,12 +1338,7 @@ func (api *API) metricMetadata(r *http.Request) apiFuncResult {
|
|||
// RuleDiscovery has info for all rules.
|
||||
type RuleDiscovery struct {
|
||||
RuleGroups []*RuleGroup `json:"groups"`
|
||||
}
|
||||
|
||||
// PaginatedRuleDiscovery has info for all rules with pagination.
|
||||
type PaginatedRuleDiscovery struct {
|
||||
RuleGroups []*RuleGroup `json:"groups"`
|
||||
NextToken string `json:"nextToken"`
|
||||
NextToken string `json:"nextToken:omitempty"`
|
||||
}
|
||||
|
||||
// RuleGroup has info for rules which are part of a group.
|
||||
|
@ -1381,29 +1375,6 @@ type AlertingRule struct {
|
|||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type AlertingRulePaginated struct {
|
||||
// State can be "pending", "firing", "inactive".
|
||||
State string `json:"state"`
|
||||
Name string `json:"name"`
|
||||
Query string `json:"query"`
|
||||
Duration float64 `json:"duration"`
|
||||
KeepFiringFor float64 `json:"keepFiringFor"`
|
||||
Labels labels.Labels `json:"labels"`
|
||||
Annotations labels.Labels `json:"annotations"`
|
||||
PartialAlerts *PartialAlerts `json:"alertInfo"`
|
||||
Health rules.RuleHealth `json:"health"`
|
||||
LastError string `json:"lastError,omitempty"`
|
||||
EvaluationTime float64 `json:"evaluationTime"`
|
||||
LastEvaluation time.Time `json:"lastEvaluation"`
|
||||
// Type of an alertingRule is always "alerting".
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type PartialAlerts struct {
|
||||
Alerts []*Alert `json:"alerts"`
|
||||
HasMore bool `json:"hasMore"`
|
||||
}
|
||||
|
||||
type RecordingRule struct {
|
||||
Name string `json:"name"`
|
||||
Query string `json:"query"`
|
||||
|
@ -1459,6 +1430,7 @@ func (api *API) rules(r *http.Request) apiFuncResult {
|
|||
}
|
||||
|
||||
rgs := make([]*RuleGroup, 0, len(ruleGroups))
|
||||
|
||||
for _, grp := range ruleGroups {
|
||||
if len(rgSet) > 0 {
|
||||
if _, ok := rgSet[grp.Name()]; !ok {
|
||||
|
@ -1509,48 +1481,23 @@ func (api *API) rules(r *http.Request) apiFuncResult {
|
|||
if !excludeAlerts {
|
||||
activeAlerts = rulesAlertsToAPIAlerts(rule.ActiveAlerts())
|
||||
}
|
||||
hasMore := false
|
||||
if paginationRequest != nil && paginationRequest.MaxAlerts >= 0 && len(activeAlerts) > int(paginationRequest.MaxAlerts) {
|
||||
activeAlerts = activeAlerts[:int(paginationRequest.MaxAlerts)]
|
||||
hasMore = true
|
||||
|
||||
enrichedRule = AlertingRule{
|
||||
State: rule.State().String(),
|
||||
Name: rule.Name(),
|
||||
Query: rule.Query().String(),
|
||||
Duration: rule.HoldDuration().Seconds(),
|
||||
KeepFiringFor: rule.KeepFiringFor().Seconds(),
|
||||
Labels: rule.Labels(),
|
||||
Annotations: rule.Annotations(),
|
||||
Alerts: activeAlerts,
|
||||
Health: rule.Health(),
|
||||
LastError: lastError,
|
||||
EvaluationTime: rule.GetEvaluationDuration().Seconds(),
|
||||
LastEvaluation: rule.GetEvaluationTimestamp(),
|
||||
Type: "alerting",
|
||||
}
|
||||
|
||||
if paginationRequest != nil {
|
||||
enrichedRule = AlertingRulePaginated{
|
||||
State: rule.State().String(),
|
||||
Name: rule.Name(),
|
||||
Query: rule.Query().String(),
|
||||
Duration: rule.HoldDuration().Seconds(),
|
||||
KeepFiringFor: rule.KeepFiringFor().Seconds(),
|
||||
Labels: rule.Labels(),
|
||||
Annotations: rule.Annotations(),
|
||||
PartialAlerts: &PartialAlerts{
|
||||
Alerts: activeAlerts,
|
||||
HasMore: hasMore,
|
||||
},
|
||||
Health: rule.Health(),
|
||||
LastError: lastError,
|
||||
EvaluationTime: rule.GetEvaluationDuration().Seconds(),
|
||||
LastEvaluation: rule.GetEvaluationTimestamp(),
|
||||
Type: "alerting",
|
||||
}
|
||||
} else {
|
||||
enrichedRule = AlertingRule{
|
||||
State: rule.State().String(),
|
||||
Name: rule.Name(),
|
||||
Query: rule.Query().String(),
|
||||
Duration: rule.HoldDuration().Seconds(),
|
||||
KeepFiringFor: rule.KeepFiringFor().Seconds(),
|
||||
Labels: rule.Labels(),
|
||||
Annotations: rule.Annotations(),
|
||||
Alerts: activeAlerts,
|
||||
Health: rule.Health(),
|
||||
LastError: lastError,
|
||||
EvaluationTime: rule.GetEvaluationDuration().Seconds(),
|
||||
LastEvaluation: rule.GetEvaluationTimestamp(),
|
||||
Type: "alerting",
|
||||
}
|
||||
}
|
||||
case *rules.RecordingRule:
|
||||
if !returnRecording {
|
||||
break
|
||||
|
@ -1582,11 +1529,10 @@ func (api *API) rules(r *http.Request) apiFuncResult {
|
|||
}
|
||||
|
||||
if paginationRequest != nil {
|
||||
paginatedRes := &PaginatedRuleDiscovery{RuleGroups: make([]*RuleGroup, 0, len(ruleGroups))}
|
||||
returnGroups, nextToken := TruncateGroupInfos(rgs, int(paginationRequest.MaxRuleGroups))
|
||||
paginatedRes.RuleGroups = returnGroups
|
||||
paginatedRes.NextToken = nextToken
|
||||
return apiFuncResult{paginatedRes, nil, nil, nil}
|
||||
res.NextToken = nextToken
|
||||
res.RuleGroups = returnGroups
|
||||
return apiFuncResult{res, nil, nil, nil}
|
||||
}
|
||||
|
||||
res.RuleGroups = rgs
|
||||
|
@ -1609,28 +1555,17 @@ func parseExcludeAlerts(r *http.Request) (bool, error) {
|
|||
|
||||
func parseListRulesPaginationRequest(r *http.Request) (*listRulesPaginationRequest, *parsePaginationError) {
|
||||
var (
|
||||
maxAlerts int64 = -1
|
||||
maxRuleGroups int64 = -1
|
||||
nextToken = ""
|
||||
err error
|
||||
)
|
||||
|
||||
if r.URL.Query().Get("maxAlerts") != "" {
|
||||
maxAlerts, err = strconv.ParseInt(r.URL.Query().Get("maxAlerts"), 10, 32)
|
||||
if err != nil || maxAlerts < 0 {
|
||||
return nil, &parsePaginationError{
|
||||
err: fmt.Errorf("maxAlerts need to be a valid number greater than or equal to 0: %w", err),
|
||||
parameter: "maxAlerts",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if r.URL.Query().Get("maxRuleGroups") != "" {
|
||||
maxRuleGroups, err = strconv.ParseInt(r.URL.Query().Get("maxRuleGroups"), 10, 32)
|
||||
if err != nil || maxRuleGroups < 0 {
|
||||
return nil, &parsePaginationError{
|
||||
err: fmt.Errorf("maxRuleGroups need to be a valid number greater than or equal to 0: %w", err),
|
||||
parameter: "maxAlerts",
|
||||
parameter: "maxRuleGroups",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1639,10 +1574,9 @@ func parseListRulesPaginationRequest(r *http.Request) (*listRulesPaginationReque
|
|||
nextToken = r.URL.Query().Get("nextToken")
|
||||
}
|
||||
|
||||
if maxAlerts >= 0 || maxRuleGroups >= 0 || nextToken != "" {
|
||||
if maxRuleGroups >= 0 || nextToken != "" {
|
||||
return &listRulesPaginationRequest{
|
||||
MaxRuleGroups: maxRuleGroups,
|
||||
MaxAlerts: maxAlerts,
|
||||
NextToken: nextToken,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -1073,54 +1073,28 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E
|
|||
}
|
||||
|
||||
rulesZeroFunc := func(i interface{}) {
|
||||
if i != nil {
|
||||
switch v := i.(type) {
|
||||
case *RuleDiscovery:
|
||||
for _, ruleGroup := range v.RuleGroups {
|
||||
ruleGroup.EvaluationTime = float64(0)
|
||||
ruleGroup.LastEvaluation = time.Time{}
|
||||
for k, rule := range ruleGroup.Rules {
|
||||
switch r := rule.(type) {
|
||||
case AlertingRule:
|
||||
r.LastEvaluation = time.Time{}
|
||||
r.EvaluationTime = float64(0)
|
||||
r.LastError = ""
|
||||
r.Health = "ok"
|
||||
for _, alert := range r.Alerts {
|
||||
alert.ActiveAt = nil
|
||||
}
|
||||
ruleGroup.Rules[k] = r
|
||||
case RecordingRule:
|
||||
r.LastEvaluation = time.Time{}
|
||||
r.EvaluationTime = float64(0)
|
||||
r.LastError = ""
|
||||
r.Health = "ok"
|
||||
ruleGroup.Rules[k] = r
|
||||
}
|
||||
}
|
||||
}
|
||||
case *PaginatedRuleDiscovery:
|
||||
for _, ruleGroup := range v.RuleGroups {
|
||||
ruleGroup.EvaluationTime = float64(0)
|
||||
ruleGroup.LastEvaluation = time.Time{}
|
||||
for k, rule := range ruleGroup.Rules {
|
||||
switch r := rule.(type) {
|
||||
case AlertingRulePaginated:
|
||||
r.LastEvaluation = time.Time{}
|
||||
r.EvaluationTime = float64(0)
|
||||
r.LastError = ""
|
||||
r.Health = "ok"
|
||||
for _, alert := range r.PartialAlerts.Alerts {
|
||||
alert.ActiveAt = nil
|
||||
}
|
||||
ruleGroup.Rules[k] = r
|
||||
case RecordingRule:
|
||||
r.LastEvaluation = time.Time{}
|
||||
r.EvaluationTime = float64(0)
|
||||
r.LastError = ""
|
||||
r.Health = "ok"
|
||||
ruleGroup.Rules[k] = r
|
||||
v := i.(*RuleDiscovery)
|
||||
if v != nil {
|
||||
for _, ruleGroup := range v.RuleGroups {
|
||||
ruleGroup.EvaluationTime = float64(0)
|
||||
ruleGroup.LastEvaluation = time.Time{}
|
||||
for k, rule := range ruleGroup.Rules {
|
||||
switch r := rule.(type) {
|
||||
case AlertingRule:
|
||||
r.LastEvaluation = time.Time{}
|
||||
r.EvaluationTime = float64(0)
|
||||
r.LastError = ""
|
||||
r.Health = "ok"
|
||||
for _, alert := range r.Alerts {
|
||||
alert.ActiveAt = nil
|
||||
}
|
||||
ruleGroup.Rules[k] = r
|
||||
case RecordingRule:
|
||||
r.LastEvaluation = time.Time{}
|
||||
r.EvaluationTime = float64(0)
|
||||
r.LastError = ""
|
||||
r.Health = "ok"
|
||||
ruleGroup.Rules[k] = r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2432,7 +2406,7 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E
|
|||
query: url.Values{
|
||||
"maxRuleGroups": []string{"1"},
|
||||
},
|
||||
response: &PaginatedRuleDiscovery{
|
||||
response: &RuleDiscovery{
|
||||
NextToken: getRuleGroupNextToken("/path/to/file", "grp"),
|
||||
RuleGroups: []*RuleGroup{
|
||||
{
|
||||
|
@ -2441,43 +2415,41 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E
|
|||
Interval: 1,
|
||||
Limit: 0,
|
||||
Rules: []Rule{
|
||||
AlertingRulePaginated{
|
||||
State: "inactive",
|
||||
Name: "test_metric3",
|
||||
Query: "absent(test_metric3) != 1",
|
||||
Duration: 1,
|
||||
Labels: labels.Labels{},
|
||||
Annotations: labels.Labels{},
|
||||
PartialAlerts: &PartialAlerts{Alerts: []*Alert{}},
|
||||
Health: "ok",
|
||||
Type: "alerting",
|
||||
AlertingRule{
|
||||
State: "inactive",
|
||||
Name: "test_metric3",
|
||||
Query: "absent(test_metric3) != 1",
|
||||
Duration: 1,
|
||||
Labels: labels.Labels{},
|
||||
Annotations: labels.Labels{},
|
||||
Alerts: []*Alert{},
|
||||
Health: "ok",
|
||||
Type: "alerting",
|
||||
},
|
||||
AlertingRulePaginated{
|
||||
State: "inactive",
|
||||
Name: "test_metric4",
|
||||
Query: "up == 1",
|
||||
Duration: 1,
|
||||
Labels: labels.Labels{},
|
||||
Annotations: labels.Labels{},
|
||||
PartialAlerts: &PartialAlerts{Alerts: []*Alert{}},
|
||||
Health: "ok",
|
||||
Type: "alerting",
|
||||
AlertingRule{
|
||||
State: "inactive",
|
||||
Name: "test_metric4",
|
||||
Query: "up == 1",
|
||||
Duration: 1,
|
||||
Labels: labels.Labels{},
|
||||
Annotations: labels.Labels{},
|
||||
Alerts: []*Alert{},
|
||||
Health: "ok",
|
||||
Type: "alerting",
|
||||
},
|
||||
AlertingRulePaginated{
|
||||
AlertingRule{
|
||||
State: "pending",
|
||||
Name: "test_metric5",
|
||||
Query: "vector(1)",
|
||||
Duration: 1,
|
||||
Labels: labels.FromStrings("name", "tm5"),
|
||||
Annotations: labels.Labels{},
|
||||
PartialAlerts: &PartialAlerts{
|
||||
Alerts: []*Alert{
|
||||
{
|
||||
Labels: labels.FromStrings("alertname", "test_metric5", "name", "tm5"),
|
||||
Annotations: labels.Labels{},
|
||||
State: "pending",
|
||||
Value: "1e+00",
|
||||
},
|
||||
Alerts: []*Alert{
|
||||
{
|
||||
Labels: labels.FromStrings("alertname", "test_metric5", "name", "tm5"),
|
||||
Annotations: labels.Labels{},
|
||||
State: "pending",
|
||||
Value: "1e+00",
|
||||
},
|
||||
},
|
||||
Health: "ok",
|
||||
|
@ -2496,87 +2468,6 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, es storage.E
|
|||
},
|
||||
zeroFunc: rulesZeroFunc,
|
||||
},
|
||||
{
|
||||
endpoint: api.rules,
|
||||
query: url.Values{
|
||||
"maxAlerts": []string{"0"},
|
||||
},
|
||||
response: &PaginatedRuleDiscovery{
|
||||
RuleGroups: []*RuleGroup{
|
||||
{
|
||||
Name: "grp",
|
||||
File: "/path/to/file",
|
||||
Interval: 1,
|
||||
Limit: 0,
|
||||
Rules: []Rule{
|
||||
AlertingRulePaginated{
|
||||
State: "inactive",
|
||||
Name: "test_metric3",
|
||||
Query: "absent(test_metric3) != 1",
|
||||
Duration: 1,
|
||||
Labels: labels.Labels{},
|
||||
Annotations: labels.Labels{},
|
||||
PartialAlerts: &PartialAlerts{Alerts: []*Alert{}},
|
||||
Health: "ok",
|
||||
Type: "alerting",
|
||||
},
|
||||
AlertingRulePaginated{
|
||||
State: "inactive",
|
||||
Name: "test_metric4",
|
||||
Query: "up == 1",
|
||||
Duration: 1,
|
||||
Labels: labels.Labels{},
|
||||
Annotations: labels.Labels{},
|
||||
PartialAlerts: &PartialAlerts{Alerts: []*Alert{}},
|
||||
Health: "ok",
|
||||
Type: "alerting",
|
||||
},
|
||||
AlertingRulePaginated{
|
||||
State: "pending",
|
||||
Name: "test_metric5",
|
||||
Query: "vector(1)",
|
||||
Duration: 1,
|
||||
Labels: labels.FromStrings("name", "tm5"),
|
||||
Annotations: labels.Labels{},
|
||||
PartialAlerts: &PartialAlerts{
|
||||
Alerts: []*Alert{},
|
||||
HasMore: true,
|
||||
},
|
||||
Health: "ok",
|
||||
Type: "alerting",
|
||||
},
|
||||
RecordingRule{
|
||||
Name: "recording-rule-1",
|
||||
Query: "vector(1)",
|
||||
Labels: labels.Labels{},
|
||||
Health: "ok",
|
||||
Type: "recording",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "grp2",
|
||||
File: "/path/to/file",
|
||||
Interval: 1,
|
||||
Limit: 0,
|
||||
Rules: []Rule{
|
||||
AlertingRulePaginated{
|
||||
State: "inactive",
|
||||
Name: "test_metric3",
|
||||
Query: "absent(test_metric3) != 1",
|
||||
Duration: 1,
|
||||
Labels: labels.Labels{},
|
||||
Annotations: labels.Labels{},
|
||||
PartialAlerts: &PartialAlerts{Alerts: []*Alert{}},
|
||||
Health: "ok",
|
||||
Type: "alerting",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
zeroFunc: rulesZeroFunc,
|
||||
},
|
||||
{
|
||||
endpoint: api.queryExemplars,
|
||||
query: url.Values{
|
||||
|
|
Loading…
Reference in a new issue