Show muted alerts in Alert Groups API (#3797)
This commit updates /api/v2/alerts/groups to show if an alert is suppressed from one or more active or mute time intervals. While the muted by field can be found in /api/v2/alerts, it is not used here because /api/v2/alerts does not take aggregation or routing into consideration. It also updates the UI to support filtering muted alerts via the Muted checkbox. Signed-off-by: George Robinson <george.robinson@grafana.com>
This commit is contained in:
parent
8572fe849c
commit
5979dff9dc
22
api/api.go
22
api/api.go
|
@ -45,16 +45,20 @@ type API struct {
|
||||||
inFlightSem chan struct{}
|
inFlightSem chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Options for the creation of an API object. Alerts, Silences, and StatusFunc
|
// Options for the creation of an API object. Alerts, Silences, AlertStatusFunc
|
||||||
// are mandatory to set. The zero value for everything else is a safe default.
|
// and GroupMutedFunc are mandatory. The zero value for everything else is a safe
|
||||||
|
// default.
|
||||||
type Options struct {
|
type Options struct {
|
||||||
// Alerts to be used by the API. Mandatory.
|
// Alerts to be used by the API. Mandatory.
|
||||||
Alerts provider.Alerts
|
Alerts provider.Alerts
|
||||||
// Silences to be used by the API. Mandatory.
|
// Silences to be used by the API. Mandatory.
|
||||||
Silences *silence.Silences
|
Silences *silence.Silences
|
||||||
// StatusFunc is used be the API to retrieve the AlertStatus of an
|
// AlertStatusFunc is used be the API to retrieve the AlertStatus of an
|
||||||
// alert. Mandatory.
|
// alert. Mandatory.
|
||||||
StatusFunc func(model.Fingerprint) types.AlertStatus
|
AlertStatusFunc func(model.Fingerprint) types.AlertStatus
|
||||||
|
// GroupMutedFunc is used be the API to know if an alert is muted.
|
||||||
|
// Mandatory.
|
||||||
|
GroupMutedFunc func(routeID, groupKey string) ([]string, bool)
|
||||||
// Peer from the gossip cluster. If nil, no clustering will be used.
|
// Peer from the gossip cluster. If nil, no clustering will be used.
|
||||||
Peer cluster.ClusterPeer
|
Peer cluster.ClusterPeer
|
||||||
// Timeout for all HTTP connections. The zero value (and negative
|
// Timeout for all HTTP connections. The zero value (and negative
|
||||||
|
@ -83,8 +87,11 @@ func (o Options) validate() error {
|
||||||
if o.Silences == nil {
|
if o.Silences == nil {
|
||||||
return errors.New("mandatory field Silences not set")
|
return errors.New("mandatory field Silences not set")
|
||||||
}
|
}
|
||||||
if o.StatusFunc == nil {
|
if o.AlertStatusFunc == nil {
|
||||||
return errors.New("mandatory field StatusFunc not set")
|
return errors.New("mandatory field AlertStatusFunc not set")
|
||||||
|
}
|
||||||
|
if o.GroupMutedFunc == nil {
|
||||||
|
return errors.New("mandatory field GroupMutedFunc not set")
|
||||||
}
|
}
|
||||||
if o.GroupFunc == nil {
|
if o.GroupFunc == nil {
|
||||||
return errors.New("mandatory field GroupFunc not set")
|
return errors.New("mandatory field GroupFunc not set")
|
||||||
|
@ -113,7 +120,8 @@ func New(opts Options) (*API, error) {
|
||||||
v2, err := apiv2.NewAPI(
|
v2, err := apiv2.NewAPI(
|
||||||
opts.Alerts,
|
opts.Alerts,
|
||||||
opts.GroupFunc,
|
opts.GroupFunc,
|
||||||
opts.StatusFunc,
|
opts.AlertStatusFunc,
|
||||||
|
opts.GroupMutedFunc,
|
||||||
opts.Silences,
|
opts.Silences,
|
||||||
opts.Peer,
|
opts.Peer,
|
||||||
log.With(l, "version", "v2"),
|
log.With(l, "version", "v2"),
|
||||||
|
|
|
@ -60,6 +60,7 @@ type API struct {
|
||||||
alerts provider.Alerts
|
alerts provider.Alerts
|
||||||
alertGroups groupsFn
|
alertGroups groupsFn
|
||||||
getAlertStatus getAlertStatusFn
|
getAlertStatus getAlertStatusFn
|
||||||
|
groupMutedFunc groupMutedFunc
|
||||||
uptime time.Time
|
uptime time.Time
|
||||||
|
|
||||||
// mtx protects alertmanagerConfig, setAlertStatus and route.
|
// mtx protects alertmanagerConfig, setAlertStatus and route.
|
||||||
|
@ -78,6 +79,7 @@ type API struct {
|
||||||
|
|
||||||
type (
|
type (
|
||||||
groupsFn func(func(*dispatch.Route) bool, func(*types.Alert, time.Time) bool) (dispatch.AlertGroups, map[prometheus_model.Fingerprint][]string)
|
groupsFn func(func(*dispatch.Route) bool, func(*types.Alert, time.Time) bool) (dispatch.AlertGroups, map[prometheus_model.Fingerprint][]string)
|
||||||
|
groupMutedFunc func(routeID, groupKey string) ([]string, bool)
|
||||||
getAlertStatusFn func(prometheus_model.Fingerprint) types.AlertStatus
|
getAlertStatusFn func(prometheus_model.Fingerprint) types.AlertStatus
|
||||||
setAlertStatusFn func(prometheus_model.LabelSet)
|
setAlertStatusFn func(prometheus_model.LabelSet)
|
||||||
)
|
)
|
||||||
|
@ -86,7 +88,8 @@ type (
|
||||||
func NewAPI(
|
func NewAPI(
|
||||||
alerts provider.Alerts,
|
alerts provider.Alerts,
|
||||||
gf groupsFn,
|
gf groupsFn,
|
||||||
sf getAlertStatusFn,
|
asf getAlertStatusFn,
|
||||||
|
gmf groupMutedFunc,
|
||||||
silences *silence.Silences,
|
silences *silence.Silences,
|
||||||
peer cluster.ClusterPeer,
|
peer cluster.ClusterPeer,
|
||||||
l log.Logger,
|
l log.Logger,
|
||||||
|
@ -94,8 +97,9 @@ func NewAPI(
|
||||||
) (*API, error) {
|
) (*API, error) {
|
||||||
api := API{
|
api := API{
|
||||||
alerts: alerts,
|
alerts: alerts,
|
||||||
getAlertStatus: sf,
|
getAlertStatus: asf,
|
||||||
alertGroups: gf,
|
alertGroups: gf,
|
||||||
|
groupMutedFunc: gmf,
|
||||||
peer: peer,
|
peer: peer,
|
||||||
silences: silences,
|
silences: silences,
|
||||||
logger: l,
|
logger: l,
|
||||||
|
@ -290,7 +294,7 @@ func (api *API) getAlertsHandler(params alert_ops.GetAlertsParams) middleware.Re
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
alert := AlertToOpenAPIAlert(a, api.getAlertStatus(a.Fingerprint()), receivers)
|
alert := AlertToOpenAPIAlert(a, api.getAlertStatus(a.Fingerprint()), receivers, nil)
|
||||||
|
|
||||||
res = append(res, alert)
|
res = append(res, alert)
|
||||||
}
|
}
|
||||||
|
@ -407,6 +411,11 @@ func (api *API) getAlertGroupsHandler(params alertgroup_ops.GetAlertGroupsParams
|
||||||
res := make(open_api_models.AlertGroups, 0, len(alertGroups))
|
res := make(open_api_models.AlertGroups, 0, len(alertGroups))
|
||||||
|
|
||||||
for _, alertGroup := range alertGroups {
|
for _, alertGroup := range alertGroups {
|
||||||
|
mutedBy, isMuted := api.groupMutedFunc(alertGroup.RouteID, alertGroup.GroupKey)
|
||||||
|
if !*params.Muted && isMuted {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
ag := &open_api_models.AlertGroup{
|
ag := &open_api_models.AlertGroup{
|
||||||
Receiver: &open_api_models.Receiver{Name: &alertGroup.Receiver},
|
Receiver: &open_api_models.Receiver{Name: &alertGroup.Receiver},
|
||||||
Labels: ModelLabelSetToAPILabelSet(alertGroup.Labels),
|
Labels: ModelLabelSetToAPILabelSet(alertGroup.Labels),
|
||||||
|
@ -417,7 +426,7 @@ func (api *API) getAlertGroupsHandler(params alertgroup_ops.GetAlertGroupsParams
|
||||||
fp := alert.Fingerprint()
|
fp := alert.Fingerprint()
|
||||||
receivers := allReceivers[fp]
|
receivers := allReceivers[fp]
|
||||||
status := api.getAlertStatus(fp)
|
status := api.getAlertStatus(fp)
|
||||||
apiAlert := AlertToOpenAPIAlert(alert, status, receivers)
|
apiAlert := AlertToOpenAPIAlert(alert, status, receivers, mutedBy)
|
||||||
ag.Alerts = append(ag.Alerts, apiAlert)
|
ag.Alerts = append(ag.Alerts, apiAlert)
|
||||||
}
|
}
|
||||||
res = append(res, ag)
|
res = append(res, ag)
|
||||||
|
|
|
@ -484,17 +484,12 @@ func TestAlertToOpenAPIAlert(t *testing.T) {
|
||||||
UpdatedAt: updated,
|
UpdatedAt: updated,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
openAPIAlert := AlertToOpenAPIAlert(alert, types.AlertStatus{State: types.AlertStateActive}, receivers)
|
openAPIAlert := AlertToOpenAPIAlert(alert, types.AlertStatus{State: types.AlertStateActive}, receivers, nil)
|
||||||
require.Equal(t, &open_api_models.GettableAlert{
|
require.Equal(t, &open_api_models.GettableAlert{
|
||||||
Annotations: open_api_models.LabelSet{},
|
Annotations: open_api_models.LabelSet{},
|
||||||
Alert: open_api_models.Alert{
|
Alert: open_api_models.Alert{
|
||||||
Labels: open_api_models.LabelSet{"severity": "critical", "alertname": "alert1"},
|
Labels: open_api_models.LabelSet{"severity": "critical", "alertname": "alert1"},
|
||||||
},
|
},
|
||||||
Status: &open_api_models.AlertStatus{
|
|
||||||
State: &active,
|
|
||||||
InhibitedBy: []string{},
|
|
||||||
SilencedBy: []string{},
|
|
||||||
},
|
|
||||||
StartsAt: convertDateTime(start),
|
StartsAt: convertDateTime(start),
|
||||||
EndsAt: convertDateTime(time.Time{}),
|
EndsAt: convertDateTime(time.Time{}),
|
||||||
UpdatedAt: convertDateTime(updated),
|
UpdatedAt: convertDateTime(updated),
|
||||||
|
@ -503,6 +498,12 @@ func TestAlertToOpenAPIAlert(t *testing.T) {
|
||||||
{Name: &receivers[0]},
|
{Name: &receivers[0]},
|
||||||
{Name: &receivers[1]},
|
{Name: &receivers[1]},
|
||||||
},
|
},
|
||||||
|
Status: &open_api_models.AlertStatus{
|
||||||
|
State: &active,
|
||||||
|
InhibitedBy: []string{},
|
||||||
|
SilencedBy: []string{},
|
||||||
|
MutedBy: []string{},
|
||||||
|
},
|
||||||
}, openAPIAlert)
|
}, openAPIAlert)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,14 @@ type GetAlertGroupsParams struct {
|
||||||
*/
|
*/
|
||||||
Inhibited *bool
|
Inhibited *bool
|
||||||
|
|
||||||
|
/* Muted.
|
||||||
|
|
||||||
|
Show muted alerts
|
||||||
|
|
||||||
|
Default: true
|
||||||
|
*/
|
||||||
|
Muted *bool
|
||||||
|
|
||||||
/* Receiver.
|
/* Receiver.
|
||||||
|
|
||||||
A regex matching receivers to filter alerts by
|
A regex matching receivers to filter alerts by
|
||||||
|
@ -134,12 +142,15 @@ func (o *GetAlertGroupsParams) SetDefaults() {
|
||||||
|
|
||||||
inhibitedDefault = bool(true)
|
inhibitedDefault = bool(true)
|
||||||
|
|
||||||
|
mutedDefault = bool(true)
|
||||||
|
|
||||||
silencedDefault = bool(true)
|
silencedDefault = bool(true)
|
||||||
)
|
)
|
||||||
|
|
||||||
val := GetAlertGroupsParams{
|
val := GetAlertGroupsParams{
|
||||||
Active: &activeDefault,
|
Active: &activeDefault,
|
||||||
Inhibited: &inhibitedDefault,
|
Inhibited: &inhibitedDefault,
|
||||||
|
Muted: &mutedDefault,
|
||||||
Silenced: &silencedDefault,
|
Silenced: &silencedDefault,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,6 +226,17 @@ func (o *GetAlertGroupsParams) SetInhibited(inhibited *bool) {
|
||||||
o.Inhibited = inhibited
|
o.Inhibited = inhibited
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMuted adds the muted to the get alert groups params
|
||||||
|
func (o *GetAlertGroupsParams) WithMuted(muted *bool) *GetAlertGroupsParams {
|
||||||
|
o.SetMuted(muted)
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMuted adds the muted to the get alert groups params
|
||||||
|
func (o *GetAlertGroupsParams) SetMuted(muted *bool) {
|
||||||
|
o.Muted = muted
|
||||||
|
}
|
||||||
|
|
||||||
// WithReceiver adds the receiver to the get alert groups params
|
// WithReceiver adds the receiver to the get alert groups params
|
||||||
func (o *GetAlertGroupsParams) WithReceiver(receiver *string) *GetAlertGroupsParams {
|
func (o *GetAlertGroupsParams) WithReceiver(receiver *string) *GetAlertGroupsParams {
|
||||||
o.SetReceiver(receiver)
|
o.SetReceiver(receiver)
|
||||||
|
@ -290,6 +312,23 @@ func (o *GetAlertGroupsParams) WriteToRequest(r runtime.ClientRequest, reg strfm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.Muted != nil {
|
||||||
|
|
||||||
|
// query param muted
|
||||||
|
var qrMuted bool
|
||||||
|
|
||||||
|
if o.Muted != nil {
|
||||||
|
qrMuted = *o.Muted
|
||||||
|
}
|
||||||
|
qMuted := swag.FormatBool(qrMuted)
|
||||||
|
if qMuted != "" {
|
||||||
|
|
||||||
|
if err := r.SetQueryParam("muted", qMuted); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if o.Receiver != nil {
|
if o.Receiver != nil {
|
||||||
|
|
||||||
// query param receiver
|
// query param receiver
|
||||||
|
|
|
@ -117,7 +117,7 @@ func PostableSilenceToProto(s *open_api_models.PostableSilence) (*silencepb.Sile
|
||||||
}
|
}
|
||||||
|
|
||||||
// AlertToOpenAPIAlert converts internal alerts, alert types, and receivers to *open_api_models.GettableAlert.
|
// AlertToOpenAPIAlert converts internal alerts, alert types, and receivers to *open_api_models.GettableAlert.
|
||||||
func AlertToOpenAPIAlert(alert *types.Alert, status types.AlertStatus, receivers []string) *open_api_models.GettableAlert {
|
func AlertToOpenAPIAlert(alert *types.Alert, status types.AlertStatus, receivers, mutedBy []string) *open_api_models.GettableAlert {
|
||||||
startsAt := strfmt.DateTime(alert.StartsAt)
|
startsAt := strfmt.DateTime(alert.StartsAt)
|
||||||
updatedAt := strfmt.DateTime(alert.UpdatedAt)
|
updatedAt := strfmt.DateTime(alert.UpdatedAt)
|
||||||
endsAt := strfmt.DateTime(alert.EndsAt)
|
endsAt := strfmt.DateTime(alert.EndsAt)
|
||||||
|
@ -128,7 +128,13 @@ func AlertToOpenAPIAlert(alert *types.Alert, status types.AlertStatus, receivers
|
||||||
}
|
}
|
||||||
|
|
||||||
fp := alert.Fingerprint().String()
|
fp := alert.Fingerprint().String()
|
||||||
|
|
||||||
state := string(status.State)
|
state := string(status.State)
|
||||||
|
if len(mutedBy) > 0 {
|
||||||
|
// If the alert is muted, change the state to suppressed.
|
||||||
|
state = open_api_models.AlertStatusStateSuppressed
|
||||||
|
}
|
||||||
|
|
||||||
aa := &open_api_models.GettableAlert{
|
aa := &open_api_models.GettableAlert{
|
||||||
Alert: open_api_models.Alert{
|
Alert: open_api_models.Alert{
|
||||||
GeneratorURL: strfmt.URI(alert.GeneratorURL),
|
GeneratorURL: strfmt.URI(alert.GeneratorURL),
|
||||||
|
@ -144,6 +150,7 @@ func AlertToOpenAPIAlert(alert *types.Alert, status types.AlertStatus, receivers
|
||||||
State: &state,
|
State: &state,
|
||||||
SilencedBy: status.SilencedBy,
|
SilencedBy: status.SilencedBy,
|
||||||
InhibitedBy: status.InhibitedBy,
|
InhibitedBy: status.InhibitedBy,
|
||||||
|
MutedBy: mutedBy,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +162,10 @@ func AlertToOpenAPIAlert(alert *types.Alert, status types.AlertStatus, receivers
|
||||||
aa.Status.InhibitedBy = []string{}
|
aa.Status.InhibitedBy = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if aa.Status.MutedBy == nil {
|
||||||
|
aa.Status.MutedBy = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
return aa
|
return aa
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,10 @@ type AlertStatus struct {
|
||||||
// Required: true
|
// Required: true
|
||||||
InhibitedBy []string `json:"inhibitedBy"`
|
InhibitedBy []string `json:"inhibitedBy"`
|
||||||
|
|
||||||
|
// muted by
|
||||||
|
// Required: true
|
||||||
|
MutedBy []string `json:"mutedBy"`
|
||||||
|
|
||||||
// silenced by
|
// silenced by
|
||||||
// Required: true
|
// Required: true
|
||||||
SilencedBy []string `json:"silencedBy"`
|
SilencedBy []string `json:"silencedBy"`
|
||||||
|
@ -56,6 +60,10 @@ func (m *AlertStatus) Validate(formats strfmt.Registry) error {
|
||||||
res = append(res, err)
|
res = append(res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := m.validateMutedBy(formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := m.validateSilencedBy(formats); err != nil {
|
if err := m.validateSilencedBy(formats); err != nil {
|
||||||
res = append(res, err)
|
res = append(res, err)
|
||||||
}
|
}
|
||||||
|
@ -79,6 +87,15 @@ func (m *AlertStatus) validateInhibitedBy(formats strfmt.Registry) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *AlertStatus) validateMutedBy(formats strfmt.Registry) error {
|
||||||
|
|
||||||
|
if err := validate.Required("mutedBy", "body", m.MutedBy); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *AlertStatus) validateSilencedBy(formats strfmt.Registry) error {
|
func (m *AlertStatus) validateSilencedBy(formats strfmt.Registry) error {
|
||||||
|
|
||||||
if err := validate.Required("silencedBy", "body", m.SilencedBy); err != nil {
|
if err := validate.Required("silencedBy", "body", m.SilencedBy); err != nil {
|
||||||
|
|
|
@ -223,6 +223,11 @@ paths:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: Show inhibited alerts
|
description: Show inhibited alerts
|
||||||
default: true
|
default: true
|
||||||
|
- in: query
|
||||||
|
name: muted
|
||||||
|
type: boolean
|
||||||
|
description: Show muted alerts
|
||||||
|
default: true
|
||||||
- name: filter
|
- name: filter
|
||||||
in: query
|
in: query
|
||||||
description: A list of matchers to filter alerts by
|
description: A list of matchers to filter alerts by
|
||||||
|
@ -501,10 +506,15 @@ definitions:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
mutedBy:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
required:
|
required:
|
||||||
- state
|
- state
|
||||||
- silencedBy
|
- silencedBy
|
||||||
- inhibitedBy
|
- inhibitedBy
|
||||||
|
- mutedBy
|
||||||
receiver:
|
receiver:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
|
@ -177,6 +177,13 @@ func init() {
|
||||||
"name": "inhibited",
|
"name": "inhibited",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Show muted alerts",
|
||||||
|
"name": "muted",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
@ -433,7 +440,8 @@ func init() {
|
||||||
"required": [
|
"required": [
|
||||||
"state",
|
"state",
|
||||||
"silencedBy",
|
"silencedBy",
|
||||||
"inhibitedBy"
|
"inhibitedBy",
|
||||||
|
"mutedBy"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"inhibitedBy": {
|
"inhibitedBy": {
|
||||||
|
@ -442,6 +450,12 @@ func init() {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mutedBy": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
"silencedBy": {
|
"silencedBy": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
@ -979,6 +993,13 @@ func init() {
|
||||||
"name": "inhibited",
|
"name": "inhibited",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Show muted alerts",
|
||||||
|
"name": "muted",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
@ -1256,7 +1277,8 @@ func init() {
|
||||||
"required": [
|
"required": [
|
||||||
"state",
|
"state",
|
||||||
"silencedBy",
|
"silencedBy",
|
||||||
"inhibitedBy"
|
"inhibitedBy",
|
||||||
|
"mutedBy"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"inhibitedBy": {
|
"inhibitedBy": {
|
||||||
|
@ -1265,6 +1287,12 @@ func init() {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mutedBy": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
"silencedBy": {
|
"silencedBy": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
|
|
@ -39,6 +39,7 @@ func NewGetAlertGroupsParams() GetAlertGroupsParams {
|
||||||
activeDefault = bool(true)
|
activeDefault = bool(true)
|
||||||
|
|
||||||
inhibitedDefault = bool(true)
|
inhibitedDefault = bool(true)
|
||||||
|
mutedDefault = bool(true)
|
||||||
|
|
||||||
silencedDefault = bool(true)
|
silencedDefault = bool(true)
|
||||||
)
|
)
|
||||||
|
@ -48,6 +49,8 @@ func NewGetAlertGroupsParams() GetAlertGroupsParams {
|
||||||
|
|
||||||
Inhibited: &inhibitedDefault,
|
Inhibited: &inhibitedDefault,
|
||||||
|
|
||||||
|
Muted: &mutedDefault,
|
||||||
|
|
||||||
Silenced: &silencedDefault,
|
Silenced: &silencedDefault,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,6 +79,11 @@ type GetAlertGroupsParams struct {
|
||||||
Default: true
|
Default: true
|
||||||
*/
|
*/
|
||||||
Inhibited *bool
|
Inhibited *bool
|
||||||
|
/*Show muted alerts
|
||||||
|
In: query
|
||||||
|
Default: true
|
||||||
|
*/
|
||||||
|
Muted *bool
|
||||||
/*A regex matching receivers to filter alerts by
|
/*A regex matching receivers to filter alerts by
|
||||||
In: query
|
In: query
|
||||||
*/
|
*/
|
||||||
|
@ -113,6 +121,11 @@ func (o *GetAlertGroupsParams) BindRequest(r *http.Request, route *middleware.Ma
|
||||||
res = append(res, err)
|
res = append(res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qMuted, qhkMuted, _ := qs.GetOK("muted")
|
||||||
|
if err := o.bindMuted(qMuted, qhkMuted, route.Formats); err != nil {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
|
||||||
qReceiver, qhkReceiver, _ := qs.GetOK("receiver")
|
qReceiver, qhkReceiver, _ := qs.GetOK("receiver")
|
||||||
if err := o.bindReceiver(qReceiver, qhkReceiver, route.Formats); err != nil {
|
if err := o.bindReceiver(qReceiver, qhkReceiver, route.Formats); err != nil {
|
||||||
res = append(res, err)
|
res = append(res, err)
|
||||||
|
@ -198,6 +211,30 @@ func (o *GetAlertGroupsParams) bindInhibited(rawData []string, hasKey bool, form
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bindMuted binds and validates parameter Muted from query.
|
||||||
|
func (o *GetAlertGroupsParams) bindMuted(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("muted", "query", "bool", raw)
|
||||||
|
}
|
||||||
|
o.Muted = &value
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// bindReceiver binds and validates parameter Receiver from query.
|
// bindReceiver binds and validates parameter Receiver from query.
|
||||||
func (o *GetAlertGroupsParams) bindReceiver(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
func (o *GetAlertGroupsParams) bindReceiver(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||||
var raw string
|
var raw string
|
||||||
|
|
|
@ -32,6 +32,7 @@ type GetAlertGroupsURL struct {
|
||||||
Active *bool
|
Active *bool
|
||||||
Filter []string
|
Filter []string
|
||||||
Inhibited *bool
|
Inhibited *bool
|
||||||
|
Muted *bool
|
||||||
Receiver *string
|
Receiver *string
|
||||||
Silenced *bool
|
Silenced *bool
|
||||||
|
|
||||||
|
@ -99,6 +100,14 @@ func (o *GetAlertGroupsURL) Build() (*url.URL, error) {
|
||||||
qs.Set("inhibited", inhibitedQ)
|
qs.Set("inhibited", inhibitedQ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mutedQ string
|
||||||
|
if o.Muted != nil {
|
||||||
|
mutedQ = swag.FormatBool(*o.Muted)
|
||||||
|
}
|
||||||
|
if mutedQ != "" {
|
||||||
|
qs.Set("muted", mutedQ)
|
||||||
|
}
|
||||||
|
|
||||||
var receiverQ string
|
var receiverQ string
|
||||||
if o.Receiver != nil {
|
if o.Receiver != nil {
|
||||||
receiverQ = *o.Receiver
|
receiverQ = *o.Receiver
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -368,15 +368,16 @@ func run() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
api, err := api.New(api.Options{
|
api, err := api.New(api.Options{
|
||||||
Alerts: alerts,
|
Alerts: alerts,
|
||||||
Silences: silences,
|
Silences: silences,
|
||||||
StatusFunc: marker.Status,
|
AlertStatusFunc: marker.Status,
|
||||||
Peer: clusterPeer,
|
GroupMutedFunc: marker.Muted,
|
||||||
Timeout: *httpTimeout,
|
Peer: clusterPeer,
|
||||||
Concurrency: *getConcurrency,
|
Timeout: *httpTimeout,
|
||||||
Logger: log.With(logger, "component", "api"),
|
Concurrency: *getConcurrency,
|
||||||
Registry: prometheus.DefaultRegisterer,
|
Logger: log.With(logger, "component", "api"),
|
||||||
GroupFunc: groupFn,
|
Registry: prometheus.DefaultRegisterer,
|
||||||
|
GroupFunc: groupFn,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level.Error(logger).Log("err", fmt.Errorf("failed to create API: %w", err))
|
level.Error(logger).Log("err", fmt.Errorf("failed to create API: %w", err))
|
||||||
|
|
|
@ -206,6 +206,8 @@ type AlertGroup struct {
|
||||||
Alerts types.AlertSlice
|
Alerts types.AlertSlice
|
||||||
Labels model.LabelSet
|
Labels model.LabelSet
|
||||||
Receiver string
|
Receiver string
|
||||||
|
GroupKey string
|
||||||
|
RouteID string
|
||||||
}
|
}
|
||||||
|
|
||||||
type AlertGroups []*AlertGroup
|
type AlertGroups []*AlertGroup
|
||||||
|
@ -242,6 +244,8 @@ func (d *Dispatcher) Groups(routeFilter func(*Route) bool, alertFilter func(*typ
|
||||||
alertGroup := &AlertGroup{
|
alertGroup := &AlertGroup{
|
||||||
Labels: ag.labels,
|
Labels: ag.labels,
|
||||||
Receiver: receiver,
|
Receiver: receiver,
|
||||||
|
GroupKey: ag.GroupKey(),
|
||||||
|
RouteID: ag.routeID,
|
||||||
}
|
}
|
||||||
|
|
||||||
alerts := ag.alerts.List()
|
alerts := ag.alerts.List()
|
||||||
|
|
|
@ -439,6 +439,8 @@ route:
|
||||||
"alertname": "OtherAlert",
|
"alertname": "OtherAlert",
|
||||||
},
|
},
|
||||||
Receiver: "prod",
|
Receiver: "prod",
|
||||||
|
GroupKey: "{}:{alertname=\"OtherAlert\"}",
|
||||||
|
RouteID: "{}",
|
||||||
},
|
},
|
||||||
&AlertGroup{
|
&AlertGroup{
|
||||||
Alerts: []*types.Alert{inputAlerts[1]},
|
Alerts: []*types.Alert{inputAlerts[1]},
|
||||||
|
@ -447,6 +449,8 @@ route:
|
||||||
"service": "api",
|
"service": "api",
|
||||||
},
|
},
|
||||||
Receiver: "testing",
|
Receiver: "testing",
|
||||||
|
GroupKey: "{}/{env=\"testing\"}:{alertname=\"TestingAlert\", service=\"api\"}",
|
||||||
|
RouteID: "{}/{env=\"testing\"}/0",
|
||||||
},
|
},
|
||||||
&AlertGroup{
|
&AlertGroup{
|
||||||
Alerts: []*types.Alert{inputAlerts[2], inputAlerts[3]},
|
Alerts: []*types.Alert{inputAlerts[2], inputAlerts[3]},
|
||||||
|
@ -456,6 +460,8 @@ route:
|
||||||
"cluster": "aa",
|
"cluster": "aa",
|
||||||
},
|
},
|
||||||
Receiver: "prod",
|
Receiver: "prod",
|
||||||
|
GroupKey: "{}/{env=\"prod\"}:{alertname=\"HighErrorRate\", cluster=\"aa\", service=\"api\"}",
|
||||||
|
RouteID: "{}/{env=\"prod\"}/1",
|
||||||
},
|
},
|
||||||
&AlertGroup{
|
&AlertGroup{
|
||||||
Alerts: []*types.Alert{inputAlerts[4]},
|
Alerts: []*types.Alert{inputAlerts[4]},
|
||||||
|
@ -465,6 +471,8 @@ route:
|
||||||
"cluster": "bb",
|
"cluster": "bb",
|
||||||
},
|
},
|
||||||
Receiver: "prod",
|
Receiver: "prod",
|
||||||
|
GroupKey: "{}/{env=\"prod\"}:{alertname=\"HighErrorRate\", cluster=\"bb\", service=\"api\"}",
|
||||||
|
RouteID: "{}/{env=\"prod\"}/1",
|
||||||
},
|
},
|
||||||
&AlertGroup{
|
&AlertGroup{
|
||||||
Alerts: []*types.Alert{inputAlerts[5]},
|
Alerts: []*types.Alert{inputAlerts[5]},
|
||||||
|
@ -474,6 +482,8 @@ route:
|
||||||
"cluster": "bb",
|
"cluster": "bb",
|
||||||
},
|
},
|
||||||
Receiver: "kafka",
|
Receiver: "kafka",
|
||||||
|
GroupKey: "{}/{kafka=\"yes\"}:{alertname=\"HighLatency\", cluster=\"bb\", service=\"db\"}",
|
||||||
|
RouteID: "{}/{kafka=\"yes\"}/2",
|
||||||
},
|
},
|
||||||
&AlertGroup{
|
&AlertGroup{
|
||||||
Alerts: []*types.Alert{inputAlerts[5]},
|
Alerts: []*types.Alert{inputAlerts[5]},
|
||||||
|
@ -483,6 +493,8 @@ route:
|
||||||
"cluster": "bb",
|
"cluster": "bb",
|
||||||
},
|
},
|
||||||
Receiver: "prod",
|
Receiver: "prod",
|
||||||
|
GroupKey: "{}/{env=\"prod\"}:{alertname=\"HighLatency\", cluster=\"bb\", service=\"db\"}",
|
||||||
|
RouteID: "{}/{env=\"prod\"}/1",
|
||||||
},
|
},
|
||||||
}, alertGroups)
|
}, alertGroups)
|
||||||
require.Equal(t, map[model.Fingerprint][]string{
|
require.Equal(t, map[model.Fingerprint][]string{
|
||||||
|
|
|
@ -22,6 +22,7 @@ type alias AlertStatus =
|
||||||
{ state : State
|
{ state : State
|
||||||
, silencedBy : List String
|
, silencedBy : List String
|
||||||
, inhibitedBy : List String
|
, inhibitedBy : List String
|
||||||
|
, mutedBy : List String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ decoder =
|
||||||
|> required "state" stateDecoder
|
|> required "state" stateDecoder
|
||||||
|> required "silencedBy" (Decode.list Decode.string)
|
|> required "silencedBy" (Decode.list Decode.string)
|
||||||
|> required "inhibitedBy" (Decode.list Decode.string)
|
|> required "inhibitedBy" (Decode.list Decode.string)
|
||||||
|
|> required "mutedBy" (Decode.list Decode.string)
|
||||||
|
|
||||||
|
|
||||||
encoder : AlertStatus -> Encode.Value
|
encoder : AlertStatus -> Encode.Value
|
||||||
|
@ -45,6 +47,7 @@ encoder model =
|
||||||
[ ( "state", stateEncoder model.state )
|
[ ( "state", stateEncoder model.state )
|
||||||
, ( "silencedBy", Encode.list Encode.string model.silencedBy )
|
, ( "silencedBy", Encode.list Encode.string model.silencedBy )
|
||||||
, ( "inhibitedBy", Encode.list Encode.string model.inhibitedBy )
|
, ( "inhibitedBy", Encode.list Encode.string model.inhibitedBy )
|
||||||
|
, ( "mutedBy", Encode.list Encode.string model.mutedBy )
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ type alias Filter =
|
||||||
, receiver : Maybe String
|
, receiver : Maybe String
|
||||||
, showSilenced : Maybe Bool
|
, showSilenced : Maybe Bool
|
||||||
, showInhibited : Maybe Bool
|
, showInhibited : Maybe Bool
|
||||||
|
, showMuted : Maybe Bool
|
||||||
, showActive : Maybe Bool
|
, showActive : Maybe Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +47,7 @@ nullFilter =
|
||||||
, receiver = Nothing
|
, receiver = Nothing
|
||||||
, showSilenced = Nothing
|
, showSilenced = Nothing
|
||||||
, showInhibited = Nothing
|
, showInhibited = Nothing
|
||||||
|
, showMuted = Nothing
|
||||||
, showActive = Nothing
|
, showActive = Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,11 +58,12 @@ generateQueryParam name =
|
||||||
|
|
||||||
|
|
||||||
toUrl : String -> Filter -> String
|
toUrl : String -> Filter -> String
|
||||||
toUrl baseUrl { receiver, customGrouping, showSilenced, showInhibited, showActive, text, group } =
|
toUrl baseUrl { receiver, customGrouping, showSilenced, showInhibited, showMuted, showActive, text, group } =
|
||||||
let
|
let
|
||||||
parts =
|
parts =
|
||||||
[ ( "silenced", Maybe.withDefault False showSilenced |> boolToString |> Just )
|
[ ( "silenced", Maybe.withDefault False showSilenced |> boolToString |> Just )
|
||||||
, ( "inhibited", Maybe.withDefault False showInhibited |> boolToString |> Just )
|
, ( "inhibited", Maybe.withDefault False showInhibited |> boolToString |> Just )
|
||||||
|
, ( "muted", Maybe.withDefault False showMuted |> boolToString |> Just )
|
||||||
, ( "active", Maybe.withDefault True showActive |> boolToString |> Just )
|
, ( "active", Maybe.withDefault True showActive |> boolToString |> Just )
|
||||||
, ( "filter", emptyToNothing text )
|
, ( "filter", emptyToNothing text )
|
||||||
, ( "receiver", emptyToNothing receiver )
|
, ( "receiver", emptyToNothing receiver )
|
||||||
|
@ -81,7 +84,7 @@ toUrl baseUrl { receiver, customGrouping, showSilenced, showInhibited, showActiv
|
||||||
|
|
||||||
|
|
||||||
generateAPIQueryString : Filter -> String
|
generateAPIQueryString : Filter -> String
|
||||||
generateAPIQueryString { receiver, showSilenced, showInhibited, showActive, text, group } =
|
generateAPIQueryString { receiver, showSilenced, showInhibited, showMuted, showActive, text, group } =
|
||||||
let
|
let
|
||||||
filter_ =
|
filter_ =
|
||||||
case parseFilter (Maybe.withDefault "" text) of
|
case parseFilter (Maybe.withDefault "" text) of
|
||||||
|
@ -95,6 +98,7 @@ generateAPIQueryString { receiver, showSilenced, showInhibited, showActive, text
|
||||||
filter_
|
filter_
|
||||||
++ [ ( "silenced", Maybe.withDefault False showSilenced |> boolToString |> Just )
|
++ [ ( "silenced", Maybe.withDefault False showSilenced |> boolToString |> Just )
|
||||||
, ( "inhibited", Maybe.withDefault False showInhibited |> boolToString |> Just )
|
, ( "inhibited", Maybe.withDefault False showInhibited |> boolToString |> Just )
|
||||||
|
, ( "muted", Maybe.withDefault False showMuted |> boolToString |> Just )
|
||||||
, ( "active", Maybe.withDefault True showActive |> boolToString |> Just )
|
, ( "active", Maybe.withDefault True showActive |> boolToString |> Just )
|
||||||
, ( "receiver", emptyToNothing receiver )
|
, ( "receiver", emptyToNothing receiver )
|
||||||
, ( "group", group )
|
, ( "group", group )
|
||||||
|
@ -375,6 +379,7 @@ silencePreviewFilter apiMatchers =
|
||||||
|> Just
|
|> Just
|
||||||
, showSilenced = Just True
|
, showSilenced = Just True
|
||||||
, showInhibited = Just True
|
, showInhibited = Just True
|
||||||
|
, showMuted = Just True
|
||||||
, showActive = Just True
|
, showActive = Just True
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ view labels maybeActiveId alert =
|
||||||
text ""
|
text ""
|
||||||
, silenceButton alert
|
, silenceButton alert
|
||||||
, inhibitedIcon alert
|
, inhibitedIcon alert
|
||||||
|
, mutedIcon alert
|
||||||
, linkButton alert
|
, linkButton alert
|
||||||
]
|
]
|
||||||
, if maybeActiveId == Just alert.fingerprint then
|
, if maybeActiveId == Just alert.fingerprint then
|
||||||
|
@ -145,8 +146,8 @@ inhibitedIcon : GettableAlert -> Html Msg
|
||||||
inhibitedIcon alert =
|
inhibitedIcon alert =
|
||||||
case List.head alert.status.inhibitedBy of
|
case List.head alert.status.inhibitedBy of
|
||||||
Just _ ->
|
Just _ ->
|
||||||
a
|
span
|
||||||
[ class "btn btn-outline-info border-0 text-info"
|
[ class "btn btn-outline-danger border-0"
|
||||||
]
|
]
|
||||||
[ i [ class "fa fa-eye-slash mr-2" ] []
|
[ i [ class "fa fa-eye-slash mr-2" ] []
|
||||||
, text "Inhibited"
|
, text "Inhibited"
|
||||||
|
@ -154,3 +155,18 @@ inhibitedIcon alert =
|
||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
text ""
|
text ""
|
||||||
|
|
||||||
|
|
||||||
|
mutedIcon : GettableAlert -> Html Msg
|
||||||
|
mutedIcon alert =
|
||||||
|
case List.head alert.status.mutedBy of
|
||||||
|
Just _ ->
|
||||||
|
span
|
||||||
|
[ class "btn btn-outline-danger border-0"
|
||||||
|
]
|
||||||
|
[ i [ class "fa fa-bell-slash mr-2" ] []
|
||||||
|
, text "Muted"
|
||||||
|
]
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
text ""
|
||||||
|
|
|
@ -25,5 +25,6 @@ alertsParser =
|
||||||
<?> Query.string "receiver"
|
<?> Query.string "receiver"
|
||||||
<?> maybeBoolParam "silenced"
|
<?> maybeBoolParam "silenced"
|
||||||
<?> maybeBoolParam "inhibited"
|
<?> maybeBoolParam "inhibited"
|
||||||
|
<?> maybeBoolParam "muted"
|
||||||
<?> maybeBoolParam "active"
|
<?> maybeBoolParam "active"
|
||||||
|> map Filter
|
|> map Filter
|
||||||
|
|
|
@ -24,6 +24,7 @@ type AlertListMsg
|
||||||
| MsgForGroupBar GroupBar.Msg
|
| MsgForGroupBar GroupBar.Msg
|
||||||
| ToggleSilenced Bool
|
| ToggleSilenced Bool
|
||||||
| ToggleInhibited Bool
|
| ToggleInhibited Bool
|
||||||
|
| ToggleMuted Bool
|
||||||
| SetActive (Maybe String)
|
| SetActive (Maybe String)
|
||||||
| ActiveGroups Int
|
| ActiveGroups Int
|
||||||
| SetTab Tab
|
| SetTab Tab
|
||||||
|
|
|
@ -120,6 +120,11 @@ update msg ({ groupBar, alerts, filterBar, receiverBar, alertGroups } as model)
|
||||||
, Navigation.pushUrl model.key (filteredUrl { filter | showInhibited = Just showInhibited })
|
, Navigation.pushUrl model.key (filteredUrl { filter | showInhibited = Just showInhibited })
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ToggleMuted showMuted ->
|
||||||
|
( model
|
||||||
|
, Navigation.pushUrl model.key (filteredUrl { filter | showMuted = Just showMuted })
|
||||||
|
)
|
||||||
|
|
||||||
SetTab tab ->
|
SetTab tab ->
|
||||||
( { model | tab = tab }, Cmd.none )
|
( { model | tab = tab }, Cmd.none )
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ view { alertGroups, groupBar, filterBar, receiverBar, tab, activeId, activeGroup
|
||||||
|> Html.map (MsgForReceiverBar >> MsgForAlertList)
|
|> Html.map (MsgForReceiverBar >> MsgForAlertList)
|
||||||
, renderCheckbox "Silenced" filter.showSilenced ToggleSilenced
|
, renderCheckbox "Silenced" filter.showSilenced ToggleSilenced
|
||||||
, renderCheckbox "Inhibited" filter.showInhibited ToggleInhibited
|
, renderCheckbox "Inhibited" filter.showInhibited ToggleInhibited
|
||||||
|
, renderCheckbox "Muted" filter.showMuted ToggleMuted
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
, div [ class "card-block" ]
|
, div [ class "card-block" ]
|
||||||
|
|
|
@ -9,6 +9,6 @@ silenceListParser : Parser (Filter -> a) a
|
||||||
silenceListParser =
|
silenceListParser =
|
||||||
map
|
map
|
||||||
(\t ->
|
(\t ->
|
||||||
Filter t Nothing False Nothing Nothing Nothing Nothing
|
Filter t Nothing False Nothing Nothing Nothing Nothing Nothing
|
||||||
)
|
)
|
||||||
(s "silences" <?> Query.string "filter")
|
(s "silences" <?> Query.string "filter")
|
||||||
|
|
|
@ -33,34 +33,38 @@ parseMatcher =
|
||||||
toUrl : Test
|
toUrl : Test
|
||||||
toUrl =
|
toUrl =
|
||||||
describe "toUrl"
|
describe "toUrl"
|
||||||
[ test "should not render keys with Nothing value except the silenced, inhibited, and active parameters, which default to false, false, true, respectively." <|
|
[ test "should not render keys with Nothing value except the silenced, inhibited, muted and active parameters, which default to false, false, false, true, respectively." <|
|
||||||
\() ->
|
\() ->
|
||||||
Expect.equal "/alerts?silenced=false&inhibited=false&active=true"
|
Expect.equal "/alerts?silenced=false&inhibited=false&muted=false&active=true"
|
||||||
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = False, text = Nothing, showSilenced = Nothing, showInhibited = Nothing, showActive = Nothing })
|
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = False, text = Nothing, showSilenced = Nothing, showInhibited = Nothing, showMuted = Nothing, showActive = Nothing })
|
||||||
, test "should not render filter key with empty value" <|
|
, test "should not render filter key with empty value" <|
|
||||||
\() ->
|
\() ->
|
||||||
Expect.equal "/alerts?silenced=false&inhibited=false&active=true"
|
Expect.equal "/alerts?silenced=false&inhibited=false&muted=false&active=true"
|
||||||
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = False, text = Just "", showSilenced = Nothing, showInhibited = Nothing, showActive = Nothing })
|
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = False, text = Just "", showSilenced = Nothing, showInhibited = Nothing, showMuted = Nothing, showActive = Nothing })
|
||||||
, test "should render filter key with values" <|
|
, test "should render filter key with values" <|
|
||||||
\() ->
|
\() ->
|
||||||
Expect.equal "/alerts?silenced=false&inhibited=false&active=true&filter=%7Bfoo%3D%22bar%22%2C%20baz%3D~%22quux.*%22%7D"
|
Expect.equal "/alerts?silenced=false&inhibited=false&muted=false&active=true&filter=%7Bfoo%3D%22bar%22%2C%20baz%3D~%22quux.*%22%7D"
|
||||||
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = False, text = Just "{foo=\"bar\", baz=~\"quux.*\"}", showSilenced = Nothing, showInhibited = Nothing, showActive = Nothing })
|
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = False, text = Just "{foo=\"bar\", baz=~\"quux.*\"}", showSilenced = Nothing, showInhibited = Nothing, showMuted = Nothing, showActive = Nothing })
|
||||||
, test "should render silenced key with bool" <|
|
, test "should render silenced key with bool" <|
|
||||||
\() ->
|
\() ->
|
||||||
Expect.equal "/alerts?silenced=true&inhibited=false&active=true"
|
Expect.equal "/alerts?silenced=true&inhibited=false&muted=false&active=true"
|
||||||
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = False, text = Nothing, showSilenced = Just True, showInhibited = Nothing, showActive = Nothing })
|
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = False, text = Nothing, showSilenced = Just True, showInhibited = Nothing, showMuted = Nothing, showActive = Nothing })
|
||||||
, test "should render inhibited key with bool" <|
|
, test "should render inhibited key with bool" <|
|
||||||
\() ->
|
\() ->
|
||||||
Expect.equal "/alerts?silenced=false&inhibited=true&active=true"
|
Expect.equal "/alerts?silenced=false&inhibited=true&muted=false&active=true"
|
||||||
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = False, text = Nothing, showSilenced = Nothing, showInhibited = Just True, showActive = Nothing })
|
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = False, text = Nothing, showSilenced = Nothing, showInhibited = Just True, showMuted = Nothing, showActive = Nothing })
|
||||||
|
, test "should render muted key with bool" <|
|
||||||
|
\() ->
|
||||||
|
Expect.equal "/alerts?silenced=false&inhibited=false&muted=true&active=true"
|
||||||
|
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = False, text = Nothing, showSilenced = Nothing, showInhibited = Nothing, showMuted = Just True, showActive = Nothing })
|
||||||
, test "should render active key with bool" <|
|
, test "should render active key with bool" <|
|
||||||
\() ->
|
\() ->
|
||||||
Expect.equal "/alerts?silenced=false&inhibited=false&active=false"
|
Expect.equal "/alerts?silenced=false&inhibited=false&muted=false&active=false"
|
||||||
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = False, text = Nothing, showSilenced = Nothing, showInhibited = Nothing, showActive = Just False })
|
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = False, text = Nothing, showSilenced = Nothing, showInhibited = Nothing, showMuted = Nothing, showActive = Just False })
|
||||||
, test "should add customGrouping key" <|
|
, test "should add customGrouping key" <|
|
||||||
\() ->
|
\() ->
|
||||||
Expect.equal "/alerts?silenced=false&inhibited=false&active=true&customGrouping=true"
|
Expect.equal "/alerts?silenced=false&inhibited=false&muted=false&active=true&customGrouping=true"
|
||||||
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = True, text = Nothing, showSilenced = Nothing, showInhibited = Nothing, showActive = Nothing })
|
(Utils.Filter.toUrl "/alerts" { receiver = Nothing, group = Nothing, customGrouping = True, text = Nothing, showSilenced = Nothing, showInhibited = Nothing, showMuted = Nothing, showActive = Nothing })
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue