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:
Matthew Jacobson
2023-07-24 17:56:53 -04:00
committed by GitHub
parent 4c42632ab8
commit cfb1656968
16 changed files with 731 additions and 71 deletions

View File

@@ -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))

View File

@@ -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

View File

@@ -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",

View File

@@ -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}

View File

@@ -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
}

View File

@@ -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}"),

View File

@@ -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)
}

View File

@@ -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",

View File

@@ -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

View File

@@ -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

View File

@@ -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"`
}

View File

@@ -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",

View File

@@ -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",