| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2021-09-03 00:38:42 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:34 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/datasources" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/ngalert/store" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/quota" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/prometheus/common/model" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-25 21:11:22 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/apierrors" | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/response" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/infra/log" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/models" | 
					
						
							| 
									
										
										
										
											2021-04-20 02:26:04 +08:00
										 |  |  | 	apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:34 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/ngalert/schedule" | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/util" | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/web" | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type RulerSrv struct { | 
					
						
							| 
									
										
										
										
											2021-04-28 16:31:51 +08:00
										 |  |  | 	store           store.RuleStore | 
					
						
							|  |  |  | 	DatasourceCache datasources.CacheService | 
					
						
							| 
									
										
										
										
											2021-05-05 00:16:28 +08:00
										 |  |  | 	QuotaService    *quota.QuotaService | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:34 +08:00
										 |  |  | 	scheduleService schedule.ScheduleService | 
					
						
							| 
									
										
										
										
											2021-04-28 16:31:51 +08:00
										 |  |  | 	log             log.Logger | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (srv RulerSrv) RouteDeleteNamespaceRulesConfig(c *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 	namespaceTitle := web.Params(c.Req)[":Namespace"] | 
					
						
							| 
									
										
										
										
											2021-09-14 22:08:04 +08:00
										 |  |  | 	namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgId, c.SignedInUser, true) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 		return toNamespaceErrorResponse(err) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-04 02:01:33 +08:00
										 |  |  | 	uids, err := srv.store.DeleteNamespaceAlertRules(c.SignedInUser.OrgId, namespace.Uid) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 		return ErrResp(http.StatusInternalServerError, err, "failed to delete namespace alert rules") | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-05-04 02:01:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for _, uid := range uids { | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:34 +08:00
										 |  |  | 		srv.scheduleService.DeleteAlertRule(ngmodels.AlertRuleKey{ | 
					
						
							|  |  |  | 			OrgID: c.SignedInUser.OrgId, | 
					
						
							|  |  |  | 			UID:   uid, | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2021-05-04 02:01:33 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	return response.JSON(http.StatusAccepted, util.DynMap{"message": "namespace rules deleted"}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (srv RulerSrv) RouteDeleteRuleGroupConfig(c *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 	namespaceTitle := web.Params(c.Req)[":Namespace"] | 
					
						
							| 
									
										
										
										
											2021-09-14 22:08:04 +08:00
										 |  |  | 	namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgId, c.SignedInUser, true) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 		return toNamespaceErrorResponse(err) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 	ruleGroup := web.Params(c.Req)[":Groupname"] | 
					
						
							| 
									
										
										
										
											2021-05-04 02:01:33 +08:00
										 |  |  | 	uids, err := srv.store.DeleteRuleGroupAlertRules(c.SignedInUser.OrgId, namespace.Uid, ruleGroup) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-16 20:00:07 +08:00
										 |  |  | 		if errors.Is(err, ngmodels.ErrRuleGroupNamespaceNotFound) { | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 			return ErrResp(http.StatusNotFound, err, "failed to delete rule group") | 
					
						
							| 
									
										
										
										
											2021-04-16 20:00:07 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 		return ErrResp(http.StatusInternalServerError, err, "failed to delete rule group") | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-04-16 20:00:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-04 02:01:33 +08:00
										 |  |  | 	for _, uid := range uids { | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:34 +08:00
										 |  |  | 		srv.scheduleService.DeleteAlertRule(ngmodels.AlertRuleKey{ | 
					
						
							|  |  |  | 			OrgID: c.SignedInUser.OrgId, | 
					
						
							|  |  |  | 			UID:   uid, | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2021-05-04 02:01:33 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	return response.JSON(http.StatusAccepted, util.DynMap{"message": "rule group deleted"}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (srv RulerSrv) RouteGetNamespaceRulesConfig(c *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 	namespaceTitle := web.Params(c.Req)[":Namespace"] | 
					
						
							| 
									
										
										
										
											2021-09-14 22:08:04 +08:00
										 |  |  | 	namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgId, c.SignedInUser, false) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 		return toNamespaceErrorResponse(err) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	q := ngmodels.ListNamespaceAlertRulesQuery{ | 
					
						
							|  |  |  | 		OrgID:        c.SignedInUser.OrgId, | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 		NamespaceUID: namespace.Uid, | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if err := srv.store.GetNamespaceAlertRules(&q); err != nil { | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 		return ErrResp(http.StatusInternalServerError, err, "failed to update rule group") | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result := apimodels.NamespaceConfigResponse{} | 
					
						
							|  |  |  | 	ruleGroupConfigs := make(map[string]apimodels.GettableRuleGroupConfig) | 
					
						
							|  |  |  | 	for _, r := range q.Result { | 
					
						
							|  |  |  | 		ruleGroupConfig, ok := ruleGroupConfigs[r.RuleGroup] | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							|  |  |  | 			ruleGroupInterval := model.Duration(time.Duration(r.IntervalSeconds) * time.Second) | 
					
						
							|  |  |  | 			ruleGroupConfigs[r.RuleGroup] = apimodels.GettableRuleGroupConfig{ | 
					
						
							|  |  |  | 				Name:     r.RuleGroup, | 
					
						
							|  |  |  | 				Interval: ruleGroupInterval, | 
					
						
							|  |  |  | 				Rules: []apimodels.GettableExtendedRuleNode{ | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 					toGettableExtendedRuleNode(*r, namespace.Id), | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 				}, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 			ruleGroupConfig.Rules = append(ruleGroupConfig.Rules, toGettableExtendedRuleNode(*r, namespace.Id)) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 			ruleGroupConfigs[r.RuleGroup] = ruleGroupConfig | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, ruleGroupConfig := range ruleGroupConfigs { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 		result[namespaceTitle] = append(result[namespaceTitle], ruleGroupConfig) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return response.JSON(http.StatusAccepted, result) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (srv RulerSrv) RouteGetRulegGroupConfig(c *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 	namespaceTitle := web.Params(c.Req)[":Namespace"] | 
					
						
							| 
									
										
										
										
											2021-09-14 22:08:04 +08:00
										 |  |  | 	namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgId, c.SignedInUser, false) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 		return toNamespaceErrorResponse(err) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 	ruleGroup := web.Params(c.Req)[":Groupname"] | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	q := ngmodels.ListRuleGroupAlertRulesQuery{ | 
					
						
							|  |  |  | 		OrgID:        c.SignedInUser.OrgId, | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 		NamespaceUID: namespace.Uid, | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 		RuleGroup:    ruleGroup, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := srv.store.GetRuleGroupAlertRules(&q); err != nil { | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 		return ErrResp(http.StatusInternalServerError, err, "failed to get group alert rules") | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ruleGroupInterval model.Duration | 
					
						
							|  |  |  | 	ruleNodes := make([]apimodels.GettableExtendedRuleNode, 0, len(q.Result)) | 
					
						
							|  |  |  | 	for _, r := range q.Result { | 
					
						
							|  |  |  | 		ruleGroupInterval = model.Duration(time.Duration(r.IntervalSeconds) * time.Second) | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 		ruleNodes = append(ruleNodes, toGettableExtendedRuleNode(*r, namespace.Id)) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result := apimodels.RuleGroupConfigResponse{ | 
					
						
							|  |  |  | 		GettableRuleGroupConfig: apimodels.GettableRuleGroupConfig{ | 
					
						
							|  |  |  | 			Name:     ruleGroup, | 
					
						
							|  |  |  | 			Interval: ruleGroupInterval, | 
					
						
							|  |  |  | 			Rules:    ruleNodes, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return response.JSON(http.StatusAccepted, result) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (srv RulerSrv) RouteGetRulesConfig(c *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2021-09-14 22:08:04 +08:00
										 |  |  | 	namespaceMap, err := srv.store.GetNamespaces(c.Req.Context(), c.OrgId, c.SignedInUser) | 
					
						
							| 
									
										
										
										
											2021-07-22 14:53:14 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return ErrResp(http.StatusInternalServerError, err, "failed to get namespaces visible to the user") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-08 21:26:08 +08:00
										 |  |  | 	result := apimodels.NamespaceConfigResponse{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(namespaceMap) == 0 { | 
					
						
							|  |  |  | 		srv.log.Debug("User has no access to any namespaces") | 
					
						
							|  |  |  | 		return response.JSON(http.StatusOK, result) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-07-22 14:53:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	namespaceUIDs := make([]string, len(namespaceMap)) | 
					
						
							|  |  |  | 	for k := range namespaceMap { | 
					
						
							|  |  |  | 		namespaceUIDs = append(namespaceUIDs, k) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-04 23:33:55 +08:00
										 |  |  | 	dashboardUID := c.Query("dashboard_uid") | 
					
						
							|  |  |  | 	panelID, err := getPanelIDFromRequest(c.Req) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return ErrResp(http.StatusBadRequest, err, "invalid panel_id") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if dashboardUID == "" && panelID != 0 { | 
					
						
							|  |  |  | 		return ErrResp(http.StatusBadRequest, errors.New("panel_id must be set with dashboard_uid"), "") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	q := ngmodels.ListAlertRulesQuery{ | 
					
						
							| 
									
										
										
										
											2021-07-22 14:53:14 +08:00
										 |  |  | 		OrgID:         c.SignedInUser.OrgId, | 
					
						
							|  |  |  | 		NamespaceUIDs: namespaceUIDs, | 
					
						
							| 
									
										
										
										
											2021-10-04 23:33:55 +08:00
										 |  |  | 		DashboardUID:  dashboardUID, | 
					
						
							|  |  |  | 		PanelID:       panelID, | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-07-22 14:53:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	if err := srv.store.GetOrgAlertRules(&q); err != nil { | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 		return ErrResp(http.StatusInternalServerError, err, "failed to get alert rules") | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	configs := make(map[string]map[string]apimodels.GettableRuleGroupConfig) | 
					
						
							|  |  |  | 	for _, r := range q.Result { | 
					
						
							| 
									
										
										
										
											2021-07-22 14:53:14 +08:00
										 |  |  | 		folder, ok := namespaceMap[r.NamespaceUID] | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							|  |  |  | 			srv.log.Error("namespace not visible to the user", "user", c.SignedInUser.UserId, "namespace", r.NamespaceUID, "rule", r.UID) | 
					
						
							|  |  |  | 			continue | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 		namespace := folder.Title | 
					
						
							| 
									
										
										
										
											2021-07-22 14:53:14 +08:00
										 |  |  | 		_, ok = configs[namespace] | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 		if !ok { | 
					
						
							|  |  |  | 			ruleGroupInterval := model.Duration(time.Duration(r.IntervalSeconds) * time.Second) | 
					
						
							|  |  |  | 			configs[namespace] = make(map[string]apimodels.GettableRuleGroupConfig) | 
					
						
							|  |  |  | 			configs[namespace][r.RuleGroup] = apimodels.GettableRuleGroupConfig{ | 
					
						
							|  |  |  | 				Name:     r.RuleGroup, | 
					
						
							|  |  |  | 				Interval: ruleGroupInterval, | 
					
						
							|  |  |  | 				Rules: []apimodels.GettableExtendedRuleNode{ | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 					toGettableExtendedRuleNode(*r, folder.Id), | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 				}, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			ruleGroupConfig, ok := configs[namespace][r.RuleGroup] | 
					
						
							|  |  |  | 			if !ok { | 
					
						
							|  |  |  | 				ruleGroupInterval := model.Duration(time.Duration(r.IntervalSeconds) * time.Second) | 
					
						
							|  |  |  | 				configs[namespace][r.RuleGroup] = apimodels.GettableRuleGroupConfig{ | 
					
						
							|  |  |  | 					Name:     r.RuleGroup, | 
					
						
							|  |  |  | 					Interval: ruleGroupInterval, | 
					
						
							|  |  |  | 					Rules: []apimodels.GettableExtendedRuleNode{ | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 						toGettableExtendedRuleNode(*r, folder.Id), | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 					}, | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 				ruleGroupConfig.Rules = append(ruleGroupConfig.Rules, toGettableExtendedRuleNode(*r, folder.Id)) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 				configs[namespace][r.RuleGroup] = ruleGroupConfig | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for namespace, m := range configs { | 
					
						
							|  |  |  | 		for _, ruleGroupConfig := range m { | 
					
						
							|  |  |  | 			result[namespace] = append(result[namespace], ruleGroupConfig) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-10-04 23:33:55 +08:00
										 |  |  | 	return response.JSON(http.StatusOK, result) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (srv RulerSrv) RoutePostNameRulesConfig(c *models.ReqContext, ruleGroupConfig apimodels.PostableRuleGroupConfig) response.Response { | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 	namespaceTitle := web.Params(c.Req)[":Namespace"] | 
					
						
							| 
									
										
										
										
											2021-09-14 22:08:04 +08:00
										 |  |  | 	namespace, err := srv.store.GetNamespaceByTitle(c.Req.Context(), namespaceTitle, c.SignedInUser.OrgId, c.SignedInUser, true) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 		return toNamespaceErrorResponse(err) | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-16 20:00:07 +08:00
										 |  |  | 	//TODO: Should this belong in alerting-api?
 | 
					
						
							|  |  |  | 	if ruleGroupConfig.Name == "" { | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 		return ErrResp(http.StatusBadRequest, errors.New("rule group name is not valid"), "") | 
					
						
							| 
									
										
										
										
											2021-04-16 20:00:07 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-03 00:38:42 +08:00
										 |  |  | 	alertRuleUIDs := make(map[string]struct{}) | 
					
						
							| 
									
										
										
										
											2021-04-28 16:31:51 +08:00
										 |  |  | 	for _, r := range ruleGroupConfig.Rules { | 
					
						
							|  |  |  | 		cond := ngmodels.Condition{ | 
					
						
							|  |  |  | 			Condition: r.GrafanaManagedAlert.Condition, | 
					
						
							|  |  |  | 			OrgID:     c.SignedInUser.OrgId, | 
					
						
							|  |  |  | 			Data:      r.GrafanaManagedAlert.Data, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-12-21 00:05:33 +08:00
										 |  |  | 		if err := validateCondition(c.Req.Context(), cond, c.SignedInUser, c.SkipCache, srv.DatasourceCache); err != nil { | 
					
						
							| 
									
										
										
										
											2021-09-03 00:38:42 +08:00
										 |  |  | 			return ErrResp(http.StatusBadRequest, err, "failed to validate alert rule %q", r.GrafanaManagedAlert.Title) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if r.GrafanaManagedAlert.UID != "" { | 
					
						
							|  |  |  | 			_, ok := alertRuleUIDs[r.GrafanaManagedAlert.UID] | 
					
						
							|  |  |  | 			if ok { | 
					
						
							|  |  |  | 				return ErrResp(http.StatusBadRequest, fmt.Errorf("conflicting UID %q found", r.GrafanaManagedAlert.UID), "failed to validate alert rule %q", r.GrafanaManagedAlert.Title) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			alertRuleUIDs[r.GrafanaManagedAlert.UID] = struct{}{} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	numOfNewRules := len(ruleGroupConfig.Rules) - len(alertRuleUIDs) | 
					
						
							|  |  |  | 	if numOfNewRules > 0 { | 
					
						
							|  |  |  | 		// quotas are checked in advanced
 | 
					
						
							|  |  |  | 		// that is acceptable under the assumption that there will be only one alert rule under the rule group
 | 
					
						
							|  |  |  | 		// alternatively we should check the quotas after the rule group update
 | 
					
						
							|  |  |  | 		// and rollback the transaction in case of violation
 | 
					
						
							|  |  |  | 		limitReached, err := srv.QuotaService.QuotaReached(c, "alert_rule") | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return ErrResp(http.StatusInternalServerError, err, "failed to get quota") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if limitReached { | 
					
						
							|  |  |  | 			return ErrResp(http.StatusForbidden, errors.New("quota reached"), "") | 
					
						
							| 
									
										
										
										
											2021-04-28 16:31:51 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	if err := srv.store.UpdateRuleGroup(store.UpdateRuleGroupCmd{ | 
					
						
							|  |  |  | 		OrgID:           c.SignedInUser.OrgId, | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 		NamespaceUID:    namespace.Uid, | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 		RuleGroupConfig: ruleGroupConfig, | 
					
						
							|  |  |  | 	}); err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 		if errors.Is(err, ngmodels.ErrAlertRuleNotFound) { | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 			return ErrResp(http.StatusNotFound, err, "failed to update rule group") | 
					
						
							| 
									
										
										
										
											2021-04-21 22:22:58 +08:00
										 |  |  | 		} else if errors.Is(err, ngmodels.ErrAlertRuleFailedValidation) { | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 			return ErrResp(http.StatusBadRequest, err, "failed to update rule group") | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 		return ErrResp(http.StatusInternalServerError, err, "failed to update rule group") | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-03 00:38:42 +08:00
										 |  |  | 	for uid := range alertRuleUIDs { | 
					
						
							| 
									
										
										
										
											2022-01-12 00:39:34 +08:00
										 |  |  | 		srv.scheduleService.UpdateAlertRule(ngmodels.AlertRuleKey{ | 
					
						
							|  |  |  | 			OrgID: c.SignedInUser.OrgId, | 
					
						
							|  |  |  | 			UID:   uid, | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2021-05-07 00:39:34 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 	return response.JSON(http.StatusAccepted, util.DynMap{"message": "rule group updated successfully"}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | func toGettableExtendedRuleNode(r ngmodels.AlertRule, namespaceID int64) apimodels.GettableExtendedRuleNode { | 
					
						
							|  |  |  | 	gettableExtendedRuleNode := apimodels.GettableExtendedRuleNode{ | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 		GrafanaManagedAlert: &apimodels.GettableGrafanaRule{ | 
					
						
							|  |  |  | 			ID:              r.ID, | 
					
						
							|  |  |  | 			OrgID:           r.OrgID, | 
					
						
							|  |  |  | 			Title:           r.Title, | 
					
						
							|  |  |  | 			Condition:       r.Condition, | 
					
						
							|  |  |  | 			Data:            r.Data, | 
					
						
							|  |  |  | 			Updated:         r.Updated, | 
					
						
							|  |  |  | 			IntervalSeconds: r.IntervalSeconds, | 
					
						
							|  |  |  | 			Version:         r.Version, | 
					
						
							|  |  |  | 			UID:             r.UID, | 
					
						
							|  |  |  | 			NamespaceUID:    r.NamespaceUID, | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 			NamespaceID:     namespaceID, | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | 			RuleGroup:       r.RuleGroup, | 
					
						
							|  |  |  | 			NoDataState:     apimodels.NoDataState(r.NoDataState), | 
					
						
							|  |  |  | 			ExecErrState:    apimodels.ExecutionErrorState(r.ExecErrState), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 	gettableExtendedRuleNode.ApiRuleNode = &apimodels.ApiRuleNode{ | 
					
						
							|  |  |  | 		For:         model.Duration(r.For), | 
					
						
							|  |  |  | 		Annotations: r.Annotations, | 
					
						
							|  |  |  | 		Labels:      r.Labels, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return gettableExtendedRuleNode | 
					
						
							| 
									
										
										
										
											2021-04-01 16:11:45 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-04-07 20:28:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | func toNamespaceErrorResponse(err error) response.Response { | 
					
						
							|  |  |  | 	if errors.Is(err, ngmodels.ErrCannotEditNamespace) { | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 		return ErrResp(http.StatusForbidden, err, err.Error()) | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if errors.Is(err, models.ErrDashboardIdentifierNotSet) { | 
					
						
							| 
									
										
										
										
											2021-05-28 23:55:03 +08:00
										 |  |  | 		return ErrResp(http.StatusBadRequest, err, err.Error()) | 
					
						
							| 
									
										
										
										
											2021-04-15 20:54:37 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-08-25 21:11:22 +08:00
										 |  |  | 	return apierrors.ToFolderErrorResponse(err) | 
					
						
							| 
									
										
										
										
											2021-04-07 20:28:06 +08:00
										 |  |  | } |