From 09f8e026a19629ddc69c9cba83393202e3bf9671 Mon Sep 17 00:00:00 2001 From: Santiago Date: Mon, 3 Oct 2022 10:58:41 -0300 Subject: [PATCH] Alerting: Expose info about notification delivery errors in a new /receivers endpoint (#55429) * (WIP) switch to fork AM, first implementation of the API, generate spec * get receivers avoiding race conditions * use latest version of our forked AM, tests * make linter happy, delete TODO comment * update number of expected paths to += 2 * delete unused endpoint code, code review comments, tests * Update pkg/services/ngalert/notifier/alertmanager.go Co-authored-by: Matthew Jacobson * remove call to fmt.Println * clear naming for fields * shorter variable names in GetReceivers Co-authored-by: Matthew Jacobson --- go.mod | 14 +- go.sum | 66 +---- pkg/services/ngalert/api/api.go | 3 +- pkg/services/ngalert/api/api_alertmanager.go | 10 + pkg/services/ngalert/api/authorization.go | 2 + .../ngalert/api/authorization_test.go | 2 +- .../ngalert/api/forking_alertmanager.go | 4 + .../api/generated_base_api_alertmanager.go | 14 + pkg/services/ngalert/api/tooling/api.json | 190 ++++++-------- .../api/tooling/definitions/alertmanager.go | 13 + pkg/services/ngalert/api/tooling/post.json | 244 +++++++++-------- pkg/services/ngalert/api/tooling/spec.json | 245 +++++++++--------- pkg/services/ngalert/notifier/alertmanager.go | 49 ++-- .../ngalert/notifier/alertmanager_test.go | 2 +- .../ngalert/notifier/multiorg_alertmanager.go | 2 +- pkg/services/ngalert/notifier/receivers.go | 40 +++ .../alerting/api_notification_channel_test.go | 221 +++++++++++++++- 17 files changed, 667 insertions(+), 454 deletions(-) diff --git a/go.mod b/go.mod index 72f75eee7b7..1c11e3a65c9 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f github.com/aws/aws-sdk-go v1.44.9 github.com/beevik/etree v1.1.0 - github.com/benbjohnson/clock v1.1.0 + github.com/benbjohnson/clock v1.3.0 github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b github.com/centrifugal/centrifuge v0.25.0 github.com/cortexproject/cortex v1.10.1-0.20211014125347-85c378182d0d @@ -137,8 +137,6 @@ require ( github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/FZambia/eagle v0.0.2 // indirect github.com/FZambia/sentinel v1.1.0 // indirect - github.com/PuerkitoBio/purell v1.1.1 // indirect - github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/andybalholm/brotli v1.0.3 github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 // indirect @@ -162,12 +160,12 @@ require ( github.com/go-openapi/analysis v0.21.2 // indirect github.com/go-openapi/errors v0.20.2 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/loads v0.21.1 github.com/go-openapi/runtime v0.23.1 // indirect - github.com/go-openapi/spec v0.20.4 // indirect + github.com/go-openapi/spec v0.20.6 // indirect github.com/go-openapi/swag v0.21.1 // indirect - github.com/go-openapi/validate v0.21.0 // indirect + github.com/go-openapi/validate v0.22.0 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/status v1.1.0 // indirect github.com/golang-jwt/jwt/v4 v4.4.2 // indirect @@ -370,3 +368,7 @@ replace github.com/microcosm-cc/bluemonday => github.com/microcosm-cc/bluemonday // happen, for example, during a read when the sqlite db is under heavy write load. // This patch cherry picks compatible fixes from upstream xorm PR#1998 and can be reverted on upgrade to xorm v1.2.0+. replace xorm.io/xorm => github.com/grafana/xorm v0.8.3-0.20220614223926-2fcda7565af6 + +// Use our fork of the upstream alertmanagers. +// This is required in order to get notification delivery errors from the receivers API. +replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.24.0-rc.0.0.20220930143838-d75bdc5543c0 diff --git a/go.sum b/go.sum index 578cd6272d7..d2b82aeaef6 100644 --- a/go.sum +++ b/go.sum @@ -259,10 +259,8 @@ github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C6 github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/RoaringBitmap/gocroaring v0.4.0/go.mod h1:NieMwz7ZqwU2DD73/vvYwv7r4eWBKuPVSXZIpsaMwCI= github.com/RoaringBitmap/real-roaring-datasets v0.0.0-20190726190000-eb7c87156f76/go.mod h1:oM0MHmQ3nDsq609SS36p+oYbRi16+oVvU2Bw4Ipv0SE= @@ -357,7 +355,6 @@ github.com/aws/aws-sdk-go v1.38.3/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zK github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.38.60/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.38.68/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.40.11/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/aws/aws-sdk-go v1.40.37/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/aws/aws-sdk-go v1.43.11/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= @@ -412,8 +409,9 @@ github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/immutable v0.2.1/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI= github.com/benbjohnson/tmpl v1.0.0/go.mod h1:igT620JFIi44B6awvU9IsDhR77IXWtFigTLil/RPdps= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -475,11 +473,8 @@ github.com/caio/go-tdigest v3.1.0+incompatible h1:uoVMJ3Q5lXmVLCCqaMGHLBWnbGoN6L github.com/caio/go-tdigest v3.1.0+incompatible/go.mod h1:sHQM/ubZStBUmF1WbB8FAm8q9GjDajLC5T7ydxE3JHI= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/casbin/casbin/v2 v2.31.6/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= -github.com/cenkalti/backoff v0.0.0-20181003080854-62661b46c409/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v1.0.0/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= -github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= @@ -490,7 +485,6 @@ github.com/centrifugal/centrifuge v0.25.0/go.mod h1:bFcSFalnROq/wcFeRiTG+wIbHsxE github.com/centrifugal/protocol v0.8.10 h1:eezzBIU/4pWyl7a+NUnANYojJBASqbkPZcQh9b8YQRI= github.com/centrifugal/protocol v0.8.10/go.mod h1:dlHBjKakr0r+f1pkfwSMfZ+cnpvidN7pQe1ZrsKfhtE= github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/cespare/xxhash v0.0.0-20181017004759-096ff4a8a059/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -937,7 +931,6 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= @@ -950,7 +943,6 @@ github.com/go-openapi/analysis v0.20.1/go.mod h1:BMchjvaHDykmRMsK40iPtvyOfFdMMxl github.com/go-openapi/analysis v0.21.2 h1:hXFrOYFHUAMQdu6zwAiKKJHJQ8kqZs1ux/ru1P1wLJU= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= github.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= @@ -964,7 +956,6 @@ github.com/go-openapi/errors v0.20.2 h1:dxy7PGTqEh94zj2E3h1cUmQQWiM1+aeCROfAr02E github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.17.2/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -972,16 +963,15 @@ github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUe github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.17.2/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= @@ -995,21 +985,17 @@ github.com/go-openapi/loads v0.20.2/go.mod h1:hTVUotJ+UonAMMZsvakEgmWKgtulweO9vY github.com/go-openapi/loads v0.21.1 h1:Wb3nVZpdEzDTcly8S4HMkey6fjARRzb7iEaySimlDW0= github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.18.0/go.mod h1:uI6pHuxWYTy94zZxgcwJkUWa9wbIlhteGfloI10GD4U= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= github.com/go-openapi/runtime v0.19.3/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo= github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiSjahULvYmlv98= github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk= -github.com/go-openapi/runtime v0.19.26/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M= github.com/go-openapi/runtime v0.19.28/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M= -github.com/go-openapi/runtime v0.19.29/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M= github.com/go-openapi/runtime v0.23.1 h1:/Drg9R96eMmgKJHVWZADz78XbE39/6QiIiB45mc+epo= github.com/go-openapi/runtime v0.23.1/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= @@ -1021,10 +1007,10 @@ github.com/go-openapi/spec v0.19.15/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFu github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= github.com/go-openapi/spec v0.20.1/go.mod h1:93x7oh+d+FQsmsieroS4cmR3u0p/ywH649a3qwC9OsQ= github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg= -github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ= +github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.17.2/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= @@ -1041,7 +1027,6 @@ github.com/go-openapi/strfmt v0.21.2 h1:5NDNgadiX1Vhemth/TH4gCGopWSTdDjxl60H3B7f github.com/go-openapi/strfmt v0.21.2/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.4/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= @@ -1055,7 +1040,6 @@ github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/ github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo= @@ -1066,8 +1050,9 @@ github.com/go-openapi/validate v0.19.14/go.mod h1:PdGrHe0rp6MG3A1SrAY/rIHATqzJEE github.com/go-openapi/validate v0.19.15/go.mod h1:tbn/fdOwYHgrhPBzidZfJC2MIVvs9GA7monOmWBbeCI= github.com/go-openapi/validate v0.20.1/go.mod h1:b60iJT+xNNLfaQJUqLI7946tYiFEOuE9E4k54HpKcJ0= github.com/go-openapi/validate v0.20.2/go.mod h1:e7OJoKNgd0twXZwIn0A43tHbvIcr/rZIVCbJBpTUoY0= -github.com/go-openapi/validate v0.21.0 h1:+Wqk39yKOhfpLqNLEC0/eViCkzM5FVXVqrvt526+wcI= github.com/go-openapi/validate v0.21.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +github.com/go-openapi/validate v0.22.0 h1:b0QecH6VslW/TxtpKgzpO1SNG7GU2FsaqKdP1E2T50Y= +github.com/go-openapi/validate v0.22.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= @@ -1305,7 +1290,6 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -1385,6 +1369,8 @@ github.com/grafana/grafana-google-sdk-go v0.0.0-20211104130251-b190293eaf58/go.m github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk= github.com/grafana/grafana-plugin-sdk-go v0.139.0 h1:2RQKM2QpSaWTtaGN6sK+R7LO7zykOeTYF0QkAMA7JsI= github.com/grafana/grafana-plugin-sdk-go v0.139.0/go.mod h1:Y+Ps2sesZ62AyCnX+hzrYnyDQYe/ZZl+A8yKLOBm12c= +github.com/grafana/prometheus-alertmanager v0.24.0-rc.0.0.20220930143838-d75bdc5543c0 h1:Ifcxl2wKT+UoJE+d2hsEZjH5FVdF5nML+1dtMliFk78= +github.com/grafana/prometheus-alertmanager v0.24.0-rc.0.0.20220930143838-d75bdc5543c0/go.mod h1:xVHSIhcJ2xBqw8jSf7ZM+9NnTSV68dCLrj7MDiFEse8= github.com/grafana/saml v0.4.9-0.20220727151557-61cd9c9353fc h1:1PY8n+rXuBNr3r1JQhoytWDCpc+pq+BibxV0SZv+Cr4= github.com/grafana/saml v0.4.9-0.20220727151557-61cd9c9353fc/go.mod h1:9Zh6dWPtB3MSzTRt8fIFH60Z351QQ+s7hCU3J/tTlA4= github.com/grafana/thema v0.0.0-20220817114012-ebeee841c104 h1:dYpwFYIChrMfpq3wDa/ZBxAbUGSW5NYmYBeSezhaoao= @@ -1498,7 +1484,6 @@ github.com/hashicorp/memberlist v0.1.5/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/memberlist v0.2.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.2.3/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/memberlist v0.2.4/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.3.1 h1:MXgUXLqva1QvpVEDQW1IQLG0wivQAtmFlHRQ+1vWZfM= github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= @@ -1626,7 +1611,6 @@ github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/U github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= -github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= @@ -1724,7 +1708,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE= -github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= @@ -1974,7 +1957,6 @@ github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtb github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= -github.com/oklog/ulid v0.0.0-20170117200651-66bb6560562f/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= @@ -2105,19 +2087,6 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= -github.com/prometheus/alertmanager v0.18.0/go.mod h1:WcxHBl40VSPuOaqWae6l6HpnEOVRIycEJ7i9iYkadEE= -github.com/prometheus/alertmanager v0.19.0/go.mod h1:Eyp94Yi/T+kdeb2qvq66E3RGuph5T/jm/RBVh4yz1xo= -github.com/prometheus/alertmanager v0.20.0/go.mod h1:9g2i48FAyZW6BtbsnvHtMHQXl2aVtrORKwKVCQ+nbrg= -github.com/prometheus/alertmanager v0.21.0/go.mod h1:h7tJ81NA0VLWvWEayi1QltevFkLF3KxmC/malTcT8Go= -github.com/prometheus/alertmanager v0.21.1-0.20200911160112-1fdff6b3f939/go.mod h1:imXRHOP6QTsE0fFsIsAV/cXimS32m7gVZOiUj11m6Ig= -github.com/prometheus/alertmanager v0.21.1-0.20201106142418-c39b78780054/go.mod h1:imXRHOP6QTsE0fFsIsAV/cXimS32m7gVZOiUj11m6Ig= -github.com/prometheus/alertmanager v0.21.1-0.20210310093010-0f9cab6991e6/go.mod h1:MTqVn+vIupE0dzdgo+sMcNCp37SCAi8vPrvKTTnTz9g= -github.com/prometheus/alertmanager v0.21.1-0.20210422101724-8176f78a70e1/go.mod h1:gsEqwD5BHHW9RNKvCuPOrrTMiP5I+faJUyLXvnivHik= -github.com/prometheus/alertmanager v0.22.2/go.mod h1:rYinOWxFuCnNssc3iOjn2oMTlhLaPcUuqV5yk5JKUAE= -github.com/prometheus/alertmanager v0.23.0/go.mod h1:0MLTrjQI8EuVmvykEhcfr/7X0xmaDAZrqMgxIq3OXHk= -github.com/prometheus/alertmanager v0.23.1-0.20210914172521-e35efbddb66a/go.mod h1:U7pGu+z7A9ZKhK8lq1MvIOp5GdVlZjwOYk+S0h3LSbA= -github.com/prometheus/alertmanager v0.24.0 h1:HBWR3lk4uy3ys+naDZthDdV7yEsxpaNeZuUS+hJgrOw= -github.com/prometheus/alertmanager v0.24.0/go.mod h1:r6fy/D7FRuZh5YbnX6J3MBY0eI4Pb5yPYS7/bPSXXqI= github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -2163,24 +2132,20 @@ github.com/prometheus/common v0.8.0/go.mod h1:PC/OgXc+UN7B4ALwvn1yzVZmVwvhXp5Jsb github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.11.1/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.12.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.20.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.21.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.23.0/go.mod h1:H6QK/N6XVT42whUeIdI3dp36w49c+/iMDk7UAI2qm7Q= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.31.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= -github.com/prometheus/exporter-toolkit v0.5.0/go.mod h1:OCkM4805mmisBhLmVFw858QYi3v0wKdY6/UxrT0pZVg= github.com/prometheus/exporter-toolkit v0.5.1/go.mod h1:OCkM4805mmisBhLmVFw858QYi3v0wKdY6/UxrT0pZVg= github.com/prometheus/exporter-toolkit v0.6.1/go.mod h1:ZUBIj498ePooX9t/2xtDjeQYwvRpiPP2lh5u4iblj2g= github.com/prometheus/exporter-toolkit v0.7.1 h1:c6RXaK8xBVercEeUQ4tRNL8UGWzDHfvj9dseo1FcK1Y= @@ -2207,7 +2172,6 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/prometheus v0.0.0-20180315085919-58e2a31db8de/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= github.com/prometheus/prometheus v0.0.0-20190818123050-43acd0e2e93f/go.mod h1:rMTlmxGCvukf2KMu3fClMDKLLoJ5hl61MhcJ7xKakf0= github.com/prometheus/prometheus v0.0.0-20200609090129-a6600f564e3c/go.mod h1:S5n0C6tSgdnwWshBUceRx5G1OsjLv/EeZ9t3wIfEtsY= github.com/prometheus/prometheus v1.8.2-0.20200107122003-4708915ac6ef/go.mod h1:7U90zPoLkWjEIQcy/rweQla82OCTUzxVHE51G3OhJbI= @@ -2253,8 +2217,6 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= @@ -2278,7 +2240,6 @@ github.com/samuel/go-zookeeper v0.0.0-20200724154423-2164a8ac840e/go.mod h1:gi+0 github.com/samuel/go-zookeeper v0.0.0-20201211165307-7117e9ea2414/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sanity-io/litter v1.2.0/go.mod h1:JF6pZUFgu2Q0sBZ+HSV35P8TVPI1TTzEwyu9FXAw2W4= github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= -github.com/satori/go.uuid v0.0.0-20160603004225-b111a074d5ef/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210223165440-c65ae3540d44 h1:3egqo0Vut6daANFm7tOXdNAa8v5/uLU+sgCJrc88Meo= @@ -2304,11 +2265,9 @@ github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX github.com/shirou/gopsutil v3.21.6+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/shurcooL/vfsgen v0.0.0-20180825020608-02ddb050ef6b/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/shurcooL/vfsgen v0.0.0-20200627165143-92b8a710ab6c/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= @@ -2506,7 +2465,6 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= -github.com/xlab/treeprint v1.0.0/go.mod h1:IoImgRak9i3zJyuxOKUP1v4UZd1tMoKkq/Cimt1uhCg= github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/xorcare/pointer v1.1.0 h1:sFwXOhRF8QZ0tyVZrtxWGIoVZNEmRzBCaFWdONPQIUM= @@ -2871,7 +2829,6 @@ golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -3109,7 +3066,6 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180805044716-cb6730876b98/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -3142,7 +3098,6 @@ golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181112210238-4b1f3b6b1646/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -3209,7 +3164,6 @@ golang.org/x/tools v0.0.0-20200422205258-72e4a01eba43/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200513201620-d5fe73897c97/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200603131246-cc40288be839/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= diff --git a/pkg/services/ngalert/api/api.go b/pkg/services/ngalert/api/api.go index eb16162cc57..b69aae655a2 100644 --- a/pkg/services/ngalert/api/api.go +++ b/pkg/services/ngalert/api/api.go @@ -49,7 +49,8 @@ type Alertmanager interface { GetAlerts(active, silenced, inhibited bool, filter []string, receiver string) (apimodels.GettableAlerts, error) GetAlertGroups(active, silenced, inhibited bool, filter []string, receiver string) (apimodels.AlertGroups, error) - // Testing + // Receivers + GetReceivers(ctx context.Context) apimodels.Receivers TestReceivers(ctx context.Context, c apimodels.TestReceiversConfigBodyParams) (*notifier.TestReceiversResult, error) } diff --git a/pkg/services/ngalert/api/api_alertmanager.go b/pkg/services/ngalert/api/api_alertmanager.go index fe714effe0e..4704c49dd14 100644 --- a/pkg/services/ngalert/api/api_alertmanager.go +++ b/pkg/services/ngalert/api/api_alertmanager.go @@ -248,6 +248,16 @@ func (srv AlertmanagerSrv) RoutePostAMAlerts(_ *models.ReqContext, _ apimodels.P return NotImplementedResp } +func (srv AlertmanagerSrv) RouteGetReceivers(c *models.ReqContext) response.Response { + am, errResp := srv.AlertmanagerFor(c.OrgID) + if errResp != nil { + return errResp + } + + rcvs := am.GetReceivers(c.Req.Context()) + return response.JSON(http.StatusOK, rcvs) +} + func (srv AlertmanagerSrv) RoutePostTestReceivers(c *models.ReqContext, body apimodels.TestReceiversConfigBodyParams) response.Response { if err := srv.crypto.LoadSecureSettings(c.Req.Context(), c.OrgID, body.Receivers); err != nil { var unknownReceiverError UnknownReceiverError diff --git a/pkg/services/ngalert/api/authorization.go b/pkg/services/ngalert/api/authorization.go index fda64e2b049..980aca94cb3 100644 --- a/pkg/services/ngalert/api/authorization.go +++ b/pkg/services/ngalert/api/authorization.go @@ -156,6 +156,8 @@ func (api *API) authorize(method, path string) web.Handler { case http.MethodPost + "/api/alertmanager/grafana/config/api/v1/alerts": // additional authorization is done in the request handler eval = ac.EvalAny(ac.EvalPermission(ac.ActionAlertingNotificationsWrite)) + case http.MethodGet + "/api/alertmanager/grafana/config/api/v1/receivers": + eval = ac.EvalPermission(ac.ActionAlertingNotificationsRead) case http.MethodPost + "/api/alertmanager/grafana/config/api/v1/receivers/test": fallback = middleware.ReqEditorRole eval = ac.EvalPermission(ac.ActionAlertingNotificationsRead) diff --git a/pkg/services/ngalert/api/authorization_test.go b/pkg/services/ngalert/api/authorization_test.go index d8b67290309..b4da61566fd 100644 --- a/pkg/services/ngalert/api/authorization_test.go +++ b/pkg/services/ngalert/api/authorization_test.go @@ -49,7 +49,7 @@ func TestAuthorize(t *testing.T) { } paths[p] = methods } - require.Len(t, paths, 40) + require.Len(t, paths, 41) ac := acmock.New() api := &API{AccessControl: ac} diff --git a/pkg/services/ngalert/api/forking_alertmanager.go b/pkg/services/ngalert/api/forking_alertmanager.go index afd3e90cfa2..46314c784e2 100644 --- a/pkg/services/ngalert/api/forking_alertmanager.go +++ b/pkg/services/ngalert/api/forking_alertmanager.go @@ -187,6 +187,10 @@ func (f *AlertmanagerApiHandler) handleRoutePostGrafanaAlertingConfig(ctx *model return f.GrafanaSvc.RoutePostAlertingConfig(ctx, conf) } +func (f *AlertmanagerApiHandler) handleRouteGetGrafanaReceivers(ctx *models.ReqContext) response.Response { + return f.GrafanaSvc.RouteGetReceivers(ctx) +} + func (f *AlertmanagerApiHandler) handleRoutePostTestGrafanaReceivers(ctx *models.ReqContext, conf apimodels.TestReceiversConfigBodyParams) response.Response { return f.GrafanaSvc.RoutePostTestReceivers(ctx, conf) } diff --git a/pkg/services/ngalert/api/generated_base_api_alertmanager.go b/pkg/services/ngalert/api/generated_base_api_alertmanager.go index 21f1c3cdc64..81ec3137c31 100644 --- a/pkg/services/ngalert/api/generated_base_api_alertmanager.go +++ b/pkg/services/ngalert/api/generated_base_api_alertmanager.go @@ -33,6 +33,7 @@ type AlertmanagerApi interface { RouteGetGrafanaAMAlerts(*models.ReqContext) response.Response RouteGetGrafanaAMStatus(*models.ReqContext) response.Response RouteGetGrafanaAlertingConfig(*models.ReqContext) response.Response + RouteGetGrafanaReceivers(*models.ReqContext) response.Response RouteGetGrafanaSilence(*models.ReqContext) response.Response RouteGetGrafanaSilences(*models.ReqContext) response.Response RouteGetSilence(*models.ReqContext) response.Response @@ -114,6 +115,9 @@ func (f *AlertmanagerApiHandler) RouteGetGrafanaAMStatus(ctx *models.ReqContext) func (f *AlertmanagerApiHandler) RouteGetGrafanaAlertingConfig(ctx *models.ReqContext) response.Response { return f.handleRouteGetGrafanaAlertingConfig(ctx) } +func (f *AlertmanagerApiHandler) RouteGetGrafanaReceivers(ctx *models.ReqContext) response.Response { + return f.handleRouteGetGrafanaReceivers(ctx) +} func (f *AlertmanagerApiHandler) RouteGetGrafanaSilence(ctx *models.ReqContext) response.Response { // Parse Path Parameters silenceIdParam := web.Params(ctx.Req)[":SilenceId"] @@ -330,6 +334,16 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics m, ), ) + group.Get( + toMacaronPath("/api/alertmanager/grafana/config/api/v1/receivers"), + api.authorize(http.MethodGet, "/api/alertmanager/grafana/config/api/v1/receivers"), + metrics.Instrument( + http.MethodGet, + "/api/alertmanager/grafana/config/api/v1/receivers", + srv.RouteGetGrafanaReceivers, + m, + ), + ) group.Get( toMacaronPath("/api/alertmanager/grafana/api/v2/silence/{SilenceId}"), api.authorize(http.MethodGet, "/api/alertmanager/grafana/api/v2/silence/{SilenceId}"), diff --git a/pkg/services/ngalert/api/tooling/api.json b/pkg/services/ngalert/api/tooling/api.json index 77f1f835b18..90cc5839c6a 100644 --- a/pkg/services/ngalert/api/tooling/api.json +++ b/pkg/services/ngalert/api/tooling/api.json @@ -260,7 +260,7 @@ "type": "string" }, "for": { - "$ref": "#/definitions/Duration" + "type": "string" }, "labels": { "additionalProperties": { @@ -378,25 +378,6 @@ "title": "DataTopic is used to identify which topic the frame should be assigned to.", "type": "string" }, - "DateTime": { - "description": "DateTime is a time but it serializes to ISO8601 format with millis\nIt knows how to read 3 different variations of a RFC3339 date time.\nMost APIs we encounter want either millisecond or second precision times.\nThis just tries to make it worry-free.", - "format": "date-time", - "type": "string" - }, - "DayOfMonthRange": { - "properties": { - "Begin": { - "format": "int64", - "type": "integer" - }, - "End": { - "format": "int64", - "type": "integer" - } - }, - "title": "A DayOfMonthRange is an inclusive range that may have negative Beginning/End values that represent distance from the End of the month Beginning at -1.", - "type": "object" - }, "DiscoveryBase": { "properties": { "error": { @@ -625,16 +606,12 @@ "FieldConfig": { "properties": { "color": { - "additionalProperties": { - "type": "object" - }, + "additionalProperties": {}, "description": "Map values to a display color\nNOTE: this interface is under development in the frontend... so simple map for now", "type": "object" }, "custom": { - "additionalProperties": { - "type": "object" - }, + "additionalProperties": {}, "description": "Panel Specific Values", "type": "object" }, @@ -742,8 +719,7 @@ "type": "string" }, "custom": { - "description": "Custom datasource specific values.", - "type": "object" + "description": "Custom datasource specific values." }, "dataTopic": { "$ref": "#/definitions/DataTopic" @@ -939,7 +915,7 @@ "type": "string" }, "for": { - "$ref": "#/definitions/Duration" + "type": "string" }, "grafana_alert": { "$ref": "#/definitions/GettableGrafanaRule" @@ -1239,6 +1215,10 @@ "description": "The bearer token file for the targets. Deprecated in favour of\nAuthorization.CredentialsFile.", "type": "string" }, + "enable_http2": { + "description": "EnableHTTP2 specifies whether the client should configure HTTP2.\nThe omitempty flag is not set, because it would be hidden from the\nmarshalled configuration when set to false.", + "type": "boolean" + }, "follow_redirects": { "description": "FollowRedirects specifies whether the client should follow HTTP 3xx redirects.\nThe omitempty flag is not set, because it would be hidden from the\nmarshalled configuration when set to false.", "type": "boolean" @@ -1268,20 +1248,6 @@ "title": "HostPort represents a \"host:port\" network address.", "type": "object" }, - "InclusiveRange": { - "properties": { - "Begin": { - "format": "int64", - "type": "integer" - }, - "End": { - "format": "int64", - "type": "integer" - } - }, - "title": "InclusiveRange is used to hold the Beginning and End values of many time interval components.", - "type": "object" - }, "InhibitRule": { "description": "InhibitRule defines an inhibition rule that mutes alerts that match the\ntarget labels if an alert matching the source labels exists.\nBoth alerts have to have a set of labels being equal.", "properties": { @@ -1501,20 +1467,6 @@ }, "type": "array" }, - "MonthRange": { - "properties": { - "Begin": { - "format": "int64", - "type": "integer" - }, - "End": { - "format": "int64", - "type": "integer" - } - }, - "title": "A MonthRange is an inclusive range between [1, 12] where 1 = January.", - "type": "object" - }, "MultiStatus": { "type": "object" }, @@ -1605,6 +1557,9 @@ }, "type": "object" }, + "proxy_url": { + "$ref": "#/definitions/URL" + }, "scopes": { "items": { "type": "string" @@ -1931,7 +1886,7 @@ "type": "string" }, "for": { - "$ref": "#/definitions/Duration" + "type": "string" }, "grafana_alert": { "$ref": "#/definitions/PostableGrafanaRule" @@ -2220,7 +2175,7 @@ "PushoverConfig": { "properties": { "expire": { - "$ref": "#/definitions/duration" + "type": "string" }, "html": { "type": "boolean" @@ -2235,7 +2190,7 @@ "type": "string" }, "retry": { - "$ref": "#/definitions/duration" + "type": "string" }, "send_resolved": { "type": "boolean" @@ -2265,16 +2220,12 @@ "description": "The embedded FieldConfig's display name must be set.\nIt corresponds to the QueryResultMetaStat on the frontend (https://github.com/grafana/grafana/blob/master/packages/grafana-data/src/types/data.ts#L53).", "properties": { "color": { - "additionalProperties": { - "type": "object" - }, + "additionalProperties": {}, "description": "Map values to a display color\nNOTE: this interface is under development in the frontend... so simple map for now", "type": "object" }, "custom": { - "additionalProperties": { - "type": "object" - }, + "additionalProperties": {}, "description": "Panel Specific Values", "type": "object" }, @@ -2462,10 +2413,10 @@ "type": "array" }, "group_interval": { - "$ref": "#/definitions/Duration" + "type": "string" }, "group_wait": { - "$ref": "#/definitions/Duration" + "type": "string" }, "match": { "additionalProperties": { @@ -2496,7 +2447,7 @@ "type": "string" }, "repeat_interval": { - "$ref": "#/definitions/Duration" + "type": "string" }, "routes": { "items": { @@ -2897,6 +2848,9 @@ "description": "The client key file for the targets.", "type": "string" }, + "min_version": { + "$ref": "#/definitions/TLSVersion" + }, "server_name": { "description": "Used to verify the hostname for the targets.", "type": "string" @@ -2905,6 +2859,10 @@ "title": "TLSConfig configures the options for TLS connections.", "type": "object" }, + "TLSVersion": { + "format": "uint16", + "type": "integer" + }, "TelegramConfig": { "properties": { "api_url": { @@ -3073,13 +3031,13 @@ "properties": { "days_of_month": { "items": { - "$ref": "#/definitions/DayOfMonthRange" + "type": "string" }, "type": "array" }, "months": { "items": { - "$ref": "#/definitions/MonthRange" + "type": "string" }, "type": "array" }, @@ -3091,13 +3049,13 @@ }, "weekdays": { "items": { - "$ref": "#/definitions/WeekdayRange" + "type": "string" }, "type": "array" }, "years": { "items": { - "$ref": "#/definitions/YearRange" + "type": "string" }, "type": "array" } @@ -3120,7 +3078,6 @@ "type": "object" }, "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" @@ -3131,6 +3088,9 @@ "Host": { "type": "string" }, + "OmitHost": { + "type": "boolean" + }, "Opaque": { "type": "string" }, @@ -3153,7 +3113,7 @@ "$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" }, "Userinfo": { @@ -3291,34 +3251,6 @@ "title": "WechatConfig configures notifications via Wechat.", "type": "object" }, - "WeekdayRange": { - "properties": { - "Begin": { - "format": "int64", - "type": "integer" - }, - "End": { - "format": "int64", - "type": "integer" - } - }, - "title": "A WeekdayRange is an inclusive range between [0, 6] where 0 = Sunday.", - "type": "object" - }, - "YearRange": { - "properties": { - "Begin": { - "format": "int64", - "type": "integer" - }, - "End": { - "format": "int64", - "type": "integer" - } - }, - "title": "A YearRange is a positive inclusive range.", - "type": "object" - }, "alert": { "description": "Alert alert", "properties": { @@ -3361,6 +3293,7 @@ "type": "object" }, "alertGroups": { + "description": "AlertGroups alert groups", "items": { "$ref": "#/definitions/alertGroup" }, @@ -3464,10 +3397,8 @@ ], "type": "object" }, - "duration": { - "$ref": "#/definitions/Duration" - }, "gettableAlert": { + "description": "GettableAlert gettable alert", "properties": { "annotations": { "$ref": "#/definitions/labelSet" @@ -3530,6 +3461,7 @@ "type": "array" }, "gettableSilence": { + "description": "GettableSilence gettable silence", "properties": { "comment": { "description": "comment", @@ -3578,11 +3510,42 @@ "type": "object" }, "gettableSilences": { + "description": "GettableSilences gettable silences", "items": { "$ref": "#/definitions/gettableSilence" }, "type": "array" }, + "integration": { + "properties": { + "lastNotifyAttempt": { + "description": "A timestamp indicating the last attempt to deliver a notification regardless of the outcome.\nFormat: date-time", + "format": "date-time", + "type": "string" + }, + "lastNotifyAttemptDuration": { + "description": "Duration of the last attempt to deliver a notification in humanized format (`1s` or `15ms`, etc).", + "type": "string" + }, + "lastNotifyAttemptError": { + "description": "Error string for the last attempt to deliver a notification. Empty if the last attempt was successful.", + "type": "string" + }, + "name": { + "description": "name", + "type": "string" + }, + "sendResolved": { + "description": "send resolved", + "type": "boolean" + } + }, + "required": [ + "name", + "sendResolved" + ], + "type": "object" + }, "labelSet": { "additionalProperties": { "type": "string" @@ -3688,6 +3651,7 @@ "type": "array" }, "postableSilence": { + "description": "PostableSilence postable silence", "properties": { "comment": { "description": "comment", @@ -3725,14 +3689,26 @@ "type": "object" }, "receiver": { - "description": "Receiver receiver", "properties": { + "active": { + "description": "active", + "type": "boolean" + }, + "integrations": { + "description": "integrations", + "items": { + "$ref": "#/definitions/integration" + }, + "type": "array" + }, "name": { "description": "name", "type": "string" } }, "required": [ + "active", + "integrations", "name" ], "type": "object" diff --git a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go index b666b78deaf..a870a692b12 100644 --- a/pkg/services/ngalert/api/tooling/definitions/alertmanager.go +++ b/pkg/services/ngalert/api/tooling/definitions/alertmanager.go @@ -142,6 +142,13 @@ import ( // 400: ValidationError // 404: NotFound +// swagger:route GET /api/alertmanager/grafana/config/api/v1/receivers alertmanager RouteGetGrafanaReceivers +// +// Get a list of all receivers. +// +// Responses: +// 200: receivers + // swagger:route POST /api/alertmanager/grafana/config/api/v1/receivers/test alertmanager RoutePostTestGrafanaReceivers // // Test Grafana managed receivers without saving them. @@ -403,6 +410,12 @@ type AlertGroup = amv2.AlertGroup // swagger:model receiver type Receiver = amv2.Receiver +// swagger:model receivers +type Receivers = []amv2.Receiver + +// swagger:model integration +type Integration = amv2.Integration + // swagger:parameters RouteGetAMAlerts RouteGetAMAlertGroups RouteGetGrafanaAMAlerts RouteGetGrafanaAMAlertGroups type AlertsParams struct { diff --git a/pkg/services/ngalert/api/tooling/post.json b/pkg/services/ngalert/api/tooling/post.json index 0489e9d3963..4593ee9a070 100644 --- a/pkg/services/ngalert/api/tooling/post.json +++ b/pkg/services/ngalert/api/tooling/post.json @@ -260,7 +260,7 @@ "type": "string" }, "for": { - "$ref": "#/definitions/Duration" + "type": "string" }, "labels": { "additionalProperties": { @@ -378,25 +378,6 @@ "title": "DataTopic is used to identify which topic the frame should be assigned to.", "type": "string" }, - "DateTime": { - "description": "DateTime is a time but it serializes to ISO8601 format with millis\nIt knows how to read 3 different variations of a RFC3339 date time.\nMost APIs we encounter want either millisecond or second precision times.\nThis just tries to make it worry-free.", - "format": "date-time", - "type": "string" - }, - "DayOfMonthRange": { - "properties": { - "Begin": { - "format": "int64", - "type": "integer" - }, - "End": { - "format": "int64", - "type": "integer" - } - }, - "title": "A DayOfMonthRange is an inclusive range that may have negative Beginning/End values that represent distance from the End of the month Beginning at -1.", - "type": "object" - }, "DiscoveryBase": { "properties": { "error": { @@ -625,16 +606,12 @@ "FieldConfig": { "properties": { "color": { - "additionalProperties": { - "type": "object" - }, + "additionalProperties": {}, "description": "Map values to a display color\nNOTE: this interface is under development in the frontend... so simple map for now", "type": "object" }, "custom": { - "additionalProperties": { - "type": "object" - }, + "additionalProperties": {}, "description": "Panel Specific Values", "type": "object" }, @@ -742,8 +719,7 @@ "type": "string" }, "custom": { - "description": "Custom datasource specific values.", - "type": "object" + "description": "Custom datasource specific values." }, "dataTopic": { "$ref": "#/definitions/DataTopic" @@ -939,7 +915,7 @@ "type": "string" }, "for": { - "$ref": "#/definitions/Duration" + "type": "string" }, "grafana_alert": { "$ref": "#/definitions/GettableGrafanaRule" @@ -1239,6 +1215,10 @@ "description": "The bearer token file for the targets. Deprecated in favour of\nAuthorization.CredentialsFile.", "type": "string" }, + "enable_http2": { + "description": "EnableHTTP2 specifies whether the client should configure HTTP2.\nThe omitempty flag is not set, because it would be hidden from the\nmarshalled configuration when set to false.", + "type": "boolean" + }, "follow_redirects": { "description": "FollowRedirects specifies whether the client should follow HTTP 3xx redirects.\nThe omitempty flag is not set, because it would be hidden from the\nmarshalled configuration when set to false.", "type": "boolean" @@ -1268,20 +1248,6 @@ "title": "HostPort represents a \"host:port\" network address.", "type": "object" }, - "InclusiveRange": { - "properties": { - "Begin": { - "format": "int64", - "type": "integer" - }, - "End": { - "format": "int64", - "type": "integer" - } - }, - "title": "InclusiveRange is used to hold the Beginning and End values of many time interval components.", - "type": "object" - }, "InhibitRule": { "description": "InhibitRule defines an inhibition rule that mutes alerts that match the\ntarget labels if an alert matching the source labels exists.\nBoth alerts have to have a set of labels being equal.", "properties": { @@ -1501,20 +1467,6 @@ }, "type": "array" }, - "MonthRange": { - "properties": { - "Begin": { - "format": "int64", - "type": "integer" - }, - "End": { - "format": "int64", - "type": "integer" - } - }, - "title": "A MonthRange is an inclusive range between [1, 12] where 1 = January.", - "type": "object" - }, "MultiStatus": { "type": "object" }, @@ -1605,6 +1557,9 @@ }, "type": "object" }, + "proxy_url": { + "$ref": "#/definitions/URL" + }, "scopes": { "items": { "type": "string" @@ -1931,7 +1886,7 @@ "type": "string" }, "for": { - "$ref": "#/definitions/Duration" + "type": "string" }, "grafana_alert": { "$ref": "#/definitions/PostableGrafanaRule" @@ -2220,7 +2175,7 @@ "PushoverConfig": { "properties": { "expire": { - "$ref": "#/definitions/duration" + "type": "string" }, "html": { "type": "boolean" @@ -2235,7 +2190,7 @@ "type": "string" }, "retry": { - "$ref": "#/definitions/duration" + "type": "string" }, "send_resolved": { "type": "boolean" @@ -2265,16 +2220,12 @@ "description": "The embedded FieldConfig's display name must be set.\nIt corresponds to the QueryResultMetaStat on the frontend (https://github.com/grafana/grafana/blob/master/packages/grafana-data/src/types/data.ts#L53).", "properties": { "color": { - "additionalProperties": { - "type": "object" - }, + "additionalProperties": {}, "description": "Map values to a display color\nNOTE: this interface is under development in the frontend... so simple map for now", "type": "object" }, "custom": { - "additionalProperties": { - "type": "object" - }, + "additionalProperties": {}, "description": "Panel Specific Values", "type": "object" }, @@ -2462,10 +2413,10 @@ "type": "array" }, "group_interval": { - "$ref": "#/definitions/Duration" + "type": "string" }, "group_wait": { - "$ref": "#/definitions/Duration" + "type": "string" }, "match": { "additionalProperties": { @@ -2496,7 +2447,7 @@ "type": "string" }, "repeat_interval": { - "$ref": "#/definitions/Duration" + "type": "string" }, "routes": { "items": { @@ -2897,6 +2848,9 @@ "description": "The client key file for the targets.", "type": "string" }, + "min_version": { + "$ref": "#/definitions/TLSVersion" + }, "server_name": { "description": "Used to verify the hostname for the targets.", "type": "string" @@ -2905,6 +2859,10 @@ "title": "TLSConfig configures the options for TLS connections.", "type": "object" }, + "TLSVersion": { + "format": "uint16", + "type": "integer" + }, "TelegramConfig": { "properties": { "api_url": { @@ -3073,13 +3031,13 @@ "properties": { "days_of_month": { "items": { - "$ref": "#/definitions/DayOfMonthRange" + "type": "string" }, "type": "array" }, "months": { "items": { - "$ref": "#/definitions/MonthRange" + "type": "string" }, "type": "array" }, @@ -3091,13 +3049,13 @@ }, "weekdays": { "items": { - "$ref": "#/definitions/WeekdayRange" + "type": "string" }, "type": "array" }, "years": { "items": { - "$ref": "#/definitions/YearRange" + "type": "string" }, "type": "array" } @@ -3120,6 +3078,7 @@ "type": "object" }, "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" @@ -3130,6 +3089,9 @@ "Host": { "type": "string" }, + "OmitHost": { + "type": "boolean" + }, "Opaque": { "type": "string" }, @@ -3152,7 +3114,7 @@ "$ref": "#/definitions/Userinfo" } }, - "title": "URL is a custom URL type that allows validation at configuration load time.", + "title": "A URL represents a parsed URL (technically, a URI reference).", "type": "object" }, "Userinfo": { @@ -3290,34 +3252,6 @@ "title": "WechatConfig configures notifications via Wechat.", "type": "object" }, - "WeekdayRange": { - "properties": { - "Begin": { - "format": "int64", - "type": "integer" - }, - "End": { - "format": "int64", - "type": "integer" - } - }, - "title": "A WeekdayRange is an inclusive range between [0, 6] where 0 = Sunday.", - "type": "object" - }, - "YearRange": { - "properties": { - "Begin": { - "format": "int64", - "type": "integer" - }, - "End": { - "format": "int64", - "type": "integer" - } - }, - "title": "A YearRange is a positive inclusive range.", - "type": "object" - }, "alert": { "description": "Alert alert", "properties": { @@ -3462,11 +3396,7 @@ ], "type": "object" }, - "duration": { - "$ref": "#/definitions/Duration" - }, "gettableAlert": { - "description": "GettableAlert gettable alert", "properties": { "annotations": { "$ref": "#/definitions/labelSet" @@ -3522,6 +3452,7 @@ "type": "object" }, "gettableAlerts": { + "description": "GettableAlerts gettable alerts", "items": { "$ref": "#/definitions/gettableAlert" }, @@ -3576,12 +3507,42 @@ "type": "object" }, "gettableSilences": { - "description": "GettableSilences gettable silences", "items": { "$ref": "#/definitions/gettableSilence" }, "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", + "format": "date-time", + "type": "string" + }, + "lastNotifyAttemptDuration": { + "description": "Duration of the last attempt to deliver a notification in humanized format (`1s` or `15ms`, etc).", + "type": "string" + }, + "lastNotifyAttemptError": { + "description": "Error string for the last attempt to deliver a notification. Empty if the last attempt was successful.", + "type": "string" + }, + "name": { + "description": "name", + "type": "string" + }, + "sendResolved": { + "description": "send resolved", + "type": "boolean" + } + }, + "required": [ + "name", + "sendResolved" + ], + "type": "object" + }, "labelSet": { "additionalProperties": { "type": "string" @@ -3687,7 +3648,6 @@ "type": "array" }, "postableSilence": { - "description": "PostableSilence postable silence", "properties": { "comment": { "description": "comment", @@ -3725,13 +3685,27 @@ "type": "object" }, "receiver": { + "description": "Receiver receiver", "properties": { + "active": { + "description": "active", + "type": "boolean" + }, + "integrations": { + "description": "integrations", + "items": { + "$ref": "#/definitions/integration" + }, + "type": "array" + }, "name": { "description": "name", "type": "string" } }, "required": [ + "active", + "integrations", "name" ], "type": "object" @@ -4206,6 +4180,20 @@ ] } }, + "/api/alertmanager/grafana/config/api/v1/receivers": { + "get": { + "operationId": "RouteGetGrafanaReceivers", + "responses": { + "200": { + "$ref": "#/responses/receivers" + } + }, + "summary": "Get a list of all receivers.", + "tags": [ + "alertmanager" + ] + } + }, "/api/alertmanager/grafana/config/api/v1/receivers/test": { "post": { "operationId": "RoutePostTestGrafanaReceivers", @@ -5462,6 +5450,26 @@ ] } }, + "/api/v1/ngalert": { + "get": { + "description": "Get the status of the alerting engine", + "operationId": "RouteGetStatus", + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "AlertingStatus", + "schema": { + "$ref": "#/definitions/AlertingStatus" + } + } + }, + "tags": [ + "configuration" + ] + } + }, "/api/v1/ngalert/admin_config": { "delete": { "consumes": [ @@ -5571,26 +5579,6 @@ ] } }, - "/api/v1/ngalert": { - "get": { - "description": "Get the status of the alerting engine", - "operationId": "RouteGetStatus", - "produces": [ - "application/json" - ], - "responses": { - "200": { - "description": "AlertingStatus", - "schema": { - "$ref": "#/definitions/AlertingStatus" - } - } - }, - "tags": [ - "configuration" - ] - } - }, "/api/v1/provisioning/alert-rules": { "post": { "consumes": [ diff --git a/pkg/services/ngalert/api/tooling/spec.json b/pkg/services/ngalert/api/tooling/spec.json index e525d4d6707..d6cf15854ee 100644 --- a/pkg/services/ngalert/api/tooling/spec.json +++ b/pkg/services/ngalert/api/tooling/spec.json @@ -392,6 +392,20 @@ } } }, + "/api/alertmanager/grafana/config/api/v1/receivers": { + "get": { + "tags": [ + "alertmanager" + ], + "summary": "Get a list of all receivers.", + "operationId": "RouteGetGrafanaReceivers", + "responses": { + "200": { + "$ref": "#/responses/receivers" + } + } + } + }, "/api/alertmanager/grafana/config/api/v1/receivers/test": { "post": { "tags": [ @@ -1648,6 +1662,26 @@ } } }, + "/api/v1/ngalert": { + "get": { + "description": "Get the status of the alerting engine", + "produces": [ + "application/json" + ], + "tags": [ + "configuration" + ], + "operationId": "RouteGetStatus", + "responses": { + "200": { + "description": "AlertingStatus", + "schema": { + "$ref": "#/definitions/AlertingStatus" + } + } + } + } + }, "/api/v1/ngalert/admin_config": { "get": { "produces": [ @@ -1757,26 +1791,6 @@ } } }, - "/api/v1/ngalert": { - "get": { - "description": "Get the status of the alerting engine", - "produces": [ - "application/json" - ], - "tags": [ - "configuration" - ], - "operationId": "RouteGetStatus", - "responses": { - "200": { - "description": "AlertingStatus", - "schema": { - "$ref": "#/definitions/AlertingStatus" - } - } - } - } - }, "/api/v1/provisioning/alert-rules": { "post": { "consumes": [ @@ -2782,7 +2796,7 @@ "type": "string" }, "for": { - "$ref": "#/definitions/Duration" + "type": "string" }, "labels": { "type": "object", @@ -2899,25 +2913,6 @@ "type": "string", "title": "DataTopic is used to identify which topic the frame should be assigned to." }, - "DateTime": { - "description": "DateTime is a time but it serializes to ISO8601 format with millis\nIt knows how to read 3 different variations of a RFC3339 date time.\nMost APIs we encounter want either millisecond or second precision times.\nThis just tries to make it worry-free.", - "type": "string", - "format": "date-time" - }, - "DayOfMonthRange": { - "type": "object", - "title": "A DayOfMonthRange is an inclusive range that may have negative Beginning/End values that represent distance from the End of the month Beginning at -1.", - "properties": { - "Begin": { - "type": "integer", - "format": "int64" - }, - "End": { - "type": "integer", - "format": "int64" - } - } - }, "DiscoveryBase": { "type": "object", "required": [ @@ -3153,16 +3148,12 @@ "color": { "description": "Map values to a display color\nNOTE: this interface is under development in the frontend... so simple map for now", "type": "object", - "additionalProperties": { - "type": "object" - } + "additionalProperties": {} }, "custom": { "description": "Panel Specific Values", "type": "object", - "additionalProperties": { - "type": "object" - } + "additionalProperties": {} }, "decimals": { "type": "integer", @@ -3268,8 +3259,7 @@ "type": "string" }, "custom": { - "description": "Custom datasource specific values.", - "type": "object" + "description": "Custom datasource specific values." }, "dataTopic": { "$ref": "#/definitions/DataTopic" @@ -3464,7 +3454,7 @@ "type": "string" }, "for": { - "$ref": "#/definitions/Duration" + "type": "string" }, "grafana_alert": { "$ref": "#/definitions/GettableGrafanaRule" @@ -3765,6 +3755,10 @@ "description": "The bearer token file for the targets. Deprecated in favour of\nAuthorization.CredentialsFile.", "type": "string" }, + "enable_http2": { + "description": "EnableHTTP2 specifies whether the client should configure HTTP2.\nThe omitempty flag is not set, because it would be hidden from the\nmarshalled configuration when set to false.", + "type": "boolean" + }, "follow_redirects": { "description": "FollowRedirects specifies whether the client should follow HTTP 3xx redirects.\nThe omitempty flag is not set, because it would be hidden from the\nmarshalled configuration when set to false.", "type": "boolean" @@ -3792,20 +3786,6 @@ } } }, - "InclusiveRange": { - "type": "object", - "title": "InclusiveRange is used to hold the Beginning and End values of many time interval components.", - "properties": { - "Begin": { - "type": "integer", - "format": "int64" - }, - "End": { - "type": "integer", - "format": "int64" - } - } - }, "InhibitRule": { "description": "InhibitRule defines an inhibition rule that mutes alerts that match the\ntarget labels if an alert matching the source labels exists.\nBoth alerts have to have a set of labels being equal.", "type": "object", @@ -4026,20 +4006,6 @@ "$ref": "#/definitions/MessageTemplate" } }, - "MonthRange": { - "type": "object", - "title": "A MonthRange is an inclusive range between [1, 12] where 1 = January.", - "properties": { - "Begin": { - "type": "integer", - "format": "int64" - }, - "End": { - "type": "integer", - "format": "int64" - } - } - }, "MultiStatus": { "type": "object" }, @@ -4132,6 +4098,9 @@ "type": "string" } }, + "proxy_url": { + "$ref": "#/definitions/URL" + }, "scopes": { "type": "array", "items": { @@ -4457,7 +4426,7 @@ "type": "string" }, "for": { - "$ref": "#/definitions/Duration" + "type": "string" }, "grafana_alert": { "$ref": "#/definitions/PostableGrafanaRule" @@ -4746,7 +4715,7 @@ "type": "object", "properties": { "expire": { - "$ref": "#/definitions/duration" + "type": "string" }, "html": { "type": "boolean" @@ -4761,7 +4730,7 @@ "type": "string" }, "retry": { - "$ref": "#/definitions/duration" + "type": "string" }, "send_resolved": { "type": "boolean" @@ -4794,16 +4763,12 @@ "color": { "description": "Map values to a display color\nNOTE: this interface is under development in the frontend... so simple map for now", "type": "object", - "additionalProperties": { - "type": "object" - } + "additionalProperties": {} }, "custom": { "description": "Panel Specific Values", "type": "object", - "additionalProperties": { - "type": "object" - } + "additionalProperties": {} }, "decimals": { "type": "integer", @@ -4988,10 +4953,10 @@ } }, "group_interval": { - "$ref": "#/definitions/Duration" + "type": "string" }, "group_wait": { - "$ref": "#/definitions/Duration" + "type": "string" }, "match": { "description": "Deprecated. Remove before v1.0 release.", @@ -5022,7 +4987,7 @@ "type": "string" }, "repeat_interval": { - "$ref": "#/definitions/Duration" + "type": "string" }, "routes": { "type": "array", @@ -5424,12 +5389,19 @@ "description": "The client key file for the targets.", "type": "string" }, + "min_version": { + "$ref": "#/definitions/TLSVersion" + }, "server_name": { "description": "Used to verify the hostname for the targets.", "type": "string" } } }, + "TLSVersion": { + "type": "integer", + "format": "uint16" + }, "TelegramConfig": { "type": "object", "title": "TelegramConfig configures notifications via Telegram.", @@ -5600,13 +5572,13 @@ "days_of_month": { "type": "array", "items": { - "$ref": "#/definitions/DayOfMonthRange" + "type": "string" } }, "months": { "type": "array", "items": { - "$ref": "#/definitions/MonthRange" + "type": "string" } }, "times": { @@ -5618,13 +5590,13 @@ "weekdays": { "type": "array", "items": { - "$ref": "#/definitions/WeekdayRange" + "type": "string" } }, "years": { "type": "array", "items": { - "$ref": "#/definitions/YearRange" + "type": "string" } } } @@ -5645,8 +5617,9 @@ } }, "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": "URL is a custom URL type that allows validation at configuration load time.", + "title": "A URL represents a parsed URL (technically, a URI reference).", "properties": { "ForceQuery": { "type": "boolean" @@ -5657,6 +5630,9 @@ "Host": { "type": "string" }, + "OmitHost": { + "type": "boolean" + }, "Opaque": { "type": "string" }, @@ -5815,34 +5791,6 @@ } } }, - "WeekdayRange": { - "type": "object", - "title": "A WeekdayRange is an inclusive range between [0, 6] where 0 = Sunday.", - "properties": { - "Begin": { - "type": "integer", - "format": "int64" - }, - "End": { - "type": "integer", - "format": "int64" - } - } - }, - "YearRange": { - "type": "object", - "title": "A YearRange is a positive inclusive range.", - "properties": { - "Begin": { - "type": "integer", - "format": "int64" - }, - "End": { - "type": "integer", - "format": "int64" - } - } - }, "alert": { "description": "Alert alert", "type": "object", @@ -5989,11 +5937,7 @@ } } }, - "duration": { - "$ref": "#/definitions/Duration" - }, "gettableAlert": { - "description": "GettableAlert gettable alert", "type": "object", "required": [ "labels", @@ -6050,6 +5994,7 @@ "$ref": "#/definitions/gettableAlert" }, "gettableAlerts": { + "description": "GettableAlerts gettable alerts", "type": "array", "items": { "$ref": "#/definitions/gettableAlert" @@ -6106,13 +6051,44 @@ "$ref": "#/definitions/gettableSilence" }, "gettableSilences": { - "description": "GettableSilences gettable silences", "type": "array", "items": { "$ref": "#/definitions/gettableSilence" }, "$ref": "#/definitions/gettableSilences" }, + "integration": { + "description": "Integration integration", + "type": "object", + "required": [ + "name", + "sendResolved" + ], + "properties": { + "lastNotifyAttempt": { + "description": "A timestamp indicating the last attempt to deliver a notification regardless of the outcome.\nFormat: date-time", + "type": "string", + "format": "date-time" + }, + "lastNotifyAttemptDuration": { + "description": "Duration of the last attempt to deliver a notification in humanized format (`1s` or `15ms`, etc).", + "type": "string" + }, + "lastNotifyAttemptError": { + "description": "Error string for the last attempt to deliver a notification. Empty if the last attempt was successful.", + "type": "string" + }, + "name": { + "description": "name", + "type": "string" + }, + "sendResolved": { + "description": "send resolved", + "type": "boolean" + } + }, + "$ref": "#/definitions/integration" + }, "labelSet": { "description": "LabelSet label set", "type": "object", @@ -6218,7 +6194,6 @@ } }, "postableSilence": { - "description": "PostableSilence postable silence", "type": "object", "required": [ "comment", @@ -6257,11 +6232,25 @@ "$ref": "#/definitions/postableSilence" }, "receiver": { + "description": "Receiver receiver", "type": "object", "required": [ + "active", + "integrations", "name" ], "properties": { + "active": { + "description": "active", + "type": "boolean" + }, + "integrations": { + "description": "integrations", + "type": "array", + "items": { + "$ref": "#/definitions/integration" + } + }, "name": { "description": "name", "type": "string" diff --git a/pkg/services/ngalert/notifier/alertmanager.go b/pkg/services/ngalert/notifier/alertmanager.go index 7243a9ac606..9633aa48073 100644 --- a/pkg/services/ngalert/notifier/alertmanager.go +++ b/pkg/services/ngalert/notifier/alertmanager.go @@ -118,6 +118,8 @@ type Alertmanager struct { silencer *silence.Silencer silences *silence.Silences + receivers []*notify.Receiver + // muteTimes is a map where the key is the name of the mute_time_interval // and the value represents all configured time_interval(s) muteTimes map[string][]timeinterval.TimeInterval @@ -206,7 +208,7 @@ func newAlertmanager(ctx context.Context, orgID int64, cfg *setting.Cfg, store A }() // Initialize in-memory alerts - am.alerts, err = mem.NewAlerts(context.Background(), am.marker, memoryAlertsGCInterval, nil, am.logger) + am.alerts, err = mem.NewAlerts(context.Background(), am.marker, memoryAlertsGCInterval, nil, am.logger, m.Registerer) if err != nil { return nil, fmt.Errorf("unable to initialize the alert provider component of alerting: %w", err) } @@ -421,14 +423,20 @@ func (am *Alertmanager) applyConfig(cfg *apimodels.PostableUserConfig, rawConfig inhibitionStage := notify.NewMuteStage(am.inhibitor) timeMuteStage := notify.NewTimeMuteStage(am.muteTimes) silencingStage := notify.NewMuteStage(am.silencer) - for name := range integrationsMap { - stage := am.createReceiverStage(name, integrationsMap[name], am.waitFunc, am.notificationLog) - routingStage[name] = notify.MultiStage{meshStage, silencingStage, timeMuteStage, inhibitionStage, stage} - } am.route = dispatch.NewRoute(cfg.AlertmanagerConfig.Route.AsAMRoute(), nil) am.dispatcher = dispatch.NewDispatcher(am.alerts, am.route, routingStage, am.marker, am.timeoutFunc, &nilLimits{}, am.logger, am.dispatcherMetrics) + // Check which receivers are active and create the receiver stage. + activeReceivers := am.getActiveReceiversMap(am.route) + for name := range integrationsMap { + stage := am.createReceiverStage(name, integrationsMap[name], am.waitFunc, am.notificationLog) + routingStage[name] = notify.MultiStage{meshStage, silencingStage, timeMuteStage, inhibitionStage, stage} + _, isActive := activeReceivers[name] + + am.receivers = append(am.receivers, notify.NewReceiver(name, isActive, integrationsMap[name])) + } + am.wg.Add(1) go func() { defer am.wg.Done() @@ -452,8 +460,8 @@ func (am *Alertmanager) WorkingDirPath() string { } // buildIntegrationsMap builds a map of name to the list of Grafana integration notifiers off of a list of receiver config. -func (am *Alertmanager) buildIntegrationsMap(receivers []*apimodels.PostableApiReceiver, templates *template.Template) (map[string][]notify.Integration, error) { - integrationsMap := make(map[string][]notify.Integration, len(receivers)) +func (am *Alertmanager) buildIntegrationsMap(receivers []*apimodels.PostableApiReceiver, templates *template.Template) (map[string][]*notify.Integration, error) { + integrationsMap := make(map[string][]*notify.Integration, len(receivers)) for _, receiver := range receivers { integrations, err := am.buildReceiverIntegrations(receiver, templates) if err != nil { @@ -466,8 +474,8 @@ func (am *Alertmanager) buildIntegrationsMap(receivers []*apimodels.PostableApiR } // buildReceiverIntegrations builds a list of integration notifiers off of a receiver config. -func (am *Alertmanager) buildReceiverIntegrations(receiver *apimodels.PostableApiReceiver, tmpl *template.Template) ([]notify.Integration, error) { - var integrations []notify.Integration +func (am *Alertmanager) buildReceiverIntegrations(receiver *apimodels.PostableApiReceiver, tmpl *template.Template) ([]*notify.Integration, error) { + var integrations []*notify.Integration for i, r := range receiver.GrafanaManagedReceivers { n, err := am.buildReceiverIntegration(r, tmpl) if err != nil { @@ -667,18 +675,18 @@ func (e AlertValidationError) Error() string { } // createReceiverStage creates a pipeline of stages for a receiver. -func (am *Alertmanager) createReceiverStage(name string, integrations []notify.Integration, wait func() time.Duration, notificationLog notify.NotificationLog) notify.Stage { +func (am *Alertmanager) createReceiverStage(name string, integrations []*notify.Integration, wait func() time.Duration, notificationLog notify.NotificationLog) notify.Stage { var fs notify.FanoutStage - for i := range integrations { + for _, integration := range integrations { recv := &nflogpb.Receiver{ GroupName: name, - Integration: integrations[i].Name(), - Idx: uint32(integrations[i].Index()), + Integration: integration.Name(), + Idx: uint32(integration.Index()), } var s notify.MultiStage s = append(s, notify.NewWaitStage(wait)) - s = append(s, notify.NewDedupStage(&integrations[i], notificationLog, recv)) - s = append(s, notify.NewRetryStage(integrations[i], name, am.stageMetrics)) + s = append(s, notify.NewDedupStage(integration, notificationLog, recv)) + s = append(s, notify.NewRetryStage(integration, name, am.stageMetrics)) s = append(s, notify.NewSetNotifiesStage(notificationLog, recv)) fs = append(fs, s) @@ -686,6 +694,17 @@ func (am *Alertmanager) createReceiverStage(name string, integrations []notify.I return fs } +// getActiveReceiversMap returns all receivers that are in use by a route. +func (am *Alertmanager) getActiveReceiversMap(r *dispatch.Route) map[string]struct{} { + receiversMap := make(map[string]struct{}) + visitFunc := func(r *dispatch.Route) { + receiversMap[r.RouteOpts.Receiver] = struct{}{} + } + r.Walk(visitFunc) + + return receiversMap +} + func (am *Alertmanager) waitFunc() time.Duration { return time.Duration(am.peer.Position()) * am.peerTimeout } diff --git a/pkg/services/ngalert/notifier/alertmanager_test.go b/pkg/services/ngalert/notifier/alertmanager_test.go index 07adcaebbe5..63de5631b84 100644 --- a/pkg/services/ngalert/notifier/alertmanager_test.go +++ b/pkg/services/ngalert/notifier/alertmanager_test.go @@ -314,7 +314,7 @@ func TestPutAlert(t *testing.T) { t.Run(c.title, func(t *testing.T) { r := prometheus.NewRegistry() am.marker = types.NewMarker(r) - am.alerts, err = mem.NewAlerts(context.Background(), am.marker, 15*time.Minute, nil, am.logger) + am.alerts, err = mem.NewAlerts(context.Background(), am.marker, 15*time.Minute, nil, am.logger, r) require.NoError(t, err) alerts := []*types.Alert{} diff --git a/pkg/services/ngalert/notifier/multiorg_alertmanager.go b/pkg/services/ngalert/notifier/multiorg_alertmanager.go index dd07aba3785..5d060233cf2 100644 --- a/pkg/services/ngalert/notifier/multiorg_alertmanager.go +++ b/pkg/services/ngalert/notifier/multiorg_alertmanager.go @@ -85,7 +85,7 @@ func NewMultiOrgAlertmanager(cfg *setting.Cfg, configStore AlertingStore, orgSto true, cfg.UnifiedAlerting.HAPushPullInterval, cfg.UnifiedAlerting.HAGossipInterval, - cluster.DefaultTcpTimeout, + cluster.DefaultTCPTimeout, cluster.DefaultProbeTimeout, cluster.DefaultProbeInterval, nil, diff --git a/pkg/services/ngalert/notifier/receivers.go b/pkg/services/ngalert/notifier/receivers.go index 1b60a72793c..0e705cf0ff3 100644 --- a/pkg/services/ngalert/notifier/receivers.go +++ b/pkg/services/ngalert/notifier/receivers.go @@ -8,7 +8,9 @@ import ( "sort" "time" + "github.com/go-openapi/strfmt" apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" + "github.com/prometheus/alertmanager/api/v2/models" "github.com/prometheus/alertmanager/notify" "github.com/prometheus/alertmanager/types" "github.com/prometheus/common/model" @@ -197,6 +199,44 @@ func (am *Alertmanager) TestReceivers(ctx context.Context, c apimodels.TestRecei return newTestReceiversResult(testAlert, append(invalid, results...), now), nil } +func (am *Alertmanager) GetReceivers(ctx context.Context) apimodels.Receivers { + am.reloadConfigMtx.RLock() + defer am.reloadConfigMtx.RUnlock() + + var apiReceivers apimodels.Receivers + for _, rcv := range am.receivers { + // Build integrations slice for each receiver. + var integrations []*models.Integration + for _, integration := range rcv.Integrations() { + name := integration.Name() + sendResolved := integration.SendResolved() + ts, d, err := integration.GetReport() + integrations = append(integrations, &apimodels.Integration{ + Name: &name, + SendResolved: &sendResolved, + LastNotifyAttempt: strfmt.DateTime(ts), + LastNotifyAttemptDuration: d.String(), + LastNotifyAttemptError: func() string { + if err != nil { + return err.Error() + } + return "" + }(), + }) + } + + active := rcv.Active() + name := rcv.Name() + apiReceivers = append(apiReceivers, apimodels.Receiver{ + Active: &active, + Integrations: integrations, + Name: &name, + }) + } + + return apiReceivers +} + func newTestAlert(c apimodels.TestReceiversConfigBodyParams, startsAt, updatedAt time.Time) types.Alert { var ( defaultAnnotations = model.LabelSet{ diff --git a/pkg/tests/api/alerting/api_notification_channel_test.go b/pkg/tests/api/alerting/api_notification_channel_test.go index b49295b3717..051697e26ba 100644 --- a/pkg/tests/api/alerting/api_notification_channel_test.go +++ b/pkg/tests/api/alerting/api_notification_channel_test.go @@ -728,7 +728,7 @@ func TestNotificationChannels(t *testing.T) { channels.GetBoundary = func() string { return "abcd" } env.NotificationService.EmailHandlerSync = mockEmail.sendEmailCommandHandlerSync - // As we are using a NotificationService mock here, but he test expects real NotificationService - + // As we are using a NotificationService mock here, but the test expects real NotificationService - // we try to issue a real POST request here env.NotificationService.WebhookHandler = func(_ context.Context, cmd *models.SendWebhookSync) error { if res, err := http.Post(cmd.Url, "", strings.NewReader(cmd.Body)); err == nil { @@ -770,11 +770,31 @@ func TestNotificationChannels(t *testing.T) { re := regexp.MustCompile(`"uid":"([\w|-]*)"`) e := getExpAlertmanagerConfigFromAPI(mockChannel.server.Addr) require.JSONEq(t, e, string(re.ReplaceAll([]byte(b), []byte(`"uid":""`)))) + + // Check the receivers API. No errors nor attempts to notify should be registered. + receiversURL := fmt.Sprintf("http://grafana:password@%s/api/alertmanager/grafana/config/api/v1/receivers", grafanaListedAddr) + resp = getRequest(t, receiversURL, http.StatusOK) // nolint + b = getBody(t, resp.Body) + + var receivers apimodels.Receivers + err := json.Unmarshal([]byte(b), &receivers) + require.NoError(t, err) + for _, rcv := range receivers { + require.NotNil(t, rcv.Name) + require.NotNil(t, rcv.Active) + require.NotEmpty(t, rcv.Integrations) + for _, integration := range rcv.Integrations { + require.NotNil(t, integration.Name) + require.NotNil(t, integration.SendResolved) + require.Equal(t, "", integration.LastNotifyAttemptError) + require.Zero(t, integration.LastNotifyAttempt) + require.Equal(t, "0s", integration.LastNotifyAttemptDuration) + } + } } { // Create rules that will fire as quickly as possible - originalFunction := store.GenerateNewAlertRuleUID t.Cleanup(func() { store.GenerateNewAlertRuleUID = originalFunction @@ -791,6 +811,7 @@ func TestNotificationChannels(t *testing.T) { // Eventually, we'll get all the desired alerts. // nolint:gosec require.Eventually(t, func() bool { + // TODO: not waiting for the failed notifications, flaky test? return mockChannel.totalNotifications() >= len(nonEmailAlertNames) && len(mockEmail.emails) >= 1 }, 30*time.Second, 1*time.Second) @@ -798,6 +819,60 @@ func TestNotificationChannels(t *testing.T) { require.Equal(t, expEmailNotifications, mockEmail.emails) require.NoError(t, mockChannel.Close()) + // Check the receivers API. Errors and inactive receivers are expected, attempts to deliver notifications should be registered. + receiversURL := fmt.Sprintf("http://grafana:password@%s/api/alertmanager/grafana/config/api/v1/receivers", grafanaListedAddr) + resp := getRequest(t, receiversURL, http.StatusOK) // nolint + b := getBody(t, resp.Body) + + var receivers apimodels.Receivers + err := json.Unmarshal([]byte(b), &receivers) + require.NoError(t, err) + for _, rcv := range receivers { + var expActive bool + if _, ok := expInactiveReceivers[*rcv.Name]; !ok { + expActive = true + } + var expErr bool + if _, ok := expNotificationErrors[*rcv.Name]; ok { + expErr = true + } + + require.NotNil(t, rcv.Name) + require.NotNil(t, rcv.Active) + require.NotEmpty(t, rcv.Integrations) + if expActive { + require.True(t, *rcv.Active) + } + + // We don't have test alerts for the default notifier, continue iterating. + if *rcv.Name == "grafana-default-email" { + continue + } + + for _, integration := range rcv.Integrations { + require.NotNil(t, integration.Name) + require.NotNil(t, integration.SendResolved) + + // If the receiver is not active, no attempts to send notifications should be registered. + if expActive { + require.NotZero(t, integration.LastNotifyAttempt) + require.NotEqual(t, "0s", integration.LastNotifyAttemptDuration) + } else { + require.Zero(t, integration.LastNotifyAttempt) + require.Equal(t, "0s", integration.LastNotifyAttemptDuration) + } + + // Check whether we're expecting an error on this integration. + if expErr { + for _, integration := range rcv.Integrations { + require.Equal(t, expNotificationErrors[*rcv.Name], integration.LastNotifyAttemptError) + } + } else { + require.Equal(t, "", integration.LastNotifyAttemptError) + } + } + } + { // Delete the configuration; so it returns the default configuration. u := fmt.Sprintf("http://grafana:password@%s/api/alertmanager/grafana/config/api/v1/alerts", grafanaListedAddr) @@ -859,6 +934,10 @@ var emailAlertNames = []string{ "EmailAlert", } +var failedAlertNames = []string{ + "SlackFailedAlert", +} + func getRulesConfig(t *testing.T) string { t.Helper() interval, err := model.ParseDuration("10s") @@ -869,7 +948,10 @@ func getRulesConfig(t *testing.T) string { } // Create rules that will fire as quickly as possible for all the routes. - for _, alertName := range append(nonEmailAlertNames, emailAlertNames...) { + rulesToCreate := append(nonEmailAlertNames, emailAlertNames...) + rulesToCreate = append(rulesToCreate, failedAlertNames...) + + for _, alertName := range rulesToCreate { rules.Rules = append(rules.Rules, apimodels.PostableExtendedRuleNode{ GrafanaManagedAlert: &apimodels.PostableGrafanaRule{ Title: alertName, @@ -1124,6 +1206,26 @@ const alertmanagerConfig = ` "alertname=\"SlackAlert2\"" ] }, + { + "receiver": "slack_failed_recv", + "group_wait": "0s", + "group_by": [ + "alertname" + ], + "matchers": [ + "alertname=\"SlackFailedAlert\"" + ] + }, + { + "receiver": "slack_inactive_recv", + "group_wait": "0s", + "group_by": [ + "alertname" + ], + "matchers": [ + "alertname=\"Inactive\"" + ] + }, { "receiver": "pagerduty_recv", "group_wait": "0s", @@ -1273,7 +1375,7 @@ const alertmanagerConfig = ` "matchers": [ "alertname=\"TelegramAlert\"" ] - } + } ] }, "receivers": [ @@ -1483,7 +1585,7 @@ const alertmanagerConfig = ` } ] }, - { + { "name": "slack_recv1", "grafana_managed_receiver_configs": [ { @@ -1506,8 +1608,8 @@ const alertmanagerConfig = ` } } ] - }, - { + }, + { "name": "slack_recv2", "grafana_managed_receiver_configs": [ { @@ -1523,6 +1625,39 @@ const alertmanagerConfig = ` } } ] + }, + { + "name": "slack_failed_recv", + "grafana_managed_receiver_configs": [ + { + "name": "slack_failed_test", + "type": "slack", + "settings": { + "recipient": "#test-channel", + "username": "test", + "text": "Integration Test" + }, + "secureSettings": { + "url": "htt://127.0.0.1:8080/slack_failed_recv/slack_failed_test" + } + } + ] + }, + { + "name": "slack_inactive_recv", + "grafana_managed_receiver_configs": [ + { + "name": "inactive", + "type": "slack", + "settings": { + "recipient": "#inactive-channel", + "username": "Integration Test" + }, + "secureSettings": { + "token": "myfullysecrettoken" + } + } + ] }, { "name": "pagerduty_recv", @@ -1589,7 +1724,26 @@ var expAlertmanagerConfigFromAPI = ` "alertname=\"SlackAlert2\"" ] }, - { + { + "receiver": "slack_failed_recv", + "group_wait": "0s", + "group_by": [ + "alertname" + ], + "matchers": [ + "alertname=\"SlackFailedAlert\"" + ] + }, + { + "receiver": "slack_inactive_recv", + "group_wait": "0s", + "group_by": [ + "alertname" + ], + "matchers": [ + "alertname=\"Inactive\"" + ] + }, { "receiver": "pagerduty_recv", "group_wait": "0s", "group_by": [ @@ -1738,7 +1892,7 @@ var expAlertmanagerConfigFromAPI = ` "matchers": [ "alertname=\"TelegramAlert\"" ] - } + } ] }, "templates": null, @@ -1986,7 +2140,7 @@ var expAlertmanagerConfigFromAPI = ` } ] }, - { + { "name": "slack_recv1", "grafana_managed_receiver_configs": [ { @@ -2031,6 +2185,43 @@ var expAlertmanagerConfigFromAPI = ` } ] }, + { + "name": "slack_failed_recv", + "grafana_managed_receiver_configs": [ + { + "uid": "", + "name": "slack_failed_test", + "type": "slack", + "disableResolveMessage": false, + "settings": { + "recipient": "#test-channel", + "username": "test", + "text": "Integration Test" + }, + "secureFields": { + "url": true + } + } + ] + }, + { + "name": "slack_inactive_recv", + "grafana_managed_receiver_configs": [ + { + "uid": "", + "name": "inactive", + "type": "slack", + "disableResolveMessage": false, + "settings": { + "recipient": "#inactive-channel", + "username": "Integration Test" + }, + "secureFields": { + "token": true + } + } + ] + }, { "name": "pagerduty_recv", "grafana_managed_receiver_configs": [ @@ -2435,3 +2626,13 @@ var expNonEmailNotifications = map[string][]string{ ]`, }, } + +// expNotificationErrors maps a receiver name with its expected error string. +var expNotificationErrors = map[string]string{ + "slack_failed_recv": `Post "htt://127.0.0.1:8080/slack_failed_recv/slack_failed_test": unsupported protocol scheme "htt"`, +} + +// expNotificationErrors maps a receiver name with its expected error string. +var expInactiveReceivers = map[string]struct{}{ + "slack_inactive_recv": {}, +}