package api import ( "fmt" "net/http" "time" "github.com/grafana/grafana/pkg/services/ngalert/eval" apiv1 "github.com/prometheus/client_golang/api/prometheus/v1" ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/store" "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/models" apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" "github.com/grafana/grafana/pkg/services/ngalert/state" ) type PrometheusSrv struct { log log.Logger stateTracker *state.StateTracker store store.RuleStore } func (srv PrometheusSrv) RouteGetAlertStatuses(c *models.ReqContext) response.Response { alertResponse := apimodels.AlertResponse{ DiscoveryBase: apimodels.DiscoveryBase{ Status: "success", }, Data: apimodels.AlertDiscovery{ Alerts: []*apimodels.Alert{}, }, } for _, alertState := range srv.stateTracker.GetAll() { startsAt := alertState.StartsAt alertResponse.Data.Alerts = append(alertResponse.Data.Alerts, &apimodels.Alert{ Labels: map[string]string(alertState.Labels), Annotations: map[string]string{}, //TODO: Once annotations are added to the evaluation result, set them here State: alertState.State.String(), ActiveAt: &startsAt, Value: "", //TODO: once the result of the evaluation is added to the evaluation result, set it here }) } return response.JSON(http.StatusOK, alertResponse) } func (srv PrometheusSrv) RouteGetRuleStatuses(c *models.ReqContext) response.Response { ruleResponse := apimodels.RuleResponse{ DiscoveryBase: apimodels.DiscoveryBase{ Status: "success", }, Data: apimodels.RuleDiscovery{ RuleGroups: []*apimodels.RuleGroup{}, }, } ruleGroupQuery := ngmodels.ListOrgRuleGroupsQuery{ OrgID: c.SignedInUser.OrgId, } if err := srv.store.GetOrgRuleGroups(&ruleGroupQuery); err != nil { ruleResponse.DiscoveryBase.Status = "error" ruleResponse.DiscoveryBase.Error = fmt.Sprintf("failure getting rule groups: %s", err.Error()) ruleResponse.DiscoveryBase.ErrorType = apiv1.ErrServer return response.JSON(http.StatusInternalServerError, ruleResponse) } for _, r := range ruleGroupQuery.Result { if len(r) < 3 { continue } groupId, namespaceUID, namespace := r[0], r[1], r[2] alertRuleQuery := ngmodels.ListRuleGroupAlertRulesQuery{OrgID: c.SignedInUser.OrgId, NamespaceUID: namespaceUID, RuleGroup: groupId} if err := srv.store.GetRuleGroupAlertRules(&alertRuleQuery); err != nil { ruleResponse.DiscoveryBase.Status = "error" ruleResponse.DiscoveryBase.Error = fmt.Sprintf("failure getting rules for group %s: %s", groupId, err.Error()) ruleResponse.DiscoveryBase.ErrorType = apiv1.ErrServer return response.JSON(http.StatusInternalServerError, ruleResponse) } newGroup := &apimodels.RuleGroup{ Name: groupId, // This doesn't make sense in our architecture // so we use this field for passing to the frontend the namespace File: namespace, LastEvaluation: time.Time{}, EvaluationTime: 0, // TODO: see if we are able to pass this along with evaluation results } stateMap := srv.stateTracker.GetStatesByRuleUID() for _, rule := range alertRuleQuery.Result { alertingRule := apimodels.AlertingRule{ State: "inactive", Name: rule.Title, Query: rule.DataToString(), // TODO: don't escape <>& etc Duration: rule.For.Seconds(), Annotations: rule.Annotations, } newRule := apimodels.Rule{ Name: rule.Title, Labels: rule.Labels, Health: "ok", Type: apiv1.RuleTypeAlerting, LastEvaluation: time.Time{}, } for _, alertState := range stateMap[rule.UID] { activeAt := alertState.StartsAt alert := &apimodels.Alert{ Labels: map[string]string(alertState.Labels), Annotations: alertState.Annotations, State: alertState.State.String(), ActiveAt: &activeAt, Value: "", // TODO: set this once it is added to the evaluation results } if alertState.LastEvaluationTime.After(newRule.LastEvaluation) { newRule.LastEvaluation = alertState.LastEvaluationTime newGroup.LastEvaluation = alertState.LastEvaluationTime } alertingRule.Duration = alertState.EvaluationDuration.Seconds() newRule.EvaluationTime = alertState.EvaluationDuration.Seconds() switch alertState.State { case eval.Normal: case eval.Pending: if alertingRule.State == "inactive" { alertingRule.State = "pending" } case eval.Alerting: alertingRule.State = "firing" case eval.Error: newRule.Health = "error" case eval.NoData: newRule.Health = "nodata" } alertingRule.Alerts = append(alertingRule.Alerts, alert) } alertingRule.Rule = newRule newGroup.Rules = append(newGroup.Rules, alertingRule) newGroup.Interval = float64(rule.IntervalSeconds) } ruleResponse.Data.RuleGroups = append(ruleResponse.Data.RuleGroups, newGroup) } return response.JSON(http.StatusOK, ruleResponse) }