...

Source file src/github.com/prometheus/alertmanager/api/v2/api.go

Documentation: github.com/prometheus/alertmanager/api/v2

     1  // Copyright 2018 Prometheus Team
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package v2
    15  
    16  import (
    17  	"fmt"
    18  	"net/http"
    19  	"regexp"
    20  	"sort"
    21  	"sync"
    22  	"time"
    23  
    24  	"github.com/go-kit/log"
    25  	"github.com/go-kit/log/level"
    26  	"github.com/go-openapi/analysis"
    27  	"github.com/go-openapi/loads"
    28  	"github.com/go-openapi/runtime/middleware"
    29  	"github.com/go-openapi/strfmt"
    30  	"github.com/prometheus/client_golang/prometheus"
    31  	prometheus_model "github.com/prometheus/common/model"
    32  	"github.com/prometheus/common/version"
    33  	"github.com/rs/cors"
    34  
    35  	"github.com/prometheus/alertmanager/api/metrics"
    36  	open_api_models "github.com/prometheus/alertmanager/api/v2/models"
    37  	"github.com/prometheus/alertmanager/api/v2/restapi"
    38  	"github.com/prometheus/alertmanager/api/v2/restapi/operations"
    39  	alert_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/alert"
    40  	alertgroup_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/alertgroup"
    41  	general_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/general"
    42  	receiver_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/receiver"
    43  	silence_ops "github.com/prometheus/alertmanager/api/v2/restapi/operations/silence"
    44  	"github.com/prometheus/alertmanager/cluster"
    45  	"github.com/prometheus/alertmanager/config"
    46  	"github.com/prometheus/alertmanager/dispatch"
    47  	"github.com/prometheus/alertmanager/pkg/labels"
    48  	"github.com/prometheus/alertmanager/provider"
    49  	"github.com/prometheus/alertmanager/silence"
    50  	"github.com/prometheus/alertmanager/silence/silencepb"
    51  	"github.com/prometheus/alertmanager/types"
    52  )
    53  
    54  // API represents an Alertmanager API v2
    55  type API struct {
    56  	peer           cluster.ClusterPeer
    57  	silences       *silence.Silences
    58  	alerts         provider.Alerts
    59  	alertGroups    groupsFn
    60  	getAlertStatus getAlertStatusFn
    61  	uptime         time.Time
    62  
    63  	// mtx protects alertmanagerConfig, setAlertStatus and route.
    64  	mtx sync.RWMutex
    65  	// resolveTimeout represents the default resolve timeout that an alert is
    66  	// assigned if no end time is specified.
    67  	alertmanagerConfig *config.Config
    68  	route              *dispatch.Route
    69  	setAlertStatus     setAlertStatusFn
    70  
    71  	logger log.Logger
    72  	m      *metrics.Alerts
    73  
    74  	Handler http.Handler
    75  }
    76  
    77  type (
    78  	groupsFn         func(func(*dispatch.Route) bool, func(*types.Alert, time.Time) bool) (dispatch.AlertGroups, map[prometheus_model.Fingerprint][]string)
    79  	getAlertStatusFn func(prometheus_model.Fingerprint) types.AlertStatus
    80  	setAlertStatusFn func(prometheus_model.LabelSet)
    81  )
    82  
    83  // NewAPI returns a new Alertmanager API v2
    84  func NewAPI(
    85  	alerts provider.Alerts,
    86  	gf groupsFn,
    87  	sf getAlertStatusFn,
    88  	silences *silence.Silences,
    89  	peer cluster.ClusterPeer,
    90  	l log.Logger,
    91  	r prometheus.Registerer,
    92  ) (*API, error) {
    93  	api := API{
    94  		alerts:         alerts,
    95  		getAlertStatus: sf,
    96  		alertGroups:    gf,
    97  		peer:           peer,
    98  		silences:       silences,
    99  		logger:         l,
   100  		m:              metrics.NewAlerts("v2", r),
   101  		uptime:         time.Now(),
   102  	}
   103  
   104  	// Load embedded swagger file.
   105  	swaggerSpec, swaggerSpecAnalysis, err := getSwaggerSpec()
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  
   110  	// Create new service API.
   111  	openAPI := operations.NewAlertmanagerAPI(swaggerSpec)
   112  
   113  	// Skip the  redoc middleware, only serving the OpenAPI specification and
   114  	// the API itself via RoutesHandler. See:
   115  	// https://github.com/go-swagger/go-swagger/issues/1779
   116  	openAPI.Middleware = func(b middleware.Builder) http.Handler {
   117  		// Manually create the context so that we can use the singleton swaggerSpecAnalysis.
   118  		swaggerContext := middleware.NewRoutableContextWithAnalyzedSpec(swaggerSpec, swaggerSpecAnalysis, openAPI, nil)
   119  		return middleware.Spec("", swaggerSpec.Raw(), swaggerContext.RoutesHandler(b))
   120  	}
   121  
   122  	openAPI.AlertGetAlertsHandler = alert_ops.GetAlertsHandlerFunc(api.getAlertsHandler)
   123  	openAPI.AlertPostAlertsHandler = alert_ops.PostAlertsHandlerFunc(api.postAlertsHandler)
   124  	openAPI.AlertgroupGetAlertGroupsHandler = alertgroup_ops.GetAlertGroupsHandlerFunc(api.getAlertGroupsHandler)
   125  	openAPI.GeneralGetStatusHandler = general_ops.GetStatusHandlerFunc(api.getStatusHandler)
   126  	openAPI.ReceiverGetReceiversHandler = receiver_ops.GetReceiversHandlerFunc(api.getReceiversHandler)
   127  	openAPI.SilenceDeleteSilenceHandler = silence_ops.DeleteSilenceHandlerFunc(api.deleteSilenceHandler)
   128  	openAPI.SilenceGetSilenceHandler = silence_ops.GetSilenceHandlerFunc(api.getSilenceHandler)
   129  	openAPI.SilenceGetSilencesHandler = silence_ops.GetSilencesHandlerFunc(api.getSilencesHandler)
   130  	openAPI.SilencePostSilencesHandler = silence_ops.PostSilencesHandlerFunc(api.postSilencesHandler)
   131  
   132  	handleCORS := cors.Default().Handler
   133  	api.Handler = handleCORS(openAPI.Serve(nil))
   134  
   135  	return &api, nil
   136  }
   137  
   138  func (api *API) requestLogger(req *http.Request) log.Logger {
   139  	return log.With(api.logger, "path", req.URL.Path, "method", req.Method)
   140  }
   141  
   142  // Update sets the API struct members that may change between reloads of alertmanager.
   143  func (api *API) Update(cfg *config.Config, setAlertStatus setAlertStatusFn) {
   144  	api.mtx.Lock()
   145  	defer api.mtx.Unlock()
   146  
   147  	api.alertmanagerConfig = cfg
   148  	api.route = dispatch.NewRoute(cfg.Route, nil)
   149  	api.setAlertStatus = setAlertStatus
   150  }
   151  
   152  func (api *API) getStatusHandler(params general_ops.GetStatusParams) middleware.Responder {
   153  	api.mtx.RLock()
   154  	defer api.mtx.RUnlock()
   155  
   156  	original := api.alertmanagerConfig.String()
   157  	uptime := strfmt.DateTime(api.uptime)
   158  
   159  	status := open_api_models.ClusterStatusStatusDisabled
   160  
   161  	resp := open_api_models.AlertmanagerStatus{
   162  		Uptime: &uptime,
   163  		VersionInfo: &open_api_models.VersionInfo{
   164  			Version:   &version.Version,
   165  			Revision:  &version.Revision,
   166  			Branch:    &version.Branch,
   167  			BuildUser: &version.BuildUser,
   168  			BuildDate: &version.BuildDate,
   169  			GoVersion: &version.GoVersion,
   170  		},
   171  		Config: &open_api_models.AlertmanagerConfig{
   172  			Original: &original,
   173  		},
   174  		Cluster: &open_api_models.ClusterStatus{
   175  			Status: &status,
   176  			Peers:  []*open_api_models.PeerStatus{},
   177  		},
   178  	}
   179  
   180  	// If alertmanager cluster feature is disabled, then api.peers == nil.
   181  	if api.peer != nil {
   182  		status := api.peer.Status()
   183  
   184  		peers := []*open_api_models.PeerStatus{}
   185  		for _, n := range api.peer.Peers() {
   186  			address := n.Address()
   187  			name := n.Name()
   188  			peers = append(peers, &open_api_models.PeerStatus{
   189  				Name:    &name,
   190  				Address: &address,
   191  			})
   192  		}
   193  
   194  		sort.Slice(peers, func(i, j int) bool {
   195  			return *peers[i].Name < *peers[j].Name
   196  		})
   197  
   198  		resp.Cluster = &open_api_models.ClusterStatus{
   199  			Name:   api.peer.Name(),
   200  			Status: &status,
   201  			Peers:  peers,
   202  		}
   203  	}
   204  
   205  	return general_ops.NewGetStatusOK().WithPayload(&resp)
   206  }
   207  
   208  func (api *API) getReceiversHandler(params receiver_ops.GetReceiversParams) middleware.Responder {
   209  	api.mtx.RLock()
   210  	defer api.mtx.RUnlock()
   211  
   212  	receivers := make([]*open_api_models.Receiver, 0, len(api.alertmanagerConfig.Receivers))
   213  	for _, r := range api.alertmanagerConfig.Receivers {
   214  		receivers = append(receivers, &open_api_models.Receiver{Name: &r.Name})
   215  	}
   216  
   217  	return receiver_ops.NewGetReceiversOK().WithPayload(receivers)
   218  }
   219  
   220  func (api *API) getAlertsHandler(params alert_ops.GetAlertsParams) middleware.Responder {
   221  	var (
   222  		receiverFilter *regexp.Regexp
   223  		// Initialize result slice to prevent api returning `null` when there
   224  		// are no alerts present
   225  		res = open_api_models.GettableAlerts{}
   226  		ctx = params.HTTPRequest.Context()
   227  
   228  		logger = api.requestLogger(params.HTTPRequest)
   229  	)
   230  
   231  	matchers, err := parseFilter(params.Filter)
   232  	if err != nil {
   233  		level.Debug(logger).Log("msg", "Failed to parse matchers", "err", err)
   234  		return alertgroup_ops.NewGetAlertGroupsBadRequest().WithPayload(err.Error())
   235  	}
   236  
   237  	if params.Receiver != nil {
   238  		receiverFilter, err = regexp.Compile("^(?:" + *params.Receiver + ")$")
   239  		if err != nil {
   240  			level.Debug(logger).Log("msg", "Failed to compile receiver regex", "err", err)
   241  			return alert_ops.
   242  				NewGetAlertsBadRequest().
   243  				WithPayload(
   244  					fmt.Sprintf("failed to parse receiver param: %v", err.Error()),
   245  				)
   246  		}
   247  	}
   248  
   249  	alerts := api.alerts.GetPending()
   250  	defer alerts.Close()
   251  
   252  	alertFilter := api.alertFilter(matchers, *params.Silenced, *params.Inhibited, *params.Active)
   253  	now := time.Now()
   254  
   255  	api.mtx.RLock()
   256  	for a := range alerts.Next() {
   257  		if err = alerts.Err(); err != nil {
   258  			break
   259  		}
   260  		if err = ctx.Err(); err != nil {
   261  			break
   262  		}
   263  
   264  		routes := api.route.Match(a.Labels)
   265  		receivers := make([]string, 0, len(routes))
   266  		for _, r := range routes {
   267  			receivers = append(receivers, r.RouteOpts.Receiver)
   268  		}
   269  
   270  		if receiverFilter != nil && !receiversMatchFilter(receivers, receiverFilter) {
   271  			continue
   272  		}
   273  
   274  		if !alertFilter(a, now) {
   275  			continue
   276  		}
   277  
   278  		alert := AlertToOpenAPIAlert(a, api.getAlertStatus(a.Fingerprint()), receivers)
   279  
   280  		res = append(res, alert)
   281  	}
   282  	api.mtx.RUnlock()
   283  
   284  	if err != nil {
   285  		level.Error(logger).Log("msg", "Failed to get alerts", "err", err)
   286  		return alert_ops.NewGetAlertsInternalServerError().WithPayload(err.Error())
   287  	}
   288  	sort.Slice(res, func(i, j int) bool {
   289  		return *res[i].Fingerprint < *res[j].Fingerprint
   290  	})
   291  
   292  	return alert_ops.NewGetAlertsOK().WithPayload(res)
   293  }
   294  
   295  func (api *API) postAlertsHandler(params alert_ops.PostAlertsParams) middleware.Responder {
   296  	logger := api.requestLogger(params.HTTPRequest)
   297  
   298  	alerts := OpenAPIAlertsToAlerts(params.Alerts)
   299  	now := time.Now()
   300  
   301  	api.mtx.RLock()
   302  	resolveTimeout := time.Duration(api.alertmanagerConfig.Global.ResolveTimeout)
   303  	api.mtx.RUnlock()
   304  
   305  	for _, alert := range alerts {
   306  		alert.UpdatedAt = now
   307  
   308  		// Ensure StartsAt is set.
   309  		if alert.StartsAt.IsZero() {
   310  			if alert.EndsAt.IsZero() {
   311  				alert.StartsAt = now
   312  			} else {
   313  				alert.StartsAt = alert.EndsAt
   314  			}
   315  		}
   316  		// If no end time is defined, set a timeout after which an alert
   317  		// is marked resolved if it is not updated.
   318  		if alert.EndsAt.IsZero() {
   319  			alert.Timeout = true
   320  			alert.EndsAt = now.Add(resolveTimeout)
   321  		}
   322  		if alert.EndsAt.After(time.Now()) {
   323  			api.m.Firing().Inc()
   324  		} else {
   325  			api.m.Resolved().Inc()
   326  		}
   327  	}
   328  
   329  	// Make a best effort to insert all alerts that are valid.
   330  	var (
   331  		validAlerts    = make([]*types.Alert, 0, len(alerts))
   332  		validationErrs = &types.MultiError{}
   333  	)
   334  	for _, a := range alerts {
   335  		removeEmptyLabels(a.Labels)
   336  
   337  		if err := a.Validate(); err != nil {
   338  			validationErrs.Add(err)
   339  			api.m.Invalid().Inc()
   340  			continue
   341  		}
   342  		validAlerts = append(validAlerts, a)
   343  	}
   344  	if err := api.alerts.Put(validAlerts...); err != nil {
   345  		level.Error(logger).Log("msg", "Failed to create alerts", "err", err)
   346  		return alert_ops.NewPostAlertsInternalServerError().WithPayload(err.Error())
   347  	}
   348  
   349  	if validationErrs.Len() > 0 {
   350  		level.Error(logger).Log("msg", "Failed to validate alerts", "err", validationErrs.Error())
   351  		return alert_ops.NewPostAlertsBadRequest().WithPayload(validationErrs.Error())
   352  	}
   353  
   354  	return alert_ops.NewPostAlertsOK()
   355  }
   356  
   357  func (api *API) getAlertGroupsHandler(params alertgroup_ops.GetAlertGroupsParams) middleware.Responder {
   358  	logger := api.requestLogger(params.HTTPRequest)
   359  
   360  	matchers, err := parseFilter(params.Filter)
   361  	if err != nil {
   362  		level.Debug(logger).Log("msg", "Failed to parse matchers", "err", err)
   363  		return alertgroup_ops.NewGetAlertGroupsBadRequest().WithPayload(err.Error())
   364  	}
   365  
   366  	var receiverFilter *regexp.Regexp
   367  	if params.Receiver != nil {
   368  		receiverFilter, err = regexp.Compile("^(?:" + *params.Receiver + ")$")
   369  		if err != nil {
   370  			level.Error(logger).Log("msg", "Failed to compile receiver regex", "err", err)
   371  			return alertgroup_ops.
   372  				NewGetAlertGroupsBadRequest().
   373  				WithPayload(
   374  					fmt.Sprintf("failed to parse receiver param: %v", err.Error()),
   375  				)
   376  		}
   377  	}
   378  
   379  	rf := func(receiverFilter *regexp.Regexp) func(r *dispatch.Route) bool {
   380  		return func(r *dispatch.Route) bool {
   381  			receiver := r.RouteOpts.Receiver
   382  			if receiverFilter != nil && !receiverFilter.MatchString(receiver) {
   383  				return false
   384  			}
   385  			return true
   386  		}
   387  	}(receiverFilter)
   388  
   389  	af := api.alertFilter(matchers, *params.Silenced, *params.Inhibited, *params.Active)
   390  	alertGroups, allReceivers := api.alertGroups(rf, af)
   391  
   392  	res := make(open_api_models.AlertGroups, 0, len(alertGroups))
   393  
   394  	for _, alertGroup := range alertGroups {
   395  		ag := &open_api_models.AlertGroup{
   396  			Receiver: &open_api_models.Receiver{Name: &alertGroup.Receiver},
   397  			Labels:   ModelLabelSetToAPILabelSet(alertGroup.Labels),
   398  			Alerts:   make([]*open_api_models.GettableAlert, 0, len(alertGroup.Alerts)),
   399  		}
   400  
   401  		for _, alert := range alertGroup.Alerts {
   402  			fp := alert.Fingerprint()
   403  			receivers := allReceivers[fp]
   404  			status := api.getAlertStatus(fp)
   405  			apiAlert := AlertToOpenAPIAlert(alert, status, receivers)
   406  			ag.Alerts = append(ag.Alerts, apiAlert)
   407  		}
   408  		res = append(res, ag)
   409  	}
   410  
   411  	return alertgroup_ops.NewGetAlertGroupsOK().WithPayload(res)
   412  }
   413  
   414  func (api *API) alertFilter(matchers []*labels.Matcher, silenced, inhibited, active bool) func(a *types.Alert, now time.Time) bool {
   415  	return func(a *types.Alert, now time.Time) bool {
   416  		if !a.EndsAt.IsZero() && a.EndsAt.Before(now) {
   417  			return false
   418  		}
   419  
   420  		// Set alert's current status based on its label set.
   421  		api.setAlertStatus(a.Labels)
   422  
   423  		// Get alert's current status after seeing if it is suppressed.
   424  		status := api.getAlertStatus(a.Fingerprint())
   425  
   426  		if !active && status.State == types.AlertStateActive {
   427  			return false
   428  		}
   429  
   430  		if !silenced && len(status.SilencedBy) != 0 {
   431  			return false
   432  		}
   433  
   434  		if !inhibited && len(status.InhibitedBy) != 0 {
   435  			return false
   436  		}
   437  
   438  		return alertMatchesFilterLabels(&a.Alert, matchers)
   439  	}
   440  }
   441  
   442  func removeEmptyLabels(ls prometheus_model.LabelSet) {
   443  	for k, v := range ls {
   444  		if string(v) == "" {
   445  			delete(ls, k)
   446  		}
   447  	}
   448  }
   449  
   450  func receiversMatchFilter(receivers []string, filter *regexp.Regexp) bool {
   451  	for _, r := range receivers {
   452  		if filter.MatchString(r) {
   453  			return true
   454  		}
   455  	}
   456  
   457  	return false
   458  }
   459  
   460  func alertMatchesFilterLabels(a *prometheus_model.Alert, matchers []*labels.Matcher) bool {
   461  	sms := make(map[string]string)
   462  	for name, value := range a.Labels {
   463  		sms[string(name)] = string(value)
   464  	}
   465  	return matchFilterLabels(matchers, sms)
   466  }
   467  
   468  func matchFilterLabels(matchers []*labels.Matcher, sms map[string]string) bool {
   469  	for _, m := range matchers {
   470  		v, prs := sms[m.Name]
   471  		switch m.Type {
   472  		case labels.MatchNotRegexp, labels.MatchNotEqual:
   473  			if m.Value == "" && prs {
   474  				continue
   475  			}
   476  			if !m.Matches(v) {
   477  				return false
   478  			}
   479  		default:
   480  			if m.Value == "" && !prs {
   481  				continue
   482  			}
   483  			if !m.Matches(v) {
   484  				return false
   485  			}
   486  		}
   487  	}
   488  
   489  	return true
   490  }
   491  
   492  func (api *API) getSilencesHandler(params silence_ops.GetSilencesParams) middleware.Responder {
   493  	logger := api.requestLogger(params.HTTPRequest)
   494  
   495  	matchers := []*labels.Matcher{}
   496  	if params.Filter != nil {
   497  		for _, matcherString := range params.Filter {
   498  			matcher, err := labels.ParseMatcher(matcherString)
   499  			if err != nil {
   500  				level.Debug(logger).Log("msg", "Failed to parse matchers", "err", err)
   501  				return alert_ops.NewGetAlertsBadRequest().WithPayload(err.Error())
   502  			}
   503  
   504  			matchers = append(matchers, matcher)
   505  		}
   506  	}
   507  
   508  	psils, _, err := api.silences.Query()
   509  	if err != nil {
   510  		level.Error(logger).Log("msg", "Failed to get silences", "err", err)
   511  		return silence_ops.NewGetSilencesInternalServerError().WithPayload(err.Error())
   512  	}
   513  
   514  	sils := open_api_models.GettableSilences{}
   515  	for _, ps := range psils {
   516  		if !CheckSilenceMatchesFilterLabels(ps, matchers) {
   517  			continue
   518  		}
   519  		silence, err := GettableSilenceFromProto(ps)
   520  		if err != nil {
   521  			level.Error(logger).Log("msg", "Failed to unmarshal silence from proto", "err", err)
   522  			return silence_ops.NewGetSilencesInternalServerError().WithPayload(err.Error())
   523  		}
   524  		sils = append(sils, &silence)
   525  	}
   526  
   527  	SortSilences(sils)
   528  
   529  	return silence_ops.NewGetSilencesOK().WithPayload(sils)
   530  }
   531  
   532  var silenceStateOrder = map[types.SilenceState]int{
   533  	types.SilenceStateActive:  1,
   534  	types.SilenceStatePending: 2,
   535  	types.SilenceStateExpired: 3,
   536  }
   537  
   538  // SortSilences sorts first according to the state "active, pending, expired"
   539  // then by end time or start time depending on the state.
   540  // active silences should show the next to expire first
   541  // pending silences are ordered based on which one starts next
   542  // expired are ordered based on which one expired most recently
   543  func SortSilences(sils open_api_models.GettableSilences) {
   544  	sort.Slice(sils, func(i, j int) bool {
   545  		state1 := types.SilenceState(*sils[i].Status.State)
   546  		state2 := types.SilenceState(*sils[j].Status.State)
   547  		if state1 != state2 {
   548  			return silenceStateOrder[state1] < silenceStateOrder[state2]
   549  		}
   550  		switch state1 {
   551  		case types.SilenceStateActive:
   552  			endsAt1 := time.Time(*sils[i].Silence.EndsAt)
   553  			endsAt2 := time.Time(*sils[j].Silence.EndsAt)
   554  			return endsAt1.Before(endsAt2)
   555  		case types.SilenceStatePending:
   556  			startsAt1 := time.Time(*sils[i].Silence.StartsAt)
   557  			startsAt2 := time.Time(*sils[j].Silence.StartsAt)
   558  			return startsAt1.Before(startsAt2)
   559  		case types.SilenceStateExpired:
   560  			endsAt1 := time.Time(*sils[i].Silence.EndsAt)
   561  			endsAt2 := time.Time(*sils[j].Silence.EndsAt)
   562  			return endsAt1.After(endsAt2)
   563  		}
   564  		return false
   565  	})
   566  }
   567  
   568  // CheckSilenceMatchesFilterLabels returns true if
   569  // a given silence matches a list of matchers.
   570  // A silence matches a filter (list of matchers) if
   571  // for all matchers in the filter, there exists a matcher in the silence
   572  // such that their names, types, and values are equivalent.
   573  func CheckSilenceMatchesFilterLabels(s *silencepb.Silence, matchers []*labels.Matcher) bool {
   574  	for _, matcher := range matchers {
   575  		found := false
   576  		for _, m := range s.Matchers {
   577  			if matcher.Name == m.Name &&
   578  				(matcher.Type == labels.MatchEqual && m.Type == silencepb.Matcher_EQUAL ||
   579  					matcher.Type == labels.MatchRegexp && m.Type == silencepb.Matcher_REGEXP ||
   580  					matcher.Type == labels.MatchNotEqual && m.Type == silencepb.Matcher_NOT_EQUAL ||
   581  					matcher.Type == labels.MatchNotRegexp && m.Type == silencepb.Matcher_NOT_REGEXP) &&
   582  				matcher.Value == m.Pattern {
   583  				found = true
   584  				break
   585  			}
   586  		}
   587  		if !found {
   588  			return false
   589  		}
   590  	}
   591  
   592  	return true
   593  }
   594  
   595  func (api *API) getSilenceHandler(params silence_ops.GetSilenceParams) middleware.Responder {
   596  	logger := api.requestLogger(params.HTTPRequest)
   597  
   598  	sils, _, err := api.silences.Query(silence.QIDs(params.SilenceID.String()))
   599  	if err != nil {
   600  		level.Error(logger).Log("msg", "Failed to get silence by id", "err", err, "id", params.SilenceID.String())
   601  		return silence_ops.NewGetSilenceInternalServerError().WithPayload(err.Error())
   602  	}
   603  
   604  	if len(sils) == 0 {
   605  		level.Error(logger).Log("msg", "Failed to find silence", "err", err, "id", params.SilenceID.String())
   606  		return silence_ops.NewGetSilenceNotFound()
   607  	}
   608  
   609  	sil, err := GettableSilenceFromProto(sils[0])
   610  	if err != nil {
   611  		level.Error(logger).Log("msg", "Failed to convert unmarshal from proto", "err", err)
   612  		return silence_ops.NewGetSilenceInternalServerError().WithPayload(err.Error())
   613  	}
   614  
   615  	return silence_ops.NewGetSilenceOK().WithPayload(&sil)
   616  }
   617  
   618  func (api *API) deleteSilenceHandler(params silence_ops.DeleteSilenceParams) middleware.Responder {
   619  	logger := api.requestLogger(params.HTTPRequest)
   620  
   621  	sid := params.SilenceID.String()
   622  	if err := api.silences.Expire(sid); err != nil {
   623  		level.Error(logger).Log("msg", "Failed to expire silence", "err", err)
   624  		return silence_ops.NewDeleteSilenceInternalServerError().WithPayload(err.Error())
   625  	}
   626  	return silence_ops.NewDeleteSilenceOK()
   627  }
   628  
   629  func (api *API) postSilencesHandler(params silence_ops.PostSilencesParams) middleware.Responder {
   630  	logger := api.requestLogger(params.HTTPRequest)
   631  
   632  	sil, err := PostableSilenceToProto(params.Silence)
   633  	if err != nil {
   634  		level.Error(logger).Log("msg", "Failed to marshal silence to proto", "err", err)
   635  		return silence_ops.NewPostSilencesBadRequest().WithPayload(
   636  			fmt.Sprintf("failed to convert API silence to internal silence: %v", err.Error()),
   637  		)
   638  	}
   639  
   640  	if sil.StartsAt.After(sil.EndsAt) || sil.StartsAt.Equal(sil.EndsAt) {
   641  		msg := "Failed to create silence: start time must be before end time"
   642  		level.Error(logger).Log("msg", msg, "starts_at", sil.StartsAt, "ends_at", sil.EndsAt)
   643  		return silence_ops.NewPostSilencesBadRequest().WithPayload(msg)
   644  	}
   645  
   646  	if sil.EndsAt.Before(time.Now()) {
   647  		msg := "Failed to create silence: end time can't be in the past"
   648  		level.Error(logger).Log("msg", msg, "ends_at", sil.EndsAt)
   649  		return silence_ops.NewPostSilencesBadRequest().WithPayload(msg)
   650  	}
   651  
   652  	sid, err := api.silences.Set(sil)
   653  	if err != nil {
   654  		level.Error(logger).Log("msg", "Failed to create silence", "err", err)
   655  		if err == silence.ErrNotFound {
   656  			return silence_ops.NewPostSilencesNotFound().WithPayload(err.Error())
   657  		}
   658  		return silence_ops.NewPostSilencesBadRequest().WithPayload(err.Error())
   659  	}
   660  
   661  	return silence_ops.NewPostSilencesOK().WithPayload(&silence_ops.PostSilencesOKBody{
   662  		SilenceID: sid,
   663  	})
   664  }
   665  
   666  func parseFilter(filter []string) ([]*labels.Matcher, error) {
   667  	matchers := make([]*labels.Matcher, 0, len(filter))
   668  	for _, matcherString := range filter {
   669  		matcher, err := labels.ParseMatcher(matcherString)
   670  		if err != nil {
   671  			return nil, err
   672  		}
   673  
   674  		matchers = append(matchers, matcher)
   675  	}
   676  	return matchers, nil
   677  }
   678  
   679  var (
   680  	swaggerSpecCacheMx       sync.Mutex
   681  	swaggerSpecCache         *loads.Document
   682  	swaggerSpecAnalysisCache *analysis.Spec
   683  )
   684  
   685  // getSwaggerSpec loads and caches the swagger spec. If a cached version already exists,
   686  // it returns the cached one. The reason why we cache it is because some downstream projects
   687  // (e.g. Grafana Mimir) creates many Alertmanager instances in the same process, so they would
   688  // incur in a significant memory penalty if we would reload the swagger spec each time.
   689  func getSwaggerSpec() (*loads.Document, *analysis.Spec, error) {
   690  	swaggerSpecCacheMx.Lock()
   691  	defer swaggerSpecCacheMx.Unlock()
   692  
   693  	// Check if a cached version exists.
   694  	if swaggerSpecCache != nil {
   695  		return swaggerSpecCache, swaggerSpecAnalysisCache, nil
   696  	}
   697  
   698  	// Load embedded swagger file.
   699  	swaggerSpec, err := loads.Analyzed(restapi.SwaggerJSON, "")
   700  	if err != nil {
   701  		return nil, nil, fmt.Errorf("failed to load embedded swagger file: %w", err)
   702  	}
   703  
   704  	swaggerSpecCache = swaggerSpec
   705  	swaggerSpecAnalysisCache = analysis.New(swaggerSpec.Spec())
   706  	return swaggerSpec, swaggerSpecAnalysisCache, nil
   707  }
   708  

View as plain text