mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: allow custom UID for contact points through API (#50089)
* Alerting: allow custom UID for contact points through API * fix auth
This commit is contained in:
parent
d3adc42e6e
commit
468ed68d64
@ -18,7 +18,6 @@ import (
|
||||
|
||||
const (
|
||||
namePathParam = ":name"
|
||||
idPathParam = ":ID"
|
||||
uidPathParam = ":UID"
|
||||
groupPathParam = ":Group"
|
||||
folderUIDPathParam = ":FolderUID"
|
||||
@ -111,8 +110,7 @@ func (srv *ProvisioningSrv) RoutePostContactPoint(c *models.ReqContext, cp apimo
|
||||
}
|
||||
|
||||
func (srv *ProvisioningSrv) RoutePutContactPoint(c *models.ReqContext, cp apimodels.EmbeddedContactPoint) response.Response {
|
||||
id := pathParam(c, idPathParam)
|
||||
cp.UID = id
|
||||
cp.UID = pathParam(c, uidPathParam)
|
||||
err := srv.contactPointService.UpdateContactPoint(c.Req.Context(), c.OrgId, cp, alerting_models.ProvenanceAPI)
|
||||
if err != nil {
|
||||
return ErrResp(http.StatusInternalServerError, err, "")
|
||||
@ -121,8 +119,8 @@ func (srv *ProvisioningSrv) RoutePutContactPoint(c *models.ReqContext, cp apimod
|
||||
}
|
||||
|
||||
func (srv *ProvisioningSrv) RouteDeleteContactPoint(c *models.ReqContext) response.Response {
|
||||
cpID := pathParam(c, idPathParam)
|
||||
err := srv.contactPointService.DeleteContactPoint(c.Req.Context(), c.OrgId, cpID)
|
||||
UID := pathParam(c, uidPathParam)
|
||||
err := srv.contactPointService.DeleteContactPoint(c.Req.Context(), c.OrgId, UID)
|
||||
if err != nil {
|
||||
return ErrResp(http.StatusInternalServerError, err, "")
|
||||
}
|
||||
|
@ -190,8 +190,8 @@ func (api *API) authorize(method, path string) web.Handler {
|
||||
|
||||
case http.MethodPut + "/api/provisioning/policies",
|
||||
http.MethodPost + "/api/provisioning/contact-points",
|
||||
http.MethodPut + "/api/provisioning/contact-points/{ID}",
|
||||
http.MethodDelete + "/api/provisioning/contact-points/{ID}",
|
||||
http.MethodPut + "/api/provisioning/contact-points/{UID}",
|
||||
http.MethodDelete + "/api/provisioning/contact-points/{UID}",
|
||||
http.MethodPut + "/api/provisioning/templates/{name}",
|
||||
http.MethodDelete + "/api/provisioning/templates/{name}",
|
||||
http.MethodPost + "/api/provisioning/mute-timings",
|
||||
|
@ -151,11 +151,11 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApiForkingServi
|
||||
),
|
||||
)
|
||||
group.Delete(
|
||||
toMacaronPath("/api/provisioning/contact-points/{ID}"),
|
||||
api.authorize(http.MethodDelete, "/api/provisioning/contact-points/{ID}"),
|
||||
toMacaronPath("/api/provisioning/contact-points/{UID}"),
|
||||
api.authorize(http.MethodDelete, "/api/provisioning/contact-points/{UID}"),
|
||||
metrics.Instrument(
|
||||
http.MethodDelete,
|
||||
"/api/provisioning/contact-points/{ID}",
|
||||
"/api/provisioning/contact-points/{UID}",
|
||||
srv.RouteDeleteContactpoints,
|
||||
m,
|
||||
),
|
||||
@ -301,11 +301,11 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApiForkingServi
|
||||
),
|
||||
)
|
||||
group.Put(
|
||||
toMacaronPath("/api/provisioning/contact-points/{ID}"),
|
||||
api.authorize(http.MethodPut, "/api/provisioning/contact-points/{ID}"),
|
||||
toMacaronPath("/api/provisioning/contact-points/{UID}"),
|
||||
api.authorize(http.MethodPut, "/api/provisioning/contact-points/{UID}"),
|
||||
metrics.Instrument(
|
||||
http.MethodPut,
|
||||
"/api/provisioning/contact-points/{ID}",
|
||||
"/api/provisioning/contact-points/{UID}",
|
||||
srv.RoutePutContactpoint,
|
||||
m,
|
||||
),
|
||||
|
@ -26,7 +26,7 @@ import (
|
||||
// 202: Ack
|
||||
// 400: ValidationError
|
||||
|
||||
// swagger:route PUT /api/provisioning/contact-points/{ID} provisioning RoutePutContactpoint
|
||||
// swagger:route PUT /api/provisioning/contact-points/{UID} provisioning RoutePutContactpoint
|
||||
//
|
||||
// Update an existing contact point.
|
||||
//
|
||||
@ -37,7 +37,7 @@ import (
|
||||
// 202: Ack
|
||||
// 400: ValidationError
|
||||
|
||||
// swagger:route DELETE /api/provisioning/contact-points/{ID} provisioning RouteDeleteContactpoints
|
||||
// swagger:route DELETE /api/provisioning/contact-points/{UID} provisioning RouteDeleteContactpoints
|
||||
//
|
||||
// Delete a contact point.
|
||||
//
|
||||
@ -52,7 +52,7 @@ import (
|
||||
type ContactPointUIDReference struct {
|
||||
// ContactPointUID should be the contact point UID identifier
|
||||
// in:path
|
||||
ID string
|
||||
UID string
|
||||
}
|
||||
|
||||
// swagger:parameters RoutePostContactpoints RoutePutContactpoint
|
||||
|
@ -3016,7 +3016,6 @@
|
||||
"x-go-package": "github.com/prometheus/alertmanager/timeinterval"
|
||||
},
|
||||
"URL": {
|
||||
"description": "The general form represented is:\n\n[scheme:][//[userinfo@]host][/]path[?query][#fragment]\n\nURLs that do not start with a slash after the scheme are interpreted as:\n\nscheme:opaque[?query][#fragment]\n\nNote that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.\nA consequence is that it is impossible to tell which slashes in the Path were\nslashes in the raw URL and which were %2f. This distinction is rarely important,\nbut when it is, the code should use RawPath, an optional field which only gets\nset if the default encoding is different from Path.\n\nURL's String method uses the EscapedPath method to obtain the path. See the\nEscapedPath method for more details.",
|
||||
"properties": {
|
||||
"ForceQuery": {
|
||||
"type": "boolean"
|
||||
@ -3049,9 +3048,9 @@
|
||||
"$ref": "#/definitions/Userinfo"
|
||||
}
|
||||
},
|
||||
"title": "A URL represents a parsed URL (technically, a URI reference).",
|
||||
"title": "URL is a custom URL type that allows validation at configuration load time.",
|
||||
"type": "object",
|
||||
"x-go-package": "net/url"
|
||||
"x-go-package": "github.com/prometheus/common/config"
|
||||
},
|
||||
"Userinfo": {
|
||||
"description": "The Userinfo type is an immutable encapsulation of username and\npassword details for a URL. An existing Userinfo value is guaranteed\nto have a username set (potentially empty, as allowed by RFC 2396),\nand optionally a password.",
|
||||
@ -3248,7 +3247,6 @@
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models"
|
||||
},
|
||||
"alertGroup": {
|
||||
"description": "AlertGroup alert group",
|
||||
"properties": {
|
||||
"alerts": {
|
||||
"description": "alerts",
|
||||
@ -3270,7 +3268,9 @@
|
||||
"labels",
|
||||
"receiver"
|
||||
],
|
||||
"type": "object"
|
||||
"type": "object",
|
||||
"x-go-name": "AlertGroup",
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models"
|
||||
},
|
||||
"alertGroups": {
|
||||
"description": "AlertGroups alert groups",
|
||||
@ -3522,12 +3522,11 @@
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models"
|
||||
},
|
||||
"gettableSilences": {
|
||||
"description": "GettableSilences gettable silences",
|
||||
"items": {
|
||||
"$ref": "#/definitions/gettableSilence"
|
||||
},
|
||||
"type": "array",
|
||||
"x-go-name": "GettableSilences",
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models"
|
||||
"type": "array"
|
||||
},
|
||||
"labelSet": {
|
||||
"additionalProperties": {
|
||||
@ -3656,7 +3655,6 @@
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models"
|
||||
},
|
||||
"postableSilence": {
|
||||
"description": "PostableSilence postable silence",
|
||||
"properties": {
|
||||
"comment": {
|
||||
"description": "comment",
|
||||
@ -3696,7 +3694,9 @@
|
||||
"matchers",
|
||||
"startsAt"
|
||||
],
|
||||
"type": "object"
|
||||
"type": "object",
|
||||
"x-go-name": "PostableSilence",
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models"
|
||||
},
|
||||
"receiver": {
|
||||
"description": "Receiver receiver",
|
||||
@ -5113,7 +5113,7 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/provisioning/contact-points/{ID}": {
|
||||
"/api/provisioning/contact-points/{UID}": {
|
||||
"delete": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
@ -5123,7 +5123,7 @@
|
||||
{
|
||||
"description": "ContactPointUID should be the contact point UID identifier",
|
||||
"in": "path",
|
||||
"name": "ID",
|
||||
"name": "UID",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
@ -5156,7 +5156,7 @@
|
||||
{
|
||||
"description": "ContactPointUID should be the contact point UID identifier",
|
||||
"in": "path",
|
||||
"name": "ID",
|
||||
"name": "UID",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
@ -5229,7 +5229,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"summary": "Update the interval of an rule group.",
|
||||
"summary": "Update the interval of a rule group.",
|
||||
"tags": [
|
||||
"provisioning"
|
||||
]
|
||||
|
@ -1306,7 +1306,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/provisioning/contact-points/{ID}": {
|
||||
"/api/provisioning/contact-points/{UID}": {
|
||||
"put": {
|
||||
"consumes": [
|
||||
"application/json"
|
||||
@ -1320,7 +1320,7 @@
|
||||
{
|
||||
"type": "string",
|
||||
"description": "ContactPointUID should be the contact point UID identifier",
|
||||
"name": "ID",
|
||||
"name": "UID",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
@ -1360,7 +1360,7 @@
|
||||
{
|
||||
"type": "string",
|
||||
"description": "ContactPointUID should be the contact point UID identifier",
|
||||
"name": "ID",
|
||||
"name": "UID",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
@ -1389,7 +1389,7 @@
|
||||
"tags": [
|
||||
"provisioning"
|
||||
],
|
||||
"summary": "Update the interval of an rule group.",
|
||||
"summary": "Update the interval of a rule group.",
|
||||
"operationId": "RoutePutAlertRuleGroup",
|
||||
"parameters": [
|
||||
{
|
||||
@ -5395,9 +5395,8 @@
|
||||
"x-go-package": "github.com/prometheus/alertmanager/timeinterval"
|
||||
},
|
||||
"URL": {
|
||||
"description": "The general form represented is:\n\n[scheme:][//[userinfo@]host][/]path[?query][#fragment]\n\nURLs that do not start with a slash after the scheme are interpreted as:\n\nscheme:opaque[?query][#fragment]\n\nNote that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.\nA consequence is that it is impossible to tell which slashes in the Path were\nslashes in the raw URL and which were %2f. This distinction is rarely important,\nbut when it is, the code should use RawPath, an optional field which only gets\nset if the default encoding is different from Path.\n\nURL's String method uses the EscapedPath method to obtain the path. See the\nEscapedPath method for more details.",
|
||||
"type": "object",
|
||||
"title": "A URL represents a parsed URL (technically, a URI reference).",
|
||||
"title": "URL is a custom URL type that allows validation at configuration load time.",
|
||||
"properties": {
|
||||
"ForceQuery": {
|
||||
"type": "boolean"
|
||||
@ -5430,7 +5429,7 @@
|
||||
"$ref": "#/definitions/Userinfo"
|
||||
}
|
||||
},
|
||||
"x-go-package": "net/url"
|
||||
"x-go-package": "github.com/prometheus/common/config"
|
||||
},
|
||||
"Userinfo": {
|
||||
"description": "The Userinfo type is an immutable encapsulation of username and\npassword details for a URL. An existing Userinfo value is guaranteed\nto have a username set (potentially empty, as allowed by RFC 2396),\nand optionally a password.",
|
||||
@ -5627,7 +5626,6 @@
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models"
|
||||
},
|
||||
"alertGroup": {
|
||||
"description": "AlertGroup alert group",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"alerts",
|
||||
@ -5650,6 +5648,8 @@
|
||||
"$ref": "#/definitions/receiver"
|
||||
}
|
||||
},
|
||||
"x-go-name": "AlertGroup",
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models",
|
||||
"$ref": "#/definitions/alertGroup"
|
||||
},
|
||||
"alertGroups": {
|
||||
@ -5906,12 +5906,11 @@
|
||||
"$ref": "#/definitions/gettableSilence"
|
||||
},
|
||||
"gettableSilences": {
|
||||
"description": "GettableSilences gettable silences",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/gettableSilence"
|
||||
},
|
||||
"x-go-name": "GettableSilences",
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models",
|
||||
"$ref": "#/definitions/gettableSilences"
|
||||
},
|
||||
"labelSet": {
|
||||
@ -6041,7 +6040,6 @@
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models"
|
||||
},
|
||||
"postableSilence": {
|
||||
"description": "PostableSilence postable silence",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"comment",
|
||||
@ -6082,6 +6080,8 @@
|
||||
"x-go-name": "StartsAt"
|
||||
}
|
||||
},
|
||||
"x-go-name": "PostableSilence",
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models",
|
||||
"$ref": "#/definitions/postableSilence"
|
||||
},
|
||||
"receiver": {
|
||||
|
@ -132,7 +132,9 @@ func (ecp *ContactPointService) CreateContactPoint(ctx context.Context, orgID in
|
||||
extractedSecrets[k] = encryptedValue
|
||||
}
|
||||
|
||||
contactPoint.UID = util.GenerateShortUID()
|
||||
if contactPoint.UID == "" {
|
||||
contactPoint.UID = util.GenerateShortUID()
|
||||
}
|
||||
grafanaReceiver := &apimodels.PostableGrafanaReceiver{
|
||||
UID: contactPoint.UID,
|
||||
Name: contactPoint.Name,
|
||||
|
@ -42,6 +42,21 @@ func TestContactPointService(t *testing.T) {
|
||||
require.Equal(t, "slack", cps[1].Type)
|
||||
})
|
||||
|
||||
t.Run("it's possbile to use a custom uid", func(t *testing.T) {
|
||||
customUID := "1337"
|
||||
sut := createContactPointServiceSut(secretsService)
|
||||
newCp := createTestContactPoint()
|
||||
newCp.UID = customUID
|
||||
|
||||
_, err := sut.CreateContactPoint(context.Background(), 1, newCp, models.ProvenanceAPI)
|
||||
require.NoError(t, err)
|
||||
|
||||
cps, err := sut.GetContactPoints(context.Background(), 1)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, cps, 2)
|
||||
require.Equal(t, customUID, cps[1].UID)
|
||||
})
|
||||
|
||||
t.Run("default provenance of contact points is none", func(t *testing.T) {
|
||||
sut := createContactPointServiceSut(secretsService)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user