mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Add notification policy provisioning file export (#70009)
* Alerting: Add notification policy provisioning file export - Add provisioning API endpoint for exporting notification policies. - Add option in notification policy view ellipsis dropdown for exporting. - Update various provisioning documentation.
This commit is contained in:
@@ -80,6 +80,23 @@ func (srv *ProvisioningSrv) RouteGetPolicyTree(c *contextmodel.ReqContext) respo
|
||||
return response.JSON(http.StatusOK, policies)
|
||||
}
|
||||
|
||||
func (srv *ProvisioningSrv) RouteGetPolicyTreeExport(c *contextmodel.ReqContext) response.Response {
|
||||
policies, err := srv.policies.GetPolicyTree(c.Req.Context(), c.OrgID)
|
||||
if err != nil {
|
||||
if errors.Is(err, store.ErrNoAlertmanagerConfiguration) {
|
||||
return ErrResp(http.StatusNotFound, err, "")
|
||||
}
|
||||
return ErrResp(http.StatusInternalServerError, err, "")
|
||||
}
|
||||
|
||||
e, err := AlertingFileExportFromRoute(c.OrgID, policies)
|
||||
if err != nil {
|
||||
return ErrResp(http.StatusInternalServerError, err, "failed to create alerting file export")
|
||||
}
|
||||
|
||||
return exportResponse(c, e)
|
||||
}
|
||||
|
||||
func (srv *ProvisioningSrv) RoutePutPolicyTree(c *contextmodel.ReqContext, tree definitions.Route) response.Response {
|
||||
provenance := determineProvenance(c)
|
||||
err := srv.policies.UpdatePolicyTree(c.Req.Context(), c.OrgID, tree, alerting_models.Provenance(provenance))
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
prometheus "github.com/prometheus/alertmanager/config"
|
||||
"github.com/prometheus/alertmanager/pkg/labels"
|
||||
"github.com/prometheus/alertmanager/timeinterval"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/mock"
|
||||
@@ -812,6 +813,116 @@ func TestProvisioningApi(t *testing.T) {
|
||||
require.Equal(t, expectedResponse, string(response.Body()))
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("notification policies", func(t *testing.T) {
|
||||
t.Run("are present, GET returns 200", func(t *testing.T) {
|
||||
sut := createProvisioningSrvSut(t)
|
||||
rc := createTestRequestCtx()
|
||||
|
||||
response := sut.RouteGetPolicyTreeExport(&rc)
|
||||
|
||||
require.Equal(t, 200, response.Status())
|
||||
})
|
||||
|
||||
t.Run("accept header contains yaml, GET returns text yaml", func(t *testing.T) {
|
||||
sut := createProvisioningSrvSut(t)
|
||||
rc := createTestRequestCtx()
|
||||
|
||||
rc.Context.Req.Header.Add("Accept", "application/yaml")
|
||||
response := sut.RouteGetPolicyTreeExport(&rc)
|
||||
response.WriteTo(&rc)
|
||||
|
||||
require.Equal(t, 200, response.Status())
|
||||
require.Equal(t, "text/yaml", rc.Context.Resp.Header().Get("Content-Type"))
|
||||
})
|
||||
|
||||
t.Run("accept header contains json, GET returns json", func(t *testing.T) {
|
||||
sut := createProvisioningSrvSut(t)
|
||||
rc := createTestRequestCtx()
|
||||
|
||||
rc.Context.Req.Header.Add("Accept", "application/json")
|
||||
response := sut.RouteGetPolicyTreeExport(&rc)
|
||||
response.WriteTo(&rc)
|
||||
|
||||
require.Equal(t, 200, response.Status())
|
||||
require.Equal(t, "application/json", rc.Context.Resp.Header().Get("Content-Type"))
|
||||
})
|
||||
|
||||
t.Run("accept header contains json and yaml, GET returns json", func(t *testing.T) {
|
||||
sut := createProvisioningSrvSut(t)
|
||||
rc := createTestRequestCtx()
|
||||
|
||||
rc.Context.Req.Header.Add("Accept", "application/json, application/yaml")
|
||||
response := sut.RouteGetPolicyTreeExport(&rc)
|
||||
response.WriteTo(&rc)
|
||||
|
||||
require.Equal(t, 200, response.Status())
|
||||
require.Equal(t, "application/json", rc.Context.Resp.Header().Get("Content-Type"))
|
||||
})
|
||||
|
||||
t.Run("query param download=true, GET returns content disposition attachment", func(t *testing.T) {
|
||||
sut := createProvisioningSrvSut(t)
|
||||
rc := createTestRequestCtx()
|
||||
|
||||
rc.Context.Req.Form.Set("download", "true")
|
||||
response := sut.RouteGetPolicyTreeExport(&rc)
|
||||
response.WriteTo(&rc)
|
||||
|
||||
require.Equal(t, 200, response.Status())
|
||||
require.Contains(t, rc.Context.Resp.Header().Get("Content-Disposition"), "attachment")
|
||||
})
|
||||
|
||||
t.Run("query param download=false, GET returns empty content disposition", func(t *testing.T) {
|
||||
sut := createProvisioningSrvSut(t)
|
||||
rc := createTestRequestCtx()
|
||||
|
||||
rc.Context.Req.Form.Set("download", "false")
|
||||
response := sut.RouteGetPolicyTreeExport(&rc)
|
||||
response.WriteTo(&rc)
|
||||
|
||||
require.Equal(t, 200, response.Status())
|
||||
require.Equal(t, "", rc.Context.Resp.Header().Get("Content-Disposition"))
|
||||
})
|
||||
|
||||
t.Run("query param download not set, GET returns empty content disposition", func(t *testing.T) {
|
||||
sut := createProvisioningSrvSut(t)
|
||||
rc := createTestRequestCtx()
|
||||
|
||||
response := sut.RouteGetPolicyTreeExport(&rc)
|
||||
response.WriteTo(&rc)
|
||||
|
||||
require.Equal(t, 200, response.Status())
|
||||
require.Equal(t, "", rc.Context.Resp.Header().Get("Content-Disposition"))
|
||||
})
|
||||
|
||||
t.Run("json body content is as expected", func(t *testing.T) {
|
||||
sut := createProvisioningSrvSut(t)
|
||||
sut.policies = createFakeNotificationPolicyService()
|
||||
rc := createTestRequestCtx()
|
||||
|
||||
rc.Context.Req.Header.Add("Accept", "application/json")
|
||||
expectedResponse := `{"apiVersion":1,"policies":[{"orgId":1,"Policy":{"receiver":"default-receiver","group_by":["g1","g2"],"routes":[{"receiver":"nested-receiver","group_by":["g3","g4"],"matchers":["a=\"b\""],"object_matchers":[["foo","=","bar"]],"mute_time_intervals":["interval"],"continue":true,"group_wait":"5m","group_interval":"5m","repeat_interval":"5m"}],"group_wait":"30s","group_interval":"5m","repeat_interval":"1h"}}]}`
|
||||
|
||||
response := sut.RouteGetPolicyTreeExport(&rc)
|
||||
|
||||
require.Equal(t, 200, response.Status())
|
||||
require.Equal(t, expectedResponse, string(response.Body()))
|
||||
})
|
||||
|
||||
t.Run("yaml body content is as expected", func(t *testing.T) {
|
||||
sut := createProvisioningSrvSut(t)
|
||||
sut.policies = createFakeNotificationPolicyService()
|
||||
rc := createTestRequestCtx()
|
||||
|
||||
rc.Context.Req.Header.Add("Accept", "application/yaml")
|
||||
expectedResponse := "apiVersion: 1\npolicies:\n - orgId: 1\n receiver: default-receiver\n group_by:\n - g1\n - g2\n routes:\n - receiver: nested-receiver\n group_by:\n - g3\n - g4\n matchers:\n - a=\"b\"\n object_matchers:\n - - foo\n - =\n - bar\n mute_time_intervals:\n - interval\n continue: true\n group_wait: 5m\n group_interval: 5m\n repeat_interval: 5m\n group_wait: 30s\n group_interval: 5m\n repeat_interval: 1h\n"
|
||||
|
||||
response := sut.RouteGetPolicyTreeExport(&rc)
|
||||
|
||||
require.Equal(t, 200, response.Status())
|
||||
require.Equal(t, expectedResponse, string(response.Body()))
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1162,6 +1273,39 @@ func newFakeNotificationPolicyService() *fakeNotificationPolicyService {
|
||||
}
|
||||
}
|
||||
|
||||
func createFakeNotificationPolicyService() *fakeNotificationPolicyService {
|
||||
seconds := model.Duration(time.Duration(30) * time.Second)
|
||||
minutes := model.Duration(time.Duration(5) * time.Minute)
|
||||
hours := model.Duration(time.Duration(1) * time.Hour)
|
||||
return &fakeNotificationPolicyService{
|
||||
tree: definitions.Route{
|
||||
Receiver: "default-receiver",
|
||||
GroupByStr: []string{"g1", "g2"},
|
||||
GroupWait: &seconds,
|
||||
GroupInterval: &minutes,
|
||||
RepeatInterval: &hours,
|
||||
Routes: []*definitions.Route{{
|
||||
Receiver: "nested-receiver",
|
||||
GroupByStr: []string{"g3", "g4"},
|
||||
Matchers: prometheus.Matchers{
|
||||
{
|
||||
Name: "a",
|
||||
Type: labels.MatchEqual,
|
||||
Value: "b",
|
||||
},
|
||||
},
|
||||
ObjectMatchers: definitions.ObjectMatchers{{Type: 0, Name: "foo", Value: "bar"}},
|
||||
MuteTimeIntervals: []string{"interval"},
|
||||
Continue: true,
|
||||
GroupWait: &minutes,
|
||||
GroupInterval: &minutes,
|
||||
RepeatInterval: &minutes,
|
||||
}},
|
||||
},
|
||||
prov: models.ProvenanceAPI,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *fakeNotificationPolicyService) GetPolicyTree(ctx context.Context, orgID int64) (definitions.Route, error) {
|
||||
if orgID != 1 {
|
||||
return definitions.Route{}, store.ErrNoAlertmanagerConfiguration
|
||||
|
||||
@@ -185,6 +185,7 @@ func (api *API) authorize(method, path string) web.Handler {
|
||||
|
||||
// Grafana-only Provisioning Read Paths
|
||||
case http.MethodGet + "/api/v1/provisioning/policies",
|
||||
http.MethodGet + "/api/v1/provisioning/policies/export",
|
||||
http.MethodGet + "/api/v1/provisioning/contact-points",
|
||||
http.MethodGet + "/api/v1/provisioning/contact-points/export",
|
||||
http.MethodGet + "/api/v1/provisioning/templates",
|
||||
|
||||
@@ -49,7 +49,7 @@ func TestAuthorize(t *testing.T) {
|
||||
}
|
||||
paths[p] = methods
|
||||
}
|
||||
require.Len(t, paths, 49)
|
||||
require.Len(t, paths, 50)
|
||||
|
||||
ac := acmock.New()
|
||||
api := &API{AccessControl: ac}
|
||||
|
||||
@@ -260,3 +260,41 @@ func ReceiverExportFromEmbeddedContactPoint(contact definitions.EmbeddedContactP
|
||||
DisableResolveMessage: contact.DisableResolveMessage,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AlertingFileExportFromRoute creates a definitions.AlertingFileExport DTO from definitions.Route.
|
||||
func AlertingFileExportFromRoute(orgID int64, route definitions.Route) (definitions.AlertingFileExport, error) {
|
||||
f := definitions.AlertingFileExport{
|
||||
APIVersion: 1,
|
||||
Policies: []definitions.NotificationPolicyExport{{
|
||||
OrgID: orgID,
|
||||
Policy: RouteExportFromRoute(&route),
|
||||
}},
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// RouteExportFromRoute creates a definitions.RouteExport DTO from definitions.Route.
|
||||
func RouteExportFromRoute(route *definitions.Route) *definitions.RouteExport {
|
||||
export := definitions.RouteExport{
|
||||
Receiver: route.Receiver,
|
||||
GroupByStr: route.GroupByStr,
|
||||
Match: route.Match,
|
||||
MatchRE: route.MatchRE,
|
||||
Matchers: route.Matchers,
|
||||
ObjectMatchers: route.ObjectMatchers,
|
||||
MuteTimeIntervals: route.MuteTimeIntervals,
|
||||
Continue: route.Continue,
|
||||
GroupWait: route.GroupWait,
|
||||
GroupInterval: route.GroupInterval,
|
||||
RepeatInterval: route.RepeatInterval,
|
||||
}
|
||||
|
||||
if len(route.Routes) > 0 {
|
||||
export.Routes = make([]*definitions.RouteExport, 0, len(route.Routes))
|
||||
for _, r := range route.Routes {
|
||||
export.Routes = append(export.Routes, RouteExportFromRoute(r))
|
||||
}
|
||||
}
|
||||
|
||||
return &export
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ type ProvisioningApi interface {
|
||||
RouteGetMuteTiming(*contextmodel.ReqContext) response.Response
|
||||
RouteGetMuteTimings(*contextmodel.ReqContext) response.Response
|
||||
RouteGetPolicyTree(*contextmodel.ReqContext) response.Response
|
||||
RouteGetPolicyTreeExport(*contextmodel.ReqContext) response.Response
|
||||
RouteGetTemplate(*contextmodel.ReqContext) response.Response
|
||||
RouteGetTemplates(*contextmodel.ReqContext) response.Response
|
||||
RoutePostAlertRule(*contextmodel.ReqContext) response.Response
|
||||
@@ -113,6 +114,9 @@ func (f *ProvisioningApiHandler) RouteGetMuteTimings(ctx *contextmodel.ReqContex
|
||||
func (f *ProvisioningApiHandler) RouteGetPolicyTree(ctx *contextmodel.ReqContext) response.Response {
|
||||
return f.handleRouteGetPolicyTree(ctx)
|
||||
}
|
||||
func (f *ProvisioningApiHandler) RouteGetPolicyTreeExport(ctx *contextmodel.ReqContext) response.Response {
|
||||
return f.handleRouteGetPolicyTreeExport(ctx)
|
||||
}
|
||||
func (f *ProvisioningApiHandler) RouteGetTemplate(ctx *contextmodel.ReqContext) response.Response {
|
||||
// Parse Path Parameters
|
||||
nameParam := web.Params(ctx.Req)[":name"]
|
||||
@@ -360,6 +364,16 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
|
||||
m,
|
||||
),
|
||||
)
|
||||
group.Get(
|
||||
toMacaronPath("/api/v1/provisioning/policies/export"),
|
||||
api.authorize(http.MethodGet, "/api/v1/provisioning/policies/export"),
|
||||
metrics.Instrument(
|
||||
http.MethodGet,
|
||||
"/api/v1/provisioning/policies/export",
|
||||
api.Hooks.Wrap(srv.RouteGetPolicyTreeExport),
|
||||
m,
|
||||
),
|
||||
)
|
||||
group.Get(
|
||||
toMacaronPath("/api/v1/provisioning/templates/{name}"),
|
||||
api.authorize(http.MethodGet, "/api/v1/provisioning/templates/{name}"),
|
||||
|
||||
@@ -20,6 +20,10 @@ func (f *ProvisioningApiHandler) handleRouteGetPolicyTree(ctx *contextmodel.ReqC
|
||||
return f.svc.RouteGetPolicyTree(ctx)
|
||||
}
|
||||
|
||||
func (f *ProvisioningApiHandler) handleRouteGetPolicyTreeExport(ctx *contextmodel.ReqContext) response.Response {
|
||||
return f.svc.RouteGetPolicyTreeExport(ctx)
|
||||
}
|
||||
|
||||
func (f *ProvisioningApiHandler) handleRoutePutPolicyTree(ctx *contextmodel.ReqContext, route apimodels.Route) response.Response {
|
||||
return f.svc.RoutePutPolicyTree(ctx, route)
|
||||
}
|
||||
|
||||
@@ -297,6 +297,12 @@
|
||||
"$ref": "#/definitions/AlertRuleGroupExport"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"policies": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/NotificationPolicyExport"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"title": "AlertingFileExport is the full provisioned file export.",
|
||||
@@ -1097,6 +1103,10 @@
|
||||
"description": "PathSeparator defines the separator pattern to decode a hierarchy. The default separator is '/'.",
|
||||
"type": "string"
|
||||
},
|
||||
"preferredVisualisationPluginId": {
|
||||
"description": "PreferredVisualizationPluginId sets the panel plugin id to use to render the data when using Explore. If\nthe plugin cannot be found will fall back to PreferredVisualization.",
|
||||
"type": "string"
|
||||
},
|
||||
"preferredVisualisationType": {
|
||||
"$ref": "#/definitions/VisType"
|
||||
},
|
||||
@@ -1897,6 +1907,19 @@
|
||||
"title": "NoticeSeverity is a type for the Severity property of a Notice.",
|
||||
"type": "integer"
|
||||
},
|
||||
"NotificationPolicyExport": {
|
||||
"properties": {
|
||||
"Policy": {
|
||||
"$ref": "#/definitions/RouteExport"
|
||||
},
|
||||
"orgId": {
|
||||
"format": "int64",
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"title": "NotificationPolicyExport is the provisioned file export of alerting.NotificiationPolicyV1.",
|
||||
"type": "object"
|
||||
},
|
||||
"NotificationTemplate": {
|
||||
"properties": {
|
||||
"name": {
|
||||
@@ -2882,7 +2905,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"settings": {
|
||||
"$ref": "#/definitions/Json"
|
||||
"$ref": "#/definitions/RawMessage"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
@@ -2985,6 +3008,61 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"RouteExport": {
|
||||
"description": "RouteExport is the provisioned file export of definitions.Route. This is needed to hide fields that aren't useable in\nprovisioning file format. An alternative would be to define a custom MarshalJSON and MarshalYAML that excludes them.",
|
||||
"properties": {
|
||||
"continue": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"group_by": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"group_interval": {
|
||||
"type": "string"
|
||||
},
|
||||
"group_wait": {
|
||||
"type": "string"
|
||||
},
|
||||
"match": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Deprecated. Remove before v1.0 release.",
|
||||
"type": "object"
|
||||
},
|
||||
"match_re": {
|
||||
"$ref": "#/definitions/MatchRegexps"
|
||||
},
|
||||
"matchers": {
|
||||
"$ref": "#/definitions/Matchers"
|
||||
},
|
||||
"mute_time_intervals": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"object_matchers": {
|
||||
"$ref": "#/definitions/ObjectMatchers"
|
||||
},
|
||||
"receiver": {
|
||||
"type": "string"
|
||||
},
|
||||
"repeat_interval": {
|
||||
"type": "string"
|
||||
},
|
||||
"routes": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/RouteExport"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"Rule": {
|
||||
"description": "adapted from cortex",
|
||||
"properties": {
|
||||
@@ -4185,7 +4263,6 @@
|
||||
"type": "array"
|
||||
},
|
||||
"integration": {
|
||||
"description": "Integration integration",
|
||||
"properties": {
|
||||
"lastNotifyAttempt": {
|
||||
"description": "A timestamp indicating the last attempt to deliver a notification regardless of the outcome.\nFormat: date-time",
|
||||
@@ -5237,6 +5314,29 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/provisioning/policies/export": {
|
||||
"get": {
|
||||
"operationId": "RouteGetPolicyTreeExport",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "AlertingFileExport",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/AlertingFileExport"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "NotFound",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/NotFound"
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": "Export the notification policy tree in provisioning file format.",
|
||||
"tags": [
|
||||
"provisioning"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/provisioning/templates": {
|
||||
"get": {
|
||||
"operationId": "RouteGetTemplates",
|
||||
|
||||
@@ -3,9 +3,10 @@ package definitions
|
||||
// AlertingFileExport is the full provisioned file export.
|
||||
// swagger:model
|
||||
type AlertingFileExport struct {
|
||||
APIVersion int64 `json:"apiVersion" yaml:"apiVersion"`
|
||||
Groups []AlertRuleGroupExport `json:"groups,omitempty" yaml:"groups,omitempty"`
|
||||
ContactPoints []ContactPointExport `json:"contactPoints,omitempty" yaml:"contactPoints,omitempty"`
|
||||
APIVersion int64 `json:"apiVersion" yaml:"apiVersion"`
|
||||
Groups []AlertRuleGroupExport `json:"groups,omitempty" yaml:"groups,omitempty"`
|
||||
ContactPoints []ContactPointExport `json:"contactPoints,omitempty" yaml:"contactPoints,omitempty"`
|
||||
Policies []NotificationPolicyExport `json:"policies,omitempty" yaml:"policies,omitempty"`
|
||||
}
|
||||
|
||||
// swagger:parameters RouteGetAlertRuleGroupExport RouteGetAlertRuleExport RouteGetAlertRulesExport RouteGetContactpointsExport RouteGetContactpointExport
|
||||
|
||||
@@ -51,7 +51,7 @@ import (
|
||||
// Responses:
|
||||
// 204: description: The contact point was deleted successfully.
|
||||
|
||||
// swagger:parameters RoutePutContactpoint RouteDeleteContactpoints RouteGetContactpoint RouteGetContactpointExport
|
||||
// swagger:parameters RoutePutContactpoint RouteDeleteContactpoints
|
||||
type ContactPointUIDReference struct {
|
||||
// UID is the contact point unique identifier
|
||||
// in:path
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
package definitions
|
||||
|
||||
import (
|
||||
"github.com/prometheus/alertmanager/config"
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
// swagger:route GET /api/v1/provisioning/policies provisioning stable RouteGetPolicyTree
|
||||
//
|
||||
// Get the notification policy tree.
|
||||
@@ -29,9 +34,44 @@ package definitions
|
||||
// Responses:
|
||||
// 202: Ack
|
||||
|
||||
// swagger:route GET /api/v1/provisioning/policies/export provisioning stable RouteGetPolicyTreeExport
|
||||
//
|
||||
// Export the notification policy tree in provisioning file format.
|
||||
//
|
||||
// Responses:
|
||||
// 200: AlertingFileExport
|
||||
// 404: NotFound
|
||||
|
||||
// swagger:parameters RoutePutPolicyTree
|
||||
type Policytree struct {
|
||||
// The new notification routing tree to use
|
||||
// in:body
|
||||
Body Route
|
||||
}
|
||||
|
||||
// NotificationPolicyExport is the provisioned file export of alerting.NotificiationPolicyV1.
|
||||
type NotificationPolicyExport struct {
|
||||
OrgID int64 `json:"orgId" yaml:"orgId"`
|
||||
Policy *RouteExport `json:",inline" yaml:",inline"`
|
||||
}
|
||||
|
||||
// RouteExport is the provisioned file export of definitions.Route. This is needed to hide fields that aren't useable in
|
||||
// provisioning file format. An alternative would be to define a custom MarshalJSON and MarshalYAML that excludes them.
|
||||
type RouteExport struct {
|
||||
Receiver string `yaml:"receiver,omitempty" json:"receiver,omitempty"`
|
||||
|
||||
GroupByStr []string `yaml:"group_by,omitempty" json:"group_by,omitempty"`
|
||||
// Deprecated. Remove before v1.0 release.
|
||||
Match map[string]string `yaml:"match,omitempty" json:"match,omitempty"`
|
||||
// Deprecated. Remove before v1.0 release.
|
||||
MatchRE config.MatchRegexps `yaml:"match_re,omitempty" json:"match_re,omitempty"`
|
||||
Matchers config.Matchers `yaml:"matchers,omitempty" json:"matchers,omitempty"`
|
||||
ObjectMatchers ObjectMatchers `yaml:"object_matchers,omitempty" json:"object_matchers,omitempty"`
|
||||
MuteTimeIntervals []string `yaml:"mute_time_intervals,omitempty" json:"mute_time_intervals,omitempty"`
|
||||
Continue bool `yaml:"continue,omitempty" json:"continue,omitempty"` // Added omitempty to yaml for a cleaner export.
|
||||
Routes []*RouteExport `yaml:"routes,omitempty" json:"routes,omitempty"`
|
||||
|
||||
GroupWait *model.Duration `yaml:"group_wait,omitempty" json:"group_wait,omitempty"`
|
||||
GroupInterval *model.Duration `yaml:"group_interval,omitempty" json:"group_interval,omitempty"`
|
||||
RepeatInterval *model.Duration `yaml:"repeat_interval,omitempty" json:"repeat_interval,omitempty"`
|
||||
}
|
||||
|
||||
@@ -297,6 +297,12 @@
|
||||
"$ref": "#/definitions/AlertRuleGroupExport"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"policies": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/NotificationPolicyExport"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"title": "AlertingFileExport is the full provisioned file export.",
|
||||
@@ -1097,6 +1103,10 @@
|
||||
"description": "PathSeparator defines the separator pattern to decode a hierarchy. The default separator is '/'.",
|
||||
"type": "string"
|
||||
},
|
||||
"preferredVisualisationPluginId": {
|
||||
"description": "PreferredVisualizationPluginId sets the panel plugin id to use to render the data when using Explore. If\nthe plugin cannot be found will fall back to PreferredVisualization.",
|
||||
"type": "string"
|
||||
},
|
||||
"preferredVisualisationType": {
|
||||
"$ref": "#/definitions/VisType"
|
||||
},
|
||||
@@ -1897,6 +1907,19 @@
|
||||
"title": "NoticeSeverity is a type for the Severity property of a Notice.",
|
||||
"type": "integer"
|
||||
},
|
||||
"NotificationPolicyExport": {
|
||||
"properties": {
|
||||
"Policy": {
|
||||
"$ref": "#/definitions/RouteExport"
|
||||
},
|
||||
"orgId": {
|
||||
"format": "int64",
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"title": "NotificationPolicyExport is the provisioned file export of alerting.NotificiationPolicyV1.",
|
||||
"type": "object"
|
||||
},
|
||||
"NotificationTemplate": {
|
||||
"properties": {
|
||||
"name": {
|
||||
@@ -2882,7 +2905,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"settings": {
|
||||
"$ref": "#/definitions/Json"
|
||||
"$ref": "#/definitions/RawMessage"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
@@ -2985,6 +3008,61 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"RouteExport": {
|
||||
"description": "RouteExport is the provisioned file export of definitions.Route. This is needed to hide fields that aren't useable in\nprovisioning file format. An alternative would be to define a custom MarshalJSON and MarshalYAML that excludes them.",
|
||||
"properties": {
|
||||
"continue": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"group_by": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"group_interval": {
|
||||
"type": "string"
|
||||
},
|
||||
"group_wait": {
|
||||
"type": "string"
|
||||
},
|
||||
"match": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Deprecated. Remove before v1.0 release.",
|
||||
"type": "object"
|
||||
},
|
||||
"match_re": {
|
||||
"$ref": "#/definitions/MatchRegexps"
|
||||
},
|
||||
"matchers": {
|
||||
"$ref": "#/definitions/Matchers"
|
||||
},
|
||||
"mute_time_intervals": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"object_matchers": {
|
||||
"$ref": "#/definitions/ObjectMatchers"
|
||||
},
|
||||
"receiver": {
|
||||
"type": "string"
|
||||
},
|
||||
"repeat_interval": {
|
||||
"type": "string"
|
||||
},
|
||||
"routes": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/RouteExport"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"Rule": {
|
||||
"description": "adapted from cortex",
|
||||
"properties": {
|
||||
@@ -3940,6 +4018,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"alertGroup": {
|
||||
"description": "AlertGroup alert group",
|
||||
"properties": {
|
||||
"alerts": {
|
||||
"description": "alerts",
|
||||
@@ -3963,6 +4042,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"alertGroups": {
|
||||
"description": "AlertGroups alert groups",
|
||||
"items": {
|
||||
"$ref": "#/definitions/alertGroup"
|
||||
},
|
||||
@@ -4067,7 +4147,6 @@
|
||||
"type": "object"
|
||||
},
|
||||
"gettableAlert": {
|
||||
"description": "GettableAlert gettable alert",
|
||||
"properties": {
|
||||
"annotations": {
|
||||
"$ref": "#/definitions/labelSet"
|
||||
@@ -4328,7 +4407,6 @@
|
||||
"type": "array"
|
||||
},
|
||||
"postableSilence": {
|
||||
"description": "PostableSilence postable silence",
|
||||
"properties": {
|
||||
"comment": {
|
||||
"description": "comment",
|
||||
@@ -7017,6 +7095,29 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/provisioning/policies/export": {
|
||||
"get": {
|
||||
"operationId": "RouteGetPolicyTreeExport",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "AlertingFileExport",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/AlertingFileExport"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "NotFound",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/NotFound"
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": "Export the notification policy tree in provisioning file format.",
|
||||
"tags": [
|
||||
"provisioning"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/provisioning/templates": {
|
||||
"get": {
|
||||
"operationId": "RouteGetTemplates",
|
||||
|
||||
@@ -2572,6 +2572,30 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/provisioning/policies/export": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"provisioning",
|
||||
"stable"
|
||||
],
|
||||
"summary": "Export the notification policy tree in provisioning file format.",
|
||||
"operationId": "RouteGetPolicyTreeExport",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "AlertingFileExport",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/AlertingFileExport"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "NotFound",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/NotFound"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/provisioning/templates": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -3118,6 +3142,12 @@
|
||||
"items": {
|
||||
"$ref": "#/definitions/AlertRuleGroupExport"
|
||||
}
|
||||
},
|
||||
"policies": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/NotificationPolicyExport"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -3921,6 +3951,10 @@
|
||||
"description": "PathSeparator defines the separator pattern to decode a hierarchy. The default separator is '/'.",
|
||||
"type": "string"
|
||||
},
|
||||
"preferredVisualisationPluginId": {
|
||||
"description": "PreferredVisualizationPluginId sets the panel plugin id to use to render the data when using Explore. If\nthe plugin cannot be found will fall back to PreferredVisualization.",
|
||||
"type": "string"
|
||||
},
|
||||
"preferredVisualisationType": {
|
||||
"$ref": "#/definitions/VisType"
|
||||
},
|
||||
@@ -4720,6 +4754,19 @@
|
||||
"format": "int64",
|
||||
"title": "NoticeSeverity is a type for the Severity property of a Notice."
|
||||
},
|
||||
"NotificationPolicyExport": {
|
||||
"type": "object",
|
||||
"title": "NotificationPolicyExport is the provisioned file export of alerting.NotificiationPolicyV1.",
|
||||
"properties": {
|
||||
"Policy": {
|
||||
"$ref": "#/definitions/RouteExport"
|
||||
},
|
||||
"orgId": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
"NotificationTemplate": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5707,7 +5754,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"settings": {
|
||||
"$ref": "#/definitions/Json"
|
||||
"$ref": "#/definitions/RawMessage"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
@@ -5808,6 +5855,61 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"RouteExport": {
|
||||
"description": "RouteExport is the provisioned file export of definitions.Route. This is needed to hide fields that aren't useable in\nprovisioning file format. An alternative would be to define a custom MarshalJSON and MarshalYAML that excludes them.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"continue": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"group_by": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"group_interval": {
|
||||
"type": "string"
|
||||
},
|
||||
"group_wait": {
|
||||
"type": "string"
|
||||
},
|
||||
"match": {
|
||||
"description": "Deprecated. Remove before v1.0 release.",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"match_re": {
|
||||
"$ref": "#/definitions/MatchRegexps"
|
||||
},
|
||||
"matchers": {
|
||||
"$ref": "#/definitions/Matchers"
|
||||
},
|
||||
"mute_time_intervals": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"object_matchers": {
|
||||
"$ref": "#/definitions/ObjectMatchers"
|
||||
},
|
||||
"receiver": {
|
||||
"type": "string"
|
||||
},
|
||||
"repeat_interval": {
|
||||
"type": "string"
|
||||
},
|
||||
"routes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/RouteExport"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Rule": {
|
||||
"description": "adapted from cortex",
|
||||
"type": "object",
|
||||
@@ -6763,6 +6865,7 @@
|
||||
}
|
||||
},
|
||||
"alertGroup": {
|
||||
"description": "AlertGroup alert group",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"alerts",
|
||||
@@ -6787,6 +6890,7 @@
|
||||
"$ref": "#/definitions/alertGroup"
|
||||
},
|
||||
"alertGroups": {
|
||||
"description": "AlertGroups alert groups",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/alertGroup"
|
||||
@@ -6892,7 +6996,6 @@
|
||||
}
|
||||
},
|
||||
"gettableAlert": {
|
||||
"description": "GettableAlert gettable alert",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"labels",
|
||||
@@ -7158,7 +7261,6 @@
|
||||
}
|
||||
},
|
||||
"postableSilence": {
|
||||
"description": "PostableSilence postable silence",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"comment",
|
||||
|
||||
Reference in New Issue
Block a user