|
|
|
|
@ -1,7 +1,14 @@ |
|
|
|
|
package api |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"fmt" |
|
|
|
|
"net/http" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
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" |
|
|
|
|
|
|
|
|
|
apimodels "github.com/grafana/alerting-api/pkg/api" |
|
|
|
|
"github.com/grafana/grafana/pkg/api/response" |
|
|
|
|
@ -13,6 +20,7 @@ import ( |
|
|
|
|
type PrometheusSrv struct { |
|
|
|
|
log log.Logger |
|
|
|
|
stateTracker *state.StateTracker |
|
|
|
|
store store.RuleStore |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (srv PrometheusSrv) RouteGetAlertStatuses(c *models.ReqContext) response.Response { |
|
|
|
|
@ -38,7 +46,108 @@ func (srv PrometheusSrv) RouteGetAlertStatuses(c *models.ReqContext) response.Re |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (srv PrometheusSrv) RouteGetRuleStatuses(c *models.ReqContext) response.Response { |
|
|
|
|
recipient := c.Params(":Recipient") |
|
|
|
|
srv.log.Info("RouteGetRuleStatuses: ", "Recipient", recipient) |
|
|
|
|
return response.Error(http.StatusNotImplemented, "", nil) |
|
|
|
|
ruleResponse := apimodels.RuleResponse{ |
|
|
|
|
DiscoveryBase: apimodels.DiscoveryBase{ |
|
|
|
|
Status: "success", |
|
|
|
|
}, |
|
|
|
|
Data: apimodels.RuleDiscovery{}, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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 _, groupId := range ruleGroupQuery.Result { |
|
|
|
|
alertRuleQuery := ngmodels.ListRuleGroupAlertRulesQuery{OrgID: c.SignedInUser.OrgId, 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, |
|
|
|
|
File: "", // This doesn't make sense in our architecture but would be a good use case for provisioned alerts.
|
|
|
|
|
LastEvaluation: time.Time{}, |
|
|
|
|
EvaluationTime: 0, // TODO: see if we are able to pass this along with evaluation results
|
|
|
|
|
} |
|
|
|
|
for _, rule := range alertRuleQuery.Result { |
|
|
|
|
instanceQuery := ngmodels.ListAlertInstancesQuery{ |
|
|
|
|
DefinitionOrgID: c.SignedInUser.OrgId, |
|
|
|
|
DefinitionUID: rule.UID, |
|
|
|
|
} |
|
|
|
|
if err := srv.store.ListAlertInstances(&instanceQuery); err != nil { |
|
|
|
|
ruleResponse.DiscoveryBase.Status = "error" |
|
|
|
|
ruleResponse.DiscoveryBase.Error = fmt.Sprintf("failure getting alerts for rule %s: %s", rule.UID, err.Error()) |
|
|
|
|
ruleResponse.DiscoveryBase.ErrorType = apiv1.ErrServer |
|
|
|
|
return response.JSON(http.StatusInternalServerError, ruleResponse) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
alertingRule := apimodels.AlertingRule{ |
|
|
|
|
State: "inactive", |
|
|
|
|
Name: rule.Title, |
|
|
|
|
Query: "", // TODO: get this from parsing AlertRule.Data
|
|
|
|
|
Duration: time.Duration(rule.For).Seconds(), |
|
|
|
|
Annotations: rule.Annotations, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
newRule := apimodels.Rule{ |
|
|
|
|
Name: rule.Title, |
|
|
|
|
Labels: nil, // TODO: NG AlertRule does not have labels but does have annotations
|
|
|
|
|
Health: "ok", // TODO: update this in the future when error and noData states are being evaluated and set
|
|
|
|
|
Type: apiv1.RuleTypeAlerting, |
|
|
|
|
LastEvaluation: time.Time{}, // TODO: set this to be rule evaluation time once it is being set
|
|
|
|
|
EvaluationTime: 0, // TODO: set this once we are saving it or adding it to evaluation results
|
|
|
|
|
} |
|
|
|
|
for _, instance := range instanceQuery.Result { |
|
|
|
|
activeAt := instance.CurrentStateSince |
|
|
|
|
alert := &apimodels.Alert{ |
|
|
|
|
Labels: map[string]string(instance.Labels), |
|
|
|
|
Annotations: nil, // TODO: set these once they are added to evaluation results
|
|
|
|
|
State: translateInstanceState(instance.CurrentState), |
|
|
|
|
ActiveAt: &activeAt, |
|
|
|
|
Value: "", // TODO: set this once it is added to the evaluation results
|
|
|
|
|
} |
|
|
|
|
if instance.LastEvalTime.After(newRule.LastEvaluation) { |
|
|
|
|
newRule.LastEvaluation = instance.LastEvalTime |
|
|
|
|
newGroup.LastEvaluation = instance.LastEvalTime |
|
|
|
|
} |
|
|
|
|
switch alert.State { |
|
|
|
|
case "pending": |
|
|
|
|
if alertingRule.State == "inactive" { |
|
|
|
|
alertingRule.State = "pending" |
|
|
|
|
} |
|
|
|
|
case "firing": |
|
|
|
|
alertingRule.State = "firing" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func translateInstanceState(state ngmodels.InstanceStateType) string { |
|
|
|
|
switch { |
|
|
|
|
case state == ngmodels.InstanceStateFiring: |
|
|
|
|
return "firing" |
|
|
|
|
case state == ngmodels.InstanceStateNormal: |
|
|
|
|
return "inactive" |
|
|
|
|
case state == ngmodels.InstanceStatePending: |
|
|
|
|
return "pending" |
|
|
|
|
default: |
|
|
|
|
return "inactive" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|