add groups endpoint to v2 api

Signed-off-by: stuart nelson <stuartnelson3@gmail.com>
This commit is contained in:
stuart nelson 2019-03-07 17:18:18 +01:00
parent eb09caeea9
commit 2fa210d0e3
20 changed files with 2006 additions and 67 deletions

View File

@ -24,6 +24,7 @@ import (
apiv2 "github.com/prometheus/alertmanager/api/v2"
"github.com/prometheus/alertmanager/cluster"
"github.com/prometheus/alertmanager/config"
"github.com/prometheus/alertmanager/dispatch"
"github.com/prometheus/alertmanager/provider"
"github.com/prometheus/alertmanager/silence"
"github.com/prometheus/alertmanager/types"
@ -69,6 +70,10 @@ type Options struct {
// Registry is used to register Prometheus metrics. If nil, no metrics
// registration will happen.
Registry prometheus.Registerer
// GroupFunc returns a list of alert groups. The alerts are grouped
// according to the current active configuration. Alerts returned are
// filtered by the arguments provided to the function.
GroupFunc func(func(*dispatch.Route) bool, func(*types.Alert, time.Time) bool) (dispatch.AlertGroups, map[model.Fingerprint][]string)
}
func (o Options) validate() error {
@ -81,6 +86,9 @@ func (o Options) validate() error {
if o.StatusFunc == nil {
return errors.New("mandatory field StatusFunc not set")
}
if o.GroupFunc == nil {
return errors.New("mandatory field GroupFunc not set")
}
return nil
}
@ -113,6 +121,7 @@ func New(opts Options) (*API, error) {
v2, err := apiv2.NewAPI(
opts.Alerts,
opts.GroupFunc,
opts.StatusFunc,
opts.Silences,
opts.Peer,

View File

@ -35,6 +35,7 @@ import (
"github.com/prometheus/alertmanager/api/v2/restapi"
"github.com/prometheus/alertmanager/api/v2/restapi/operations"
alert_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/alert"
alertgroup_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/alertgroup"
general_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/general"
receiver_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/receiver"
silence_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/silence"
@ -53,6 +54,7 @@ type API struct {
peer *cluster.Peer
silences *silence.Silences
alerts provider.Alerts
alertGroups groupsFn
getAlertStatus getAlertStatusFn
uptime time.Time
@ -69,12 +71,14 @@ type API struct {
Handler http.Handler
}
type groupsFn func(func(*dispatch.Route) bool, func(*types.Alert, time.Time) bool) (dispatch.AlertGroups, map[prometheus_model.Fingerprint][]string)
type getAlertStatusFn func(prometheus_model.Fingerprint) types.AlertStatus
type setAlertStatusFn func(prometheus_model.LabelSet)
// NewAPI returns a new Alertmanager API v2
func NewAPI(
alerts provider.Alerts,
gf groupsFn,
sf getAlertStatusFn,
silences *silence.Silences,
peer *cluster.Peer,
@ -83,6 +87,7 @@ func NewAPI(
api := API{
alerts: alerts,
getAlertStatus: sf,
alertGroups: gf,
peer: peer,
silences: silences,
logger: l,
@ -107,6 +112,7 @@ func NewAPI(
openAPI.AlertGetAlertsHandler = alert_ops.GetAlertsHandlerFunc(api.getAlertsHandler)
openAPI.AlertPostAlertsHandler = alert_ops.PostAlertsHandlerFunc(api.postAlertsHandler)
openAPI.AlertgroupGetAlertGroupsHandler = alertgroup_ops.GetAlertGroupsHandlerFunc(api.getAlertGroupsHandler)
openAPI.GeneralGetStatusHandler = general_ops.GetStatusHandlerFunc(api.getStatusHandler)
openAPI.ReceiverGetReceiversHandler = receiver_ops.GetReceiversHandlerFunc(api.getReceiversHandler)
openAPI.SilenceDeleteSilenceHandler = silence_ops.DeleteSilenceHandlerFunc(api.deleteSilenceHandler)
@ -224,6 +230,7 @@ func (api *API) getAlertsHandler(params alert_ops.GetAlertsParams) middleware.Re
if params.Receiver != nil {
receiverFilter, err = regexp.Compile("^(?:" + *params.Receiver + ")$")
if err != nil {
level.Error(api.logger).Log("msg", "failed to compile receiver regex", "err", err)
return alert_ops.
NewGetAlertsBadRequest().
WithPayload(
@ -235,6 +242,9 @@ func (api *API) getAlertsHandler(params alert_ops.GetAlertsParams) middleware.Re
alerts := api.alerts.GetPending()
defer alerts.Close()
alertFilter := api.alertFilter(matchers, *params.Silenced, *params.Inhibited, *params.Active)
now := time.Now()
api.mtx.RLock()
for a := range alerts.Next() {
if err = alerts.Err(); err != nil {
@ -245,79 +255,22 @@ func (api *API) getAlertsHandler(params alert_ops.GetAlertsParams) middleware.Re
}
routes := api.route.Match(a.Labels)
receivers := make([]*open_api_models.Receiver, 0, len(routes))
receivers := make([]string, 0, len(routes))
for _, r := range routes {
receivers = append(receivers, &open_api_models.Receiver{Name: &r.RouteOpts.Receiver})
receivers = append(receivers, r.RouteOpts.Receiver)
}
if receiverFilter != nil && !receiversMatchFilter(receivers, receiverFilter) {
continue
}
if !alertMatchesFilterLabels(&a.Alert, matchers) {
if !alertFilter(a, now) {
continue
}
// Continue if the alert is resolved.
if !a.Alert.EndsAt.IsZero() && a.Alert.EndsAt.Before(time.Now()) {
continue
}
alert := alertToOpenAPIAlert(a, api.getAlertStatus(a.Fingerprint()), receivers)
// Set alert's current status based on its label set.
api.setAlertStatus(a.Labels)
// Get alert's current status after seeing if it is suppressed.
status := api.getAlertStatus(a.Fingerprint())
if !*params.Active && status.State == types.AlertStateActive {
continue
}
if !*params.Unprocessed && status.State == types.AlertStateUnprocessed {
continue
}
if !*params.Silenced && len(status.SilencedBy) != 0 {
continue
}
if !*params.Inhibited && len(status.InhibitedBy) != 0 {
continue
}
state := string(status.State)
startsAt := strfmt.DateTime(a.StartsAt)
updatedAt := strfmt.DateTime(a.UpdatedAt)
endsAt := strfmt.DateTime(a.EndsAt)
fingerprint := a.Fingerprint().String()
alert := open_api_models.GettableAlert{
Alert: open_api_models.Alert{
GeneratorURL: strfmt.URI(a.GeneratorURL),
Labels: modelLabelSetToAPILabelSet(a.Labels),
},
Annotations: modelLabelSetToAPILabelSet(a.Annotations),
StartsAt: &startsAt,
UpdatedAt: &updatedAt,
EndsAt: &endsAt,
Fingerprint: &fingerprint,
Receivers: receivers,
Status: &open_api_models.AlertStatus{
State: &state,
SilencedBy: status.SilencedBy,
InhibitedBy: status.InhibitedBy,
},
}
if alert.Status.SilencedBy == nil {
alert.Status.SilencedBy = []string{}
}
if alert.Status.InhibitedBy == nil {
alert.Status.InhibitedBy = []string{}
}
res = append(res, &alert)
res = append(res, alert)
}
api.mtx.RUnlock()
@ -393,6 +346,139 @@ func (api *API) postAlertsHandler(params alert_ops.PostAlertsParams) middleware.
return alert_ops.NewPostAlertsOK()
}
func (api *API) getAlertGroupsHandler(params alertgroup_ops.GetAlertGroupsParams) middleware.Responder {
var (
err error
receiverFilter *regexp.Regexp
matchers = []*labels.Matcher{}
)
for _, matcherString := range params.Filter {
matcher, err := parse.Matcher(matcherString)
if err != nil {
level.Error(api.logger).Log("msg", "failed to parse matchers", "err", err)
return alertgroup_ops.NewGetAlertGroupsBadRequest().WithPayload(err.Error())
}
matchers = append(matchers, matcher)
}
if params.Receiver != nil {
receiverFilter, err = regexp.Compile("^(?:" + *params.Receiver + ")$")
if err != nil {
level.Error(api.logger).Log("msg", "failed to compile receiver regex", "err", err)
return alertgroup_ops.
NewGetAlertGroupsBadRequest().
WithPayload(
fmt.Sprintf("failed to parse receiver param: %v", err.Error()),
)
}
}
rf := func(receiverFilter *regexp.Regexp) func(r *dispatch.Route) bool {
return func(r *dispatch.Route) bool {
receiver := r.RouteOpts.Receiver
if receiverFilter != nil && !receiverFilter.MatchString(receiver) {
return false
}
return true
}
}(receiverFilter)
af := api.alertFilter(matchers, *params.Silenced, *params.Inhibited, *params.Active)
alertGroups, allReceivers := api.alertGroups(rf, af)
res := make(open_api_models.AlertGroups, 0, len(alertGroups))
for _, alertGroup := range alertGroups {
ag := &open_api_models.AlertGroup{
Receiver: &open_api_models.Receiver{Name: &alertGroup.Receiver},
Labels: modelLabelSetToAPILabelSet(alertGroup.Labels),
Alerts: make([]*open_api_models.GettableAlert, 0, len(alertGroup.Alerts)),
}
for _, alert := range alertGroup.Alerts {
fp := alert.Fingerprint()
receivers := allReceivers[fp]
status := api.getAlertStatus(fp)
apiAlert := alertToOpenAPIAlert(alert, status, receivers)
ag.Alerts = append(ag.Alerts, apiAlert)
}
res = append(res, ag)
}
return alertgroup_ops.NewGetAlertGroupsOK().WithPayload(res)
}
func (api *API) alertFilter(matchers []*labels.Matcher, silenced, inhibited, active bool) func(a *types.Alert, now time.Time) bool {
return func(a *types.Alert, now time.Time) bool {
if !a.EndsAt.IsZero() && a.EndsAt.Before(now) {
return false
}
// Set alert's current status based on its label set.
api.setAlertStatus(a.Labels)
// Get alert's current status after seeing if it is suppressed.
status := api.getAlertStatus(a.Fingerprint())
if !active && status.State == types.AlertStateActive {
return false
}
if !silenced && len(status.SilencedBy) != 0 {
return false
}
if !inhibited && len(status.InhibitedBy) != 0 {
return false
}
return alertMatchesFilterLabels(&a.Alert, matchers)
}
}
func alertToOpenAPIAlert(alert *types.Alert, status types.AlertStatus, receivers []string) *open_api_models.GettableAlert {
startsAt := strfmt.DateTime(alert.StartsAt)
updatedAt := strfmt.DateTime(alert.UpdatedAt)
endsAt := strfmt.DateTime(alert.EndsAt)
apiReceivers := make([]*open_api_models.Receiver, 0, len(receivers))
for _, name := range receivers {
apiReceivers = append(apiReceivers, &open_api_models.Receiver{Name: &name})
}
fp := alert.Fingerprint().String()
state := string(status.State)
aa := &open_api_models.GettableAlert{
Alert: open_api_models.Alert{
GeneratorURL: strfmt.URI(alert.GeneratorURL),
Labels: modelLabelSetToAPILabelSet(alert.Labels),
},
Annotations: modelLabelSetToAPILabelSet(alert.Annotations),
StartsAt: &startsAt,
UpdatedAt: &updatedAt,
EndsAt: &endsAt,
Fingerprint: &fp,
Receivers: apiReceivers,
Status: &open_api_models.AlertStatus{
State: &state,
SilencedBy: status.SilencedBy,
InhibitedBy: status.InhibitedBy,
},
}
if aa.Status.SilencedBy == nil {
aa.Status.SilencedBy = []string{}
}
if aa.Status.InhibitedBy == nil {
aa.Status.InhibitedBy = []string{}
}
return aa
}
func openAPIAlertsToAlerts(apiAlerts open_api_models.PostableAlerts) []*types.Alert {
alerts := []*types.Alert{}
for _, apiAlert := range apiAlerts {
@ -437,9 +523,9 @@ func apiLabelSetToModelLabelSet(apiLabelSet open_api_models.LabelSet) prometheus
return modelLabelSet
}
func receiversMatchFilter(receivers []*open_api_models.Receiver, filter *regexp.Regexp) bool {
func receiversMatchFilter(receivers []string, filter *regexp.Regexp) bool {
for _, r := range receivers {
if filter.MatchString(string(*r.Name)) {
if filter.MatchString(r) {
return true
}
}
@ -564,6 +650,8 @@ func gettableSilenceMatchesFilterLabels(s open_api_models.GettableSilence, match
return matchFilterLabels(matchers, sms)
}
// func matchesFilterLabels(labels model.LabelSet, matchers []*labels.Matcher) bool {
func (api *API) getSilenceHandler(params silence_ops.GetSilenceParams) middleware.Responder {
sils, _, err := api.silences.Query(silence.QIDs(params.SilenceID.String()))
if err != nil {

View File

@ -0,0 +1,72 @@
// Code generated by go-swagger; DO NOT EDIT.
// Copyright Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package alertgroup
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/runtime"
strfmt "github.com/go-openapi/strfmt"
)
// New creates a new alertgroup API client.
func New(transport runtime.ClientTransport, formats strfmt.Registry) *Client {
return &Client{transport: transport, formats: formats}
}
/*
Client for alertgroup API
*/
type Client struct {
transport runtime.ClientTransport
formats strfmt.Registry
}
/*
GetAlertGroups Get a list of alert groups
*/
func (a *Client) GetAlertGroups(params *GetAlertGroupsParams) (*GetAlertGroupsOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewGetAlertGroupsParams()
}
result, err := a.transport.Submit(&runtime.ClientOperation{
ID: "getAlertGroups",
Method: "GET",
PathPattern: "/alerts/groups",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http"},
Params: params,
Reader: &GetAlertGroupsReader{formats: a.formats},
Context: params.Context,
Client: params.HTTPClient,
})
if err != nil {
return nil, err
}
return result.(*GetAlertGroupsOK), nil
}
// SetTransport changes the transport on the client
func (a *Client) SetTransport(transport runtime.ClientTransport) {
a.transport = transport
}

View File

@ -0,0 +1,310 @@
// Code generated by go-swagger; DO NOT EDIT.
// Copyright Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package alertgroup
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/swag"
strfmt "github.com/go-openapi/strfmt"
)
// NewGetAlertGroupsParams creates a new GetAlertGroupsParams object
// with the default values initialized.
func NewGetAlertGroupsParams() *GetAlertGroupsParams {
var (
activeDefault = bool(true)
inhibitedDefault = bool(true)
silencedDefault = bool(true)
)
return &GetAlertGroupsParams{
Active: &activeDefault,
Inhibited: &inhibitedDefault,
Silenced: &silencedDefault,
timeout: cr.DefaultTimeout,
}
}
// NewGetAlertGroupsParamsWithTimeout creates a new GetAlertGroupsParams object
// with the default values initialized, and the ability to set a timeout on a request
func NewGetAlertGroupsParamsWithTimeout(timeout time.Duration) *GetAlertGroupsParams {
var (
activeDefault = bool(true)
inhibitedDefault = bool(true)
silencedDefault = bool(true)
)
return &GetAlertGroupsParams{
Active: &activeDefault,
Inhibited: &inhibitedDefault,
Silenced: &silencedDefault,
timeout: timeout,
}
}
// NewGetAlertGroupsParamsWithContext creates a new GetAlertGroupsParams object
// with the default values initialized, and the ability to set a context for a request
func NewGetAlertGroupsParamsWithContext(ctx context.Context) *GetAlertGroupsParams {
var (
activeDefault = bool(true)
inhibitedDefault = bool(true)
silencedDefault = bool(true)
)
return &GetAlertGroupsParams{
Active: &activeDefault,
Inhibited: &inhibitedDefault,
Silenced: &silencedDefault,
Context: ctx,
}
}
// NewGetAlertGroupsParamsWithHTTPClient creates a new GetAlertGroupsParams object
// with the default values initialized, and the ability to set a custom HTTPClient for a request
func NewGetAlertGroupsParamsWithHTTPClient(client *http.Client) *GetAlertGroupsParams {
var (
activeDefault = bool(true)
inhibitedDefault = bool(true)
silencedDefault = bool(true)
)
return &GetAlertGroupsParams{
Active: &activeDefault,
Inhibited: &inhibitedDefault,
Silenced: &silencedDefault,
HTTPClient: client,
}
}
/*GetAlertGroupsParams contains all the parameters to send to the API endpoint
for the get alert groups operation typically these are written to a http.Request
*/
type GetAlertGroupsParams struct {
/*Active
Show active alerts
*/
Active *bool
/*Filter
A list of matchers to filter alerts by
*/
Filter []string
/*Inhibited
Show inhibited alerts
*/
Inhibited *bool
/*Receiver
A regex matching receivers to filter alerts by
*/
Receiver *string
/*Silenced
Show silenced alerts
*/
Silenced *bool
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithTimeout adds the timeout to the get alert groups params
func (o *GetAlertGroupsParams) WithTimeout(timeout time.Duration) *GetAlertGroupsParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the get alert groups params
func (o *GetAlertGroupsParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the get alert groups params
func (o *GetAlertGroupsParams) WithContext(ctx context.Context) *GetAlertGroupsParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the get alert groups params
func (o *GetAlertGroupsParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the get alert groups params
func (o *GetAlertGroupsParams) WithHTTPClient(client *http.Client) *GetAlertGroupsParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the get alert groups params
func (o *GetAlertGroupsParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithActive adds the active to the get alert groups params
func (o *GetAlertGroupsParams) WithActive(active *bool) *GetAlertGroupsParams {
o.SetActive(active)
return o
}
// SetActive adds the active to the get alert groups params
func (o *GetAlertGroupsParams) SetActive(active *bool) {
o.Active = active
}
// WithFilter adds the filter to the get alert groups params
func (o *GetAlertGroupsParams) WithFilter(filter []string) *GetAlertGroupsParams {
o.SetFilter(filter)
return o
}
// SetFilter adds the filter to the get alert groups params
func (o *GetAlertGroupsParams) SetFilter(filter []string) {
o.Filter = filter
}
// WithInhibited adds the inhibited to the get alert groups params
func (o *GetAlertGroupsParams) WithInhibited(inhibited *bool) *GetAlertGroupsParams {
o.SetInhibited(inhibited)
return o
}
// SetInhibited adds the inhibited to the get alert groups params
func (o *GetAlertGroupsParams) SetInhibited(inhibited *bool) {
o.Inhibited = inhibited
}
// WithReceiver adds the receiver to the get alert groups params
func (o *GetAlertGroupsParams) WithReceiver(receiver *string) *GetAlertGroupsParams {
o.SetReceiver(receiver)
return o
}
// SetReceiver adds the receiver to the get alert groups params
func (o *GetAlertGroupsParams) SetReceiver(receiver *string) {
o.Receiver = receiver
}
// WithSilenced adds the silenced to the get alert groups params
func (o *GetAlertGroupsParams) WithSilenced(silenced *bool) *GetAlertGroupsParams {
o.SetSilenced(silenced)
return o
}
// SetSilenced adds the silenced to the get alert groups params
func (o *GetAlertGroupsParams) SetSilenced(silenced *bool) {
o.Silenced = silenced
}
// WriteToRequest writes these params to a swagger request
func (o *GetAlertGroupsParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if o.Active != nil {
// query param active
var qrActive bool
if o.Active != nil {
qrActive = *o.Active
}
qActive := swag.FormatBool(qrActive)
if qActive != "" {
if err := r.SetQueryParam("active", qActive); err != nil {
return err
}
}
}
valuesFilter := o.Filter
joinedFilter := swag.JoinByFormat(valuesFilter, "multi")
// query array param filter
if err := r.SetQueryParam("filter", joinedFilter...); err != nil {
return err
}
if o.Inhibited != nil {
// query param inhibited
var qrInhibited bool
if o.Inhibited != nil {
qrInhibited = *o.Inhibited
}
qInhibited := swag.FormatBool(qrInhibited)
if qInhibited != "" {
if err := r.SetQueryParam("inhibited", qInhibited); err != nil {
return err
}
}
}
if o.Receiver != nil {
// query param receiver
var qrReceiver string
if o.Receiver != nil {
qrReceiver = *o.Receiver
}
qReceiver := qrReceiver
if qReceiver != "" {
if err := r.SetQueryParam("receiver", qReceiver); err != nil {
return err
}
}
}
if o.Silenced != nil {
// query param silenced
var qrSilenced bool
if o.Silenced != nil {
qrSilenced = *o.Silenced
}
qSilenced := swag.FormatBool(qrSilenced)
if qSilenced != "" {
if err := r.SetQueryParam("silenced", qSilenced); err != nil {
return err
}
}
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@ -0,0 +1,147 @@
// Code generated by go-swagger; DO NOT EDIT.
// Copyright Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package alertgroup
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"fmt"
"io"
"github.com/go-openapi/runtime"
strfmt "github.com/go-openapi/strfmt"
models "github.com/prometheus/alertmanager/api/v2/models"
)
// GetAlertGroupsReader is a Reader for the GetAlertGroups structure.
type GetAlertGroupsReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *GetAlertGroupsReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewGetAlertGroupsOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 400:
result := NewGetAlertGroupsBadRequest()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 500:
result := NewGetAlertGroupsInternalServerError()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("unknown error", response, response.Code())
}
}
// NewGetAlertGroupsOK creates a GetAlertGroupsOK with default headers values
func NewGetAlertGroupsOK() *GetAlertGroupsOK {
return &GetAlertGroupsOK{}
}
/*GetAlertGroupsOK handles this case with default header values.
Get alert groups response
*/
type GetAlertGroupsOK struct {
Payload models.AlertGroups
}
func (o *GetAlertGroupsOK) Error() string {
return fmt.Sprintf("[GET /alerts/groups][%d] getAlertGroupsOK %+v", 200, o.Payload)
}
func (o *GetAlertGroupsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewGetAlertGroupsBadRequest creates a GetAlertGroupsBadRequest with default headers values
func NewGetAlertGroupsBadRequest() *GetAlertGroupsBadRequest {
return &GetAlertGroupsBadRequest{}
}
/*GetAlertGroupsBadRequest handles this case with default header values.
Bad request
*/
type GetAlertGroupsBadRequest struct {
Payload string
}
func (o *GetAlertGroupsBadRequest) Error() string {
return fmt.Sprintf("[GET /alerts/groups][%d] getAlertGroupsBadRequest %+v", 400, o.Payload)
}
func (o *GetAlertGroupsBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewGetAlertGroupsInternalServerError creates a GetAlertGroupsInternalServerError with default headers values
func NewGetAlertGroupsInternalServerError() *GetAlertGroupsInternalServerError {
return &GetAlertGroupsInternalServerError{}
}
/*GetAlertGroupsInternalServerError handles this case with default header values.
Internal server error
*/
type GetAlertGroupsInternalServerError struct {
Payload string
}
func (o *GetAlertGroupsInternalServerError) Error() string {
return fmt.Sprintf("[GET /alerts/groups][%d] getAlertGroupsInternalServerError %+v", 500, o.Payload)
}
func (o *GetAlertGroupsInternalServerError) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View File

@ -26,6 +26,7 @@ import (
strfmt "github.com/go-openapi/strfmt"
"github.com/prometheus/alertmanager/api/v2/client/alert"
"github.com/prometheus/alertmanager/api/v2/client/alertgroup"
"github.com/prometheus/alertmanager/api/v2/client/general"
"github.com/prometheus/alertmanager/api/v2/client/receiver"
"github.com/prometheus/alertmanager/api/v2/client/silence"
@ -76,6 +77,8 @@ func New(transport runtime.ClientTransport, formats strfmt.Registry) *Alertmanag
cli.Alert = alert.New(transport, formats)
cli.Alertgroup = alertgroup.New(transport, formats)
cli.General = general.New(transport, formats)
cli.Receiver = receiver.New(transport, formats)
@ -128,6 +131,8 @@ func (cfg *TransportConfig) WithSchemes(schemes []string) *TransportConfig {
type Alertmanager struct {
Alert *alert.Client
Alertgroup *alertgroup.Client
General *general.Client
Receiver *receiver.Client
@ -143,6 +148,8 @@ func (c *Alertmanager) SetTransport(transport runtime.ClientTransport) {
c.Alert.SetTransport(transport)
c.Alertgroup.SetTransport(transport)
c.General.SetTransport(transport)
c.Receiver.SetTransport(transport)

View File

@ -0,0 +1,142 @@
// Code generated by go-swagger; DO NOT EDIT.
// Copyright Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"strconv"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
)
// AlertGroup alert group
// swagger:model alertGroup
type AlertGroup struct {
// alerts
Alerts []*GettableAlert `json:"alerts"`
// labels
Labels LabelSet `json:"labels,omitempty"`
// receiver
Receiver *Receiver `json:"receiver,omitempty"`
}
// Validate validates this alert group
func (m *AlertGroup) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateAlerts(formats); err != nil {
res = append(res, err)
}
if err := m.validateLabels(formats); err != nil {
res = append(res, err)
}
if err := m.validateReceiver(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *AlertGroup) validateAlerts(formats strfmt.Registry) error {
if swag.IsZero(m.Alerts) { // not required
return nil
}
for i := 0; i < len(m.Alerts); i++ {
if swag.IsZero(m.Alerts[i]) { // not required
continue
}
if m.Alerts[i] != nil {
if err := m.Alerts[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("alerts" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *AlertGroup) validateLabels(formats strfmt.Registry) error {
if swag.IsZero(m.Labels) { // not required
return nil
}
if err := m.Labels.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("labels")
}
return err
}
return nil
}
func (m *AlertGroup) validateReceiver(formats strfmt.Registry) error {
if swag.IsZero(m.Receiver) { // not required
return nil
}
if m.Receiver != nil {
if err := m.Receiver.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("receiver")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *AlertGroup) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AlertGroup) UnmarshalBinary(b []byte) error {
var res AlertGroup
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -0,0 +1,59 @@
// Code generated by go-swagger; DO NOT EDIT.
// Copyright Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"strconv"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
)
// AlertGroups alert groups
// swagger:model alertGroups
type AlertGroups []*AlertGroup
// Validate validates this alert groups
func (m AlertGroups) Validate(formats strfmt.Registry) error {
var res []error
for i := 0; i < len(m); i++ {
if swag.IsZero(m[i]) { // not required
continue
}
if m[i] != nil {
if err := m[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName(strconv.Itoa(i))
}
return err
}
}
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@ -195,6 +195,50 @@ paths:
$ref: '#/responses/InternalServerError'
'400':
$ref: '#/responses/BadRequest'
/alerts/groups:
get:
tags:
- alertgroup
operationId: getAlertGroups
description: Get a list of alert groups
parameters:
- in: query
name: active
type: boolean
description: Show active alerts
default: true
- in: query
name: silenced
type: boolean
description: Show silenced alerts
default: true
- in: query
name: inhibited
type: boolean
description: Show inhibited alerts
default: true
- name: filter
in: query
description: A list of matchers to filter alerts by
required: false
type: array
collectionFormat: multi
items:
type: string
- name: receiver
in: query
description: A regex matching receivers to filter alerts by
required: false
type: string
responses:
'200':
description: Get alert groups response
schema:
'$ref': '#/definitions/alertGroups'
'400':
$ref: '#/responses/BadRequest'
'500':
$ref: '#/responses/InternalServerError'
responses:
BadRequest:
@ -416,6 +460,21 @@ definitions:
annotations:
$ref: '#/definitions/labelSet'
- $ref: '#/definitions/alert'
alertGroups:
type: array
items:
$ref: '#/definitions/alertGroup'
alertGroup:
type: object
properties:
labels:
$ref: '#/definitions/labelSet'
receiver:
$ref: '#/definitions/receiver'
alerts:
type: array
items:
$ref: '#/definitions/gettableAlert'
alertStatus:
type: object
properties:

View File

@ -26,6 +26,7 @@ import (
"github.com/prometheus/alertmanager/api/v2/restapi/operations"
"github.com/prometheus/alertmanager/api/v2/restapi/operations/alert"
"github.com/prometheus/alertmanager/api/v2/restapi/operations/alertgroup"
"github.com/prometheus/alertmanager/api/v2/restapi/operations/general"
"github.com/prometheus/alertmanager/api/v2/restapi/operations/receiver"
"github.com/prometheus/alertmanager/api/v2/restapi/operations/silence"
@ -54,6 +55,9 @@ func configureAPI(api *operations.AlertmanagerAPI) http.Handler {
api.SilenceDeleteSilenceHandler = silence.DeleteSilenceHandlerFunc(func(params silence.DeleteSilenceParams) middleware.Responder {
return middleware.NotImplemented("operation silence.DeleteSilence has not yet been implemented")
})
api.AlertgroupGetAlertGroupsHandler = alertgroup.GetAlertGroupsHandlerFunc(func(params alertgroup.GetAlertGroupsParams) middleware.Responder {
return middleware.NotImplemented("operation alertgroup.GetAlertGroups has not yet been implemented")
})
api.AlertGetAlertsHandler = alert.GetAlertsHandlerFunc(func(params alert.GetAlertsParams) middleware.Responder {
return middleware.NotImplemented("operation alert.GetAlerts has not yet been implemented")
})

View File

@ -147,6 +147,68 @@ func init() {
}
}
},
"/alerts/groups": {
"get": {
"description": "Get a list of alert groups",
"tags": [
"alertgroup"
],
"operationId": "getAlertGroups",
"parameters": [
{
"type": "boolean",
"default": true,
"description": "Show active alerts",
"name": "active",
"in": "query"
},
{
"type": "boolean",
"default": true,
"description": "Show silenced alerts",
"name": "silenced",
"in": "query"
},
{
"type": "boolean",
"default": true,
"description": "Show inhibited alerts",
"name": "inhibited",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "A list of matchers to filter alerts by",
"name": "filter",
"in": "query"
},
{
"type": "string",
"description": "A regex matching receivers to filter alerts by",
"name": "receiver",
"in": "query"
}
],
"responses": {
"200": {
"description": "Get alert groups response",
"schema": {
"$ref": "#/definitions/alertGroups"
}
},
"400": {
"$ref": "#/responses/BadRequest"
},
"500": {
"$ref": "#/responses/InternalServerError"
}
}
}
},
"/receivers": {
"get": {
"description": "Get list of all receivers (name of notification integrations)",
@ -331,6 +393,29 @@ func init() {
}
}
},
"alertGroup": {
"type": "object",
"properties": {
"alerts": {
"type": "array",
"items": {
"$ref": "#/definitions/gettableAlert"
}
},
"labels": {
"$ref": "#/definitions/labelSet"
},
"receiver": {
"$ref": "#/definitions/receiver"
}
}
},
"alertGroups": {
"type": "array",
"items": {
"$ref": "#/definitions/alertGroup"
}
},
"alertStatus": {
"type": "object",
"required": [
@ -848,6 +933,74 @@ func init() {
}
}
},
"/alerts/groups": {
"get": {
"description": "Get a list of alert groups",
"tags": [
"alertgroup"
],
"operationId": "getAlertGroups",
"parameters": [
{
"type": "boolean",
"default": true,
"description": "Show active alerts",
"name": "active",
"in": "query"
},
{
"type": "boolean",
"default": true,
"description": "Show silenced alerts",
"name": "silenced",
"in": "query"
},
{
"type": "boolean",
"default": true,
"description": "Show inhibited alerts",
"name": "inhibited",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "A list of matchers to filter alerts by",
"name": "filter",
"in": "query"
},
{
"type": "string",
"description": "A regex matching receivers to filter alerts by",
"name": "receiver",
"in": "query"
}
],
"responses": {
"200": {
"description": "Get alert groups response",
"schema": {
"$ref": "#/definitions/alertGroups"
}
},
"400": {
"description": "Bad request",
"schema": {
"type": "string"
}
},
"500": {
"description": "Internal server error",
"schema": {
"type": "string"
}
}
}
}
},
"/receivers": {
"get": {
"description": "Get list of all receivers (name of notification integrations)",
@ -1044,6 +1197,29 @@ func init() {
}
}
},
"alertGroup": {
"type": "object",
"properties": {
"alerts": {
"type": "array",
"items": {
"$ref": "#/definitions/gettableAlert"
}
},
"labels": {
"$ref": "#/definitions/labelSet"
},
"receiver": {
"$ref": "#/definitions/receiver"
}
}
},
"alertGroups": {
"type": "array",
"items": {
"$ref": "#/definitions/alertGroup"
}
},
"alertStatus": {
"type": "object",
"required": [

View File

@ -0,0 +1,72 @@
// Code generated by go-swagger; DO NOT EDIT.
// Copyright Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package alertgroup
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
middleware "github.com/go-openapi/runtime/middleware"
)
// GetAlertGroupsHandlerFunc turns a function with the right signature into a get alert groups handler
type GetAlertGroupsHandlerFunc func(GetAlertGroupsParams) middleware.Responder
// Handle executing the request and returning a response
func (fn GetAlertGroupsHandlerFunc) Handle(params GetAlertGroupsParams) middleware.Responder {
return fn(params)
}
// GetAlertGroupsHandler interface for that can handle valid get alert groups params
type GetAlertGroupsHandler interface {
Handle(GetAlertGroupsParams) middleware.Responder
}
// NewGetAlertGroups creates a new http.Handler for the get alert groups operation
func NewGetAlertGroups(ctx *middleware.Context, handler GetAlertGroupsHandler) *GetAlertGroups {
return &GetAlertGroups{Context: ctx, Handler: handler}
}
/*GetAlertGroups swagger:route GET /alerts/groups alertgroup getAlertGroups
Get a list of alert groups
*/
type GetAlertGroups struct {
Context *middleware.Context
Handler GetAlertGroupsHandler
}
func (o *GetAlertGroups) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
r = rCtx
}
var Params = NewGetAlertGroupsParams()
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@ -0,0 +1,242 @@
// Code generated by go-swagger; DO NOT EDIT.
// Copyright Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package alertgroup
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/swag"
strfmt "github.com/go-openapi/strfmt"
)
// NewGetAlertGroupsParams creates a new GetAlertGroupsParams object
// with the default values initialized.
func NewGetAlertGroupsParams() GetAlertGroupsParams {
var (
// initialize parameters with default values
activeDefault = bool(true)
inhibitedDefault = bool(true)
silencedDefault = bool(true)
)
return GetAlertGroupsParams{
Active: &activeDefault,
Inhibited: &inhibitedDefault,
Silenced: &silencedDefault,
}
}
// GetAlertGroupsParams contains all the bound params for the get alert groups operation
// typically these are obtained from a http.Request
//
// swagger:parameters getAlertGroups
type GetAlertGroupsParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*Show active alerts
In: query
Default: true
*/
Active *bool
/*A list of matchers to filter alerts by
In: query
Collection Format: multi
*/
Filter []string
/*Show inhibited alerts
In: query
Default: true
*/
Inhibited *bool
/*A regex matching receivers to filter alerts by
In: query
*/
Receiver *string
/*Show silenced alerts
In: query
Default: true
*/
Silenced *bool
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewGetAlertGroupsParams() beforehand.
func (o *GetAlertGroupsParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
qs := runtime.Values(r.URL.Query())
qActive, qhkActive, _ := qs.GetOK("active")
if err := o.bindActive(qActive, qhkActive, route.Formats); err != nil {
res = append(res, err)
}
qFilter, qhkFilter, _ := qs.GetOK("filter")
if err := o.bindFilter(qFilter, qhkFilter, route.Formats); err != nil {
res = append(res, err)
}
qInhibited, qhkInhibited, _ := qs.GetOK("inhibited")
if err := o.bindInhibited(qInhibited, qhkInhibited, route.Formats); err != nil {
res = append(res, err)
}
qReceiver, qhkReceiver, _ := qs.GetOK("receiver")
if err := o.bindReceiver(qReceiver, qhkReceiver, route.Formats); err != nil {
res = append(res, err)
}
qSilenced, qhkSilenced, _ := qs.GetOK("silenced")
if err := o.bindSilenced(qSilenced, qhkSilenced, route.Formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// bindActive binds and validates parameter Active from query.
func (o *GetAlertGroupsParams) bindActive(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: false
// AllowEmptyValue: false
if raw == "" { // empty values pass all other validations
// Default values have been previously initialized by NewGetAlertGroupsParams()
return nil
}
value, err := swag.ConvertBool(raw)
if err != nil {
return errors.InvalidType("active", "query", "bool", raw)
}
o.Active = &value
return nil
}
// bindFilter binds and validates array parameter Filter from query.
//
// Arrays are parsed according to CollectionFormat: "multi" (defaults to "csv" when empty).
func (o *GetAlertGroupsParams) bindFilter(rawData []string, hasKey bool, formats strfmt.Registry) error {
// CollectionFormat: multi
filterIC := rawData
if len(filterIC) == 0 {
return nil
}
var filterIR []string
for _, filterIV := range filterIC {
filterI := filterIV
filterIR = append(filterIR, filterI)
}
o.Filter = filterIR
return nil
}
// bindInhibited binds and validates parameter Inhibited from query.
func (o *GetAlertGroupsParams) bindInhibited(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: false
// AllowEmptyValue: false
if raw == "" { // empty values pass all other validations
// Default values have been previously initialized by NewGetAlertGroupsParams()
return nil
}
value, err := swag.ConvertBool(raw)
if err != nil {
return errors.InvalidType("inhibited", "query", "bool", raw)
}
o.Inhibited = &value
return nil
}
// bindReceiver binds and validates parameter Receiver from query.
func (o *GetAlertGroupsParams) bindReceiver(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: false
// AllowEmptyValue: false
if raw == "" { // empty values pass all other validations
return nil
}
o.Receiver = &raw
return nil
}
// bindSilenced binds and validates parameter Silenced from query.
func (o *GetAlertGroupsParams) bindSilenced(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: false
// AllowEmptyValue: false
if raw == "" { // empty values pass all other validations
// Default values have been previously initialized by NewGetAlertGroupsParams()
return nil
}
value, err := swag.ConvertBool(raw)
if err != nil {
return errors.InvalidType("silenced", "query", "bool", raw)
}
o.Silenced = &value
return nil
}

View File

@ -0,0 +1,161 @@
// Code generated by go-swagger; DO NOT EDIT.
// Copyright Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package alertgroup
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
models "github.com/prometheus/alertmanager/api/v2/models"
)
// GetAlertGroupsOKCode is the HTTP code returned for type GetAlertGroupsOK
const GetAlertGroupsOKCode int = 200
/*GetAlertGroupsOK Get alert groups response
swagger:response getAlertGroupsOK
*/
type GetAlertGroupsOK struct {
/*
In: Body
*/
Payload models.AlertGroups `json:"body,omitempty"`
}
// NewGetAlertGroupsOK creates GetAlertGroupsOK with default headers values
func NewGetAlertGroupsOK() *GetAlertGroupsOK {
return &GetAlertGroupsOK{}
}
// WithPayload adds the payload to the get alert groups o k response
func (o *GetAlertGroupsOK) WithPayload(payload models.AlertGroups) *GetAlertGroupsOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the get alert groups o k response
func (o *GetAlertGroupsOK) SetPayload(payload models.AlertGroups) {
o.Payload = payload
}
// WriteResponse to the client
func (o *GetAlertGroupsOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(200)
payload := o.Payload
if payload == nil {
payload = make(models.AlertGroups, 0, 50)
}
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
// GetAlertGroupsBadRequestCode is the HTTP code returned for type GetAlertGroupsBadRequest
const GetAlertGroupsBadRequestCode int = 400
/*GetAlertGroupsBadRequest Bad request
swagger:response getAlertGroupsBadRequest
*/
type GetAlertGroupsBadRequest struct {
/*
In: Body
*/
Payload string `json:"body,omitempty"`
}
// NewGetAlertGroupsBadRequest creates GetAlertGroupsBadRequest with default headers values
func NewGetAlertGroupsBadRequest() *GetAlertGroupsBadRequest {
return &GetAlertGroupsBadRequest{}
}
// WithPayload adds the payload to the get alert groups bad request response
func (o *GetAlertGroupsBadRequest) WithPayload(payload string) *GetAlertGroupsBadRequest {
o.Payload = payload
return o
}
// SetPayload sets the payload to the get alert groups bad request response
func (o *GetAlertGroupsBadRequest) SetPayload(payload string) {
o.Payload = payload
}
// WriteResponse to the client
func (o *GetAlertGroupsBadRequest) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(400)
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
// GetAlertGroupsInternalServerErrorCode is the HTTP code returned for type GetAlertGroupsInternalServerError
const GetAlertGroupsInternalServerErrorCode int = 500
/*GetAlertGroupsInternalServerError Internal server error
swagger:response getAlertGroupsInternalServerError
*/
type GetAlertGroupsInternalServerError struct {
/*
In: Body
*/
Payload string `json:"body,omitempty"`
}
// NewGetAlertGroupsInternalServerError creates GetAlertGroupsInternalServerError with default headers values
func NewGetAlertGroupsInternalServerError() *GetAlertGroupsInternalServerError {
return &GetAlertGroupsInternalServerError{}
}
// WithPayload adds the payload to the get alert groups internal server error response
func (o *GetAlertGroupsInternalServerError) WithPayload(payload string) *GetAlertGroupsInternalServerError {
o.Payload = payload
return o
}
// SetPayload sets the payload to the get alert groups internal server error response
func (o *GetAlertGroupsInternalServerError) SetPayload(payload string) {
o.Payload = payload
}
// WriteResponse to the client
func (o *GetAlertGroupsInternalServerError) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(500)
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}

View File

@ -0,0 +1,158 @@
// Code generated by go-swagger; DO NOT EDIT.
// Copyright Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package alertgroup
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
"github.com/go-openapi/swag"
)
// GetAlertGroupsURL generates an URL for the get alert groups operation
type GetAlertGroupsURL struct {
Active *bool
Filter []string
Inhibited *bool
Receiver *string
Silenced *bool
_basePath string
// avoid unkeyed usage
_ struct{}
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *GetAlertGroupsURL) WithBasePath(bp string) *GetAlertGroupsURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *GetAlertGroupsURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *GetAlertGroupsURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/alerts/groups"
_basePath := o._basePath
_result.Path = golangswaggerpaths.Join(_basePath, _path)
qs := make(url.Values)
var active string
if o.Active != nil {
active = swag.FormatBool(*o.Active)
}
if active != "" {
qs.Set("active", active)
}
var filterIR []string
for _, filterI := range o.Filter {
filterIS := filterI
if filterIS != "" {
filterIR = append(filterIR, filterIS)
}
}
filter := swag.JoinByFormat(filterIR, "multi")
for _, qsv := range filter {
qs.Add("filter", qsv)
}
var inhibited string
if o.Inhibited != nil {
inhibited = swag.FormatBool(*o.Inhibited)
}
if inhibited != "" {
qs.Set("inhibited", inhibited)
}
var receiver string
if o.Receiver != nil {
receiver = *o.Receiver
}
if receiver != "" {
qs.Set("receiver", receiver)
}
var silenced string
if o.Silenced != nil {
silenced = swag.FormatBool(*o.Silenced)
}
if silenced != "" {
qs.Set("silenced", silenced)
}
_result.RawQuery = qs.Encode()
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *GetAlertGroupsURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *GetAlertGroupsURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *GetAlertGroupsURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on GetAlertGroupsURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on GetAlertGroupsURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *GetAlertGroupsURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@ -34,6 +34,7 @@ import (
"github.com/go-openapi/swag"
"github.com/prometheus/alertmanager/api/v2/restapi/operations/alert"
"github.com/prometheus/alertmanager/api/v2/restapi/operations/alertgroup"
"github.com/prometheus/alertmanager/api/v2/restapi/operations/general"
"github.com/prometheus/alertmanager/api/v2/restapi/operations/receiver"
"github.com/prometheus/alertmanager/api/v2/restapi/operations/silence"
@ -59,6 +60,9 @@ func NewAlertmanagerAPI(spec *loads.Document) *AlertmanagerAPI {
SilenceDeleteSilenceHandler: silence.DeleteSilenceHandlerFunc(func(params silence.DeleteSilenceParams) middleware.Responder {
return middleware.NotImplemented("operation SilenceDeleteSilence has not yet been implemented")
}),
AlertgroupGetAlertGroupsHandler: alertgroup.GetAlertGroupsHandlerFunc(func(params alertgroup.GetAlertGroupsParams) middleware.Responder {
return middleware.NotImplemented("operation AlertgroupGetAlertGroups has not yet been implemented")
}),
AlertGetAlertsHandler: alert.GetAlertsHandlerFunc(func(params alert.GetAlertsParams) middleware.Responder {
return middleware.NotImplemented("operation AlertGetAlerts has not yet been implemented")
}),
@ -113,6 +117,8 @@ type AlertmanagerAPI struct {
// SilenceDeleteSilenceHandler sets the operation handler for the delete silence operation
SilenceDeleteSilenceHandler silence.DeleteSilenceHandler
// AlertgroupGetAlertGroupsHandler sets the operation handler for the get alert groups operation
AlertgroupGetAlertGroupsHandler alertgroup.GetAlertGroupsHandler
// AlertGetAlertsHandler sets the operation handler for the get alerts operation
AlertGetAlertsHandler alert.GetAlertsHandler
// ReceiverGetReceiversHandler sets the operation handler for the get receivers operation
@ -194,6 +200,10 @@ func (o *AlertmanagerAPI) Validate() error {
unregistered = append(unregistered, "silence.DeleteSilenceHandler")
}
if o.AlertgroupGetAlertGroupsHandler == nil {
unregistered = append(unregistered, "alertgroup.GetAlertGroupsHandler")
}
if o.AlertGetAlertsHandler == nil {
unregistered = append(unregistered, "alert.GetAlertsHandler")
}
@ -325,6 +335,11 @@ func (o *AlertmanagerAPI) initHandlerCache() {
}
o.handlers["DELETE"]["/silence/{silenceID}"] = silence.NewDeleteSilence(o.context, o.SilenceDeleteSilenceHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/alerts/groups"] = alertgroup.NewGetAlertGroups(o.context, o.AlertgroupGetAlertGroupsHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}

View File

@ -246,6 +246,13 @@ func run() int {
}
defer alerts.Close()
var disp *dispatch.Dispatcher
defer disp.Stop()
groupFn := func(routeFilter func(*dispatch.Route) bool, alertFilter func(*types.Alert, time.Time) bool) (dispatch.AlertGroups, map[model.Fingerprint][]string) {
return disp.Groups(routeFilter, alertFilter)
}
api, err := api.New(api.Options{
Alerts: alerts,
Silences: silences,
@ -255,6 +262,7 @@ func run() int {
Concurrency: *getConcurrency,
Logger: log.With(logger, "component", "api"),
Registry: prometheus.DefaultRegisterer,
GroupFunc: groupFn,
})
if err != nil {
@ -284,11 +292,8 @@ func run() int {
silencer *silence.Silencer
tmpl *template.Template
pipeline notify.Stage
disp *dispatch.Dispatcher
)
defer disp.Stop()
configCoordinator := config.NewCoordinator(
*configFile,
prometheus.DefaultRegisterer,

View File

@ -133,6 +133,86 @@ func (d *Dispatcher) run(it provider.AlertIterator) {
}
}
// AlertGroup represents how alerts exist within an aggrGroup.
type AlertGroup struct {
Alerts []*types.Alert
Labels model.LabelSet
Receiver string
}
type AlertGroups []*AlertGroup
func (ag AlertGroups) Swap(i, j int) { ag[i], ag[j] = ag[j], ag[i] }
func (ag AlertGroups) Less(i, j int) bool { return ag[i].Labels.Before(ag[j].Labels) }
func (ag AlertGroups) Len() int { return len(ag) }
// Groups returns a slice of AlertGroups from the dispatcher's internal state.
func (d *Dispatcher) Groups(routeFilter func(*Route) bool, alertFilter func(*types.Alert, time.Time) bool) (AlertGroups, map[model.Fingerprint][]string) {
groups := AlertGroups{}
d.mtx.RLock()
defer d.mtx.RUnlock()
seen := map[model.Fingerprint]*AlertGroup{}
// Keep a list of receivers for an alert to prevent checking each alert
// again against all routes. The alert has already matched against this
// route on ingestion.
receivers := map[model.Fingerprint][]string{}
for route, ags := range d.aggrGroups {
if !routeFilter(route) {
continue
}
for _, ag := range ags {
receiver := route.RouteOpts.Receiver
alertGroup, ok := seen[ag.fingerprint()]
if !ok {
alertGroup = &AlertGroup{
Labels: ag.labels,
Receiver: receiver,
}
seen[ag.fingerprint()] = alertGroup
}
now := time.Now()
alerts := ag.alerts.List()
filteredAlerts := make([]*types.Alert, 0, len(alerts))
for a := range alerts {
if !alertFilter(a, now) {
continue
}
fp := a.Fingerprint()
if r, ok := receivers[fp]; ok {
// Receivers slice already exists. Add
// the current receiver to the slice.
receivers[fp] = append(r, receiver)
} else {
// First time we've seen this alert fingerprint.
// Initialize a new receivers slice.
receivers[fp] = []string{receiver}
}
filteredAlerts = append(filteredAlerts, a)
}
if len(filteredAlerts) == 0 {
continue
}
alertGroup.Alerts = filteredAlerts
groups = append(groups, alertGroup)
}
}
sort.Sort(groups)
return groups, receivers
}
// Stop the dispatcher.
func (d *Dispatcher) Stop() {
if d == nil || d.cancel == nil {

View File

@ -22,9 +22,13 @@ import (
"time"
"github.com/go-kit/kit/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/model"
"github.com/stretchr/testify/require"
"github.com/prometheus/alertmanager/config"
"github.com/prometheus/alertmanager/notify"
"github.com/prometheus/alertmanager/provider/mem"
"github.com/prometheus/alertmanager/types"
)
@ -323,3 +327,98 @@ func TestGroupByAllLabels(t *testing.T) {
t.Fatalf("expected labels are %v, but got %v", expLs, ls)
}
}
func TestGroups(t *testing.T) {
logger := log.NewNopLogger()
conf, _, err := config.LoadFile("testdata/conf.yml")
if err != nil {
t.Fatal(err)
}
route := NewRoute(conf.Route, nil)
marker := types.NewMarker(prometheus.DefaultRegisterer)
alerts, err := mem.NewAlerts(context.Background(), marker, time.Hour, logger)
if err != nil {
t.Fatal(err)
}
defer alerts.Close()
timeout := func(d time.Duration) time.Duration { return time.Duration(0) }
dispatcher := NewDispatcher(alerts, route, &noopStage{}, marker, timeout, logger)
go dispatcher.Run()
// create alerts. the dispatcher will automatically create the groups
alerts.Put(
newAlert(model.LabelSet{"env": "testing", "alertname": "TestingAlert", "service": "api"}),
newAlert(model.LabelSet{"env": "prod", "alertname": "HighErrorRate", "cluster": "aa", "service": "api"}),
newAlert(model.LabelSet{"env": "prod", "alertname": "HighErrorRate", "cluster": "bb", "service": "api"}),
newAlert(model.LabelSet{"env": "prod", "alertname": "HighLatency", "cluster": "bb", "service": "db", "kafka": "yes"}),
)
// Let alerts get processed
time.Sleep(time.Second)
var routeFilter, alertFilter bool
alertGroups, receivers := dispatcher.Groups(func(_ *Route) bool {
routeFilter = true
return true
}, func(_ *types.Alert, _ time.Time) bool {
alertFilter = true
return true
})
// Verify filter functions were called
require.True(t, routeFilter)
require.True(t, alertFilter)
// Verify grouping works
require.Equal(t, 5, len(alertGroups))
for _, ag := range alertGroups {
if len(ag.Labels) == 2 {
// testing receiver
require.Equal(t, 2, len(ag.Labels))
require.Equal(t, model.LabelSet{"alertname": "TestingAlert", "service": "api"}, ag.Labels)
for _, alert := range ag.Alerts {
alertsReceivers, ok := receivers[alert.Fingerprint()]
require.True(t, ok)
require.Equal(t, 1, len(alertsReceivers))
require.Equal(t, "testing", alertsReceivers[0])
}
continue
}
require.Equal(t, 3, len(ag.Labels))
for _, alert := range ag.Alerts {
alertsReceivers, ok := receivers[alert.Fingerprint()]
require.True(t, ok)
if labelValue := ag.Labels["alertname"]; string(labelValue) == "HighLatency" {
// Matches both prod and kafka receivers
require.Equal(t, []string{"prod", "kafka"}, alertsReceivers)
continue
}
require.Equal(t, 1, len(alertsReceivers))
require.Equal(t, "prod", alertsReceivers[0])
}
}
}
type noopStage struct{}
func (n *noopStage) Exec(ctx context.Context, l log.Logger, alerts ...*types.Alert) (context.Context, []*types.Alert, error) {
return ctx, nil, nil
}
var (
t0 = time.Now()
t1 = t0.Add(100 * time.Millisecond)
)
func newAlert(labels model.LabelSet) *types.Alert {
return &types.Alert{
Alert: model.Alert{
Labels: labels,
Annotations: model.LabelSet{"foo": "bar"},
StartsAt: t0,
EndsAt: t1,
GeneratorURL: "http://example.com/prometheus",
},
UpdatedAt: t0,
Timeout: false,
}
}

34
dispatch/testdata/conf.yml vendored Normal file
View File

@ -0,0 +1,34 @@
global:
resolve_timeout: 5m
receivers:
- name: 'testing'
webhook_configs:
- url: 'http://127.0.0.1:5001/'
- name: 'prod'
webhook_configs:
- url: 'http://127.0.0.1:5001/'
- name: 'kafka'
webhook_configs:
- url: 'http://127.0.0.1:5001/'
route:
group_by: ['alertname']
group_wait: 10s
group_interval: 10s
repeat_interval: 1h
receiver: 'prod'
routes:
- match:
env: 'testing'
receiver: 'testing'
group_by: ['alertname', 'service']
- match:
env: 'prod'
receiver: 'prod'
group_by: ['alertname', 'service', 'cluster']
continue: true
- match:
kafka: 'yes'
receiver: 'kafka'
group_by: ['alertname', 'service', 'cluster']