ui: Move /status & /silences to API v2

This patch makes the Alertmanager UI (/status & /silences) use the
api/v2 endpoint. In addition it adds logic to generate the elm side data
model based on the OpenAPI specification.

Signed-off-by: Max Leonard Inden <IndenML@gmail.com>
This commit is contained in:
Max Leonard Inden 2018-11-08 17:46:04 +00:00
parent 19dad7c8d5
commit e4e053b18e
No known key found for this signature in database
GPG Key ID: 5403C5464810BC26
78 changed files with 3093 additions and 1124 deletions

View File

@ -13,7 +13,7 @@ script:
# test front-end
- make clean
- cd ui/app/ && make && cd ../..
- make assets
- make assets apiv2
- git diff --exit-code
# test back-end
- make

View File

@ -29,7 +29,7 @@ assets: ui/app/script.js ui/app/index.html ui/app/lib template/default.tmpl
cd $(PREFIX)/asset && $(GO) generate
@$(GOFMT) -w ./asset
ui/app/script.js: $(shell find ui/app/src -iname *.elm)
ui/app/script.js: $(shell find ui/app/src -iname *.elm) api/v2/openapi.yaml
cd $(FRONTEND_DIR) && $(MAKE) script.js
.PHONY: proto
@ -56,6 +56,7 @@ test/with_api_v2/api_v2_client/models test/with_api_v2/api_v2_client/client: api
.PHONY: clean
clean:
rm -f asset/assets_vfsdata.go
rm -r api/v2/models api/v2/restapi test/with_api_v2/api_v2_client/models test/with_api_v2/api_v2_client/client
cd $(FRONTEND_DIR) && $(MAKE) clean
.PHONY: test

View File

@ -39,6 +39,7 @@ import (
"github.com/prometheus/alertmanager/types"
prometheus_model "github.com/prometheus/common/model"
"github.com/prometheus/common/version"
"github.com/prometheus/prometheus/pkg/labels"
"github.com/go-kit/kit/log"
@ -54,6 +55,7 @@ type API struct {
silences *silence.Silences
alerts provider.Alerts
getAlertStatus getAlertStatusFn
uptime time.Time
// mtx protects resolveTimeout, alertmanagerConfig and route.
mtx sync.RWMutex
@ -78,6 +80,7 @@ func NewAPI(alerts provider.Alerts, sf getAlertStatusFn, silences *silence.Silen
peer: peer,
silences: silences,
logger: l,
uptime: time.Now(),
}
// load embedded swagger file
@ -122,16 +125,33 @@ func (api *API) getStatusHandler(params general_ops.GetStatusParams) middleware.
name := api.peer.Name()
status := api.peer.Status()
original := api.alertmanagerConfig.String()
uptime := strfmt.DateTime(api.uptime)
resp := open_api_models.AlertmanagerStatus{
Name: &name,
StatusInCluster: &status,
Peers: []*open_api_models.PeerStatus{},
Uptime: &uptime,
VersionInfo: &open_api_models.VersionInfo{
Version: &version.Version,
Revision: &version.Revision,
Branch: &version.Branch,
BuildUser: &version.BuildUser,
BuildDate: &version.BuildDate,
GoVersion: &version.GoVersion,
},
Config: &open_api_models.AlertmanagerConfig{
Original: &original,
},
Cluster: &open_api_models.ClusterStatus{
Name: &name,
Status: &status,
Peers: []*open_api_models.PeerStatus{},
},
}
for _, n := range api.peer.Peers() {
resp.Peers = append(resp.Peers, &open_api_models.PeerStatus{
Name: n.Name,
Address: n.Address(),
address := n.Address()
resp.Cluster.Peers = append(resp.Cluster.Peers, &open_api_models.PeerStatus{
Name: &n.Name,
Address: &address,
})
}
@ -144,7 +164,7 @@ func (api *API) getReceiversHandler(params receiver_ops.GetReceiversParams) midd
receivers := make([]*open_api_models.Receiver, 0, len(api.alertmanagerConfig.Receivers))
for _, r := range api.alertmanagerConfig.Receivers {
receivers = append(receivers, &open_api_models.Receiver{Name: r.Name})
receivers = append(receivers, &open_api_models.Receiver{Name: &r.Name})
}
return receiver_ops.NewGetReceiversOK().WithPayload(receivers)
@ -196,7 +216,7 @@ 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))
for _, r := range routes {
receivers = append(receivers, &open_api_models.Receiver{Name: r.RouteOpts.Receiver})
receivers = append(receivers, &open_api_models.Receiver{Name: &r.RouteOpts.Receiver})
}
if receiverFilter != nil && !receiversMatchFilter(receivers, receiverFilter) {
@ -230,6 +250,8 @@ func (api *API) getAlertsHandler(params alert_ops.GetAlertsParams) middleware.Re
continue
}
state := string(status.State)
alert := open_api_models.Alert{
Annotations: modelLabelSetToAPILabelSet(a.Annotations),
EndsAt: strfmt.DateTime(a.EndsAt),
@ -239,7 +261,7 @@ func (api *API) getAlertsHandler(params alert_ops.GetAlertsParams) middleware.Re
Receivers: receivers,
StartsAt: strfmt.DateTime(a.StartsAt),
Status: &open_api_models.AlertStatus{
State: string(status.State),
State: &state,
SilencedBy: status.SilencedBy,
InhibitedBy: status.InhibitedBy,
},
@ -368,7 +390,7 @@ func apiLabelSetToModelLabelSet(apiLabelSet open_api_models.LabelSet) prometheus
func receiversMatchFilter(receivers []*open_api_models.Receiver, filter *regexp.Regexp) bool {
for _, r := range receivers {
if filter.MatchString(string(r.Name)) {
if filter.MatchString(string(*r.Name)) {
return true
}
}
@ -447,7 +469,7 @@ func (api *API) getSilencesHandler(params silence_ops.GetSilencesParams) middlew
func silenceMatchesFilterLabels(s open_api_models.Silence, matchers []*labels.Matcher) bool {
sms := make(map[string]string)
for _, m := range s.Matchers {
sms[m.Name] = m.Value
sms[*m.Name] = *m.Value
}
return matchFilterLabels(matchers, sms)
@ -485,28 +507,34 @@ func (api *API) deleteSilenceHandler(params silence_ops.DeleteSilenceParams) mid
}
func silenceFromProto(s *silencepb.Silence) (open_api_models.Silence, error) {
start := strfmt.DateTime(s.StartsAt)
end := strfmt.DateTime(s.EndsAt)
updated := strfmt.DateTime(s.UpdatedAt)
state := string(types.CalcSilenceState(s.StartsAt, s.EndsAt))
sil := open_api_models.Silence{
ID: s.Id,
StartsAt: strfmt.DateTime(s.StartsAt),
EndsAt: strfmt.DateTime(s.EndsAt),
UpdatedAt: strfmt.DateTime(s.UpdatedAt),
StartsAt: &start,
EndsAt: &end,
UpdatedAt: &updated,
Status: &open_api_models.SilenceStatus{
State: string(types.CalcSilenceState(s.StartsAt, s.EndsAt)),
State: &state,
},
Comment: s.Comment,
CreatedBy: s.CreatedBy,
Comment: &s.Comment,
CreatedBy: &s.CreatedBy,
}
for _, m := range s.Matchers {
matcher := &open_api_models.Matcher{
Name: m.Name,
Value: m.Pattern,
Regex: m.Pattern,
Name: &m.Name,
Value: &m.Pattern,
}
switch m.Type {
case silencepb.Matcher_EQUAL:
f := false
matcher.IsRegex = &f
case silencepb.Matcher_REGEXP:
matcher.IsRegex = true
t := true
matcher.IsRegex = &t
default:
return sil, fmt.Errorf(
"unknown matcher type for matcher '%v' in silence '%v'",
@ -554,21 +582,26 @@ func (api *API) postSilencesHandler(params silence_ops.PostSilencesParams) middl
}
func silenceToProto(s *open_api_models.Silence) (*silencepb.Silence, error) {
// updatedAt is optional, make sure to check if nil.
updated := time.Time{}
if s.UpdatedAt != nil {
updated = time.Time(*s.UpdatedAt)
}
sil := &silencepb.Silence{
Id: s.ID,
StartsAt: time.Time(s.StartsAt),
EndsAt: time.Time(s.EndsAt),
UpdatedAt: time.Time(s.UpdatedAt),
Comment: s.Comment,
CreatedBy: s.CreatedBy,
StartsAt: time.Time(*s.StartsAt),
EndsAt: time.Time(*s.EndsAt),
UpdatedAt: updated,
Comment: *s.Comment,
CreatedBy: *s.CreatedBy,
}
for _, m := range s.Matchers {
matcher := &silencepb.Matcher{
Name: m.Name,
Pattern: m.Value,
Name: *m.Name,
Pattern: *m.Value,
Type: silencepb.Matcher_EQUAL,
}
if m.IsRegex {
if *m.IsRegex {
matcher.Type = silencepb.Matcher_REGEXP
}
sil.Matchers = append(sil.Matchers, matcher)

View File

@ -6,7 +6,6 @@ package models
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"strconv"
strfmt "github.com/go-openapi/strfmt"
@ -35,7 +34,8 @@ type Alert struct {
GeneratorURL strfmt.URI `json:"generatorURL,omitempty"`
// labels
Labels LabelSet `json:"labels,omitempty"`
// Required: true
Labels LabelSet `json:"labels"`
// receivers
Receivers []*Receiver `json:"receivers"`
@ -138,10 +138,6 @@ func (m *Alert) validateGeneratorURL(formats strfmt.Registry) error {
func (m *Alert) 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")
@ -238,96 +234,3 @@ func (m *Alert) UnmarshalBinary(b []byte) error {
*m = res
return nil
}
// AlertStatus alert status
// swagger:model AlertStatus
type AlertStatus struct {
// inhibited by
InhibitedBy []string `json:"inhibitedBy"`
// silenced by
SilencedBy []string `json:"silencedBy"`
// state
// Enum: [unprocessed active suppressed]
State string `json:"state,omitempty"`
}
// Validate validates this alert status
func (m *AlertStatus) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateState(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
var alertStatusTypeStatePropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["unprocessed","active","suppressed"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
alertStatusTypeStatePropEnum = append(alertStatusTypeStatePropEnum, v)
}
}
const (
// AlertStatusStateUnprocessed captures enum value "unprocessed"
AlertStatusStateUnprocessed string = "unprocessed"
// AlertStatusStateActive captures enum value "active"
AlertStatusStateActive string = "active"
// AlertStatusStateSuppressed captures enum value "suppressed"
AlertStatusStateSuppressed string = "suppressed"
)
// prop value enum
func (m *AlertStatus) validateStateEnum(path, location string, value string) error {
if err := validate.Enum(path, location, value, alertStatusTypeStatePropEnum); err != nil {
return err
}
return nil
}
func (m *AlertStatus) validateState(formats strfmt.Registry) error {
if swag.IsZero(m.State) { // not required
return nil
}
// value enum
if err := m.validateStateEnum("status"+"."+"state", "body", m.State); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *AlertStatus) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AlertStatus) UnmarshalBinary(b []byte) error {
var res AlertStatus
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -0,0 +1,138 @@
// Code generated by go-swagger; DO NOT EDIT.
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 (
"encoding/json"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// AlertStatus alert status
// swagger:model alertStatus
type AlertStatus struct {
// inhibited by
// Required: true
InhibitedBy []string `json:"inhibitedBy"`
// silenced by
// Required: true
SilencedBy []string `json:"silencedBy"`
// state
// Required: true
// Enum: [unprocessed active suppressed]
State *string `json:"state"`
}
// Validate validates this alert status
func (m *AlertStatus) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateInhibitedBy(formats); err != nil {
res = append(res, err)
}
if err := m.validateSilencedBy(formats); err != nil {
res = append(res, err)
}
if err := m.validateState(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *AlertStatus) validateInhibitedBy(formats strfmt.Registry) error {
if err := validate.Required("inhibitedBy", "body", m.InhibitedBy); err != nil {
return err
}
return nil
}
func (m *AlertStatus) validateSilencedBy(formats strfmt.Registry) error {
if err := validate.Required("silencedBy", "body", m.SilencedBy); err != nil {
return err
}
return nil
}
var alertStatusTypeStatePropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["unprocessed","active","suppressed"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
alertStatusTypeStatePropEnum = append(alertStatusTypeStatePropEnum, v)
}
}
const (
// AlertStatusStateUnprocessed captures enum value "unprocessed"
AlertStatusStateUnprocessed string = "unprocessed"
// AlertStatusStateActive captures enum value "active"
AlertStatusStateActive string = "active"
// AlertStatusStateSuppressed captures enum value "suppressed"
AlertStatusStateSuppressed string = "suppressed"
)
// prop value enum
func (m *AlertStatus) validateStateEnum(path, location string, value string) error {
if err := validate.Enum(path, location, value, alertStatusTypeStatePropEnum); err != nil {
return err
}
return nil
}
func (m *AlertStatus) validateState(formats strfmt.Registry) error {
if err := validate.Required("state", "body", m.State); err != nil {
return err
}
// value enum
if err := m.validateStateEnum("state", "body", *m.State); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *AlertStatus) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AlertStatus) UnmarshalBinary(b []byte) error {
var res AlertStatus
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -0,0 +1,64 @@
// Code generated by go-swagger; DO NOT EDIT.
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 (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// AlertmanagerConfig alertmanager config
// swagger:model alertmanagerConfig
type AlertmanagerConfig struct {
// original
// Required: true
Original *string `json:"original"`
}
// Validate validates this alertmanager config
func (m *AlertmanagerConfig) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateOriginal(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *AlertmanagerConfig) validateOriginal(formats strfmt.Registry) error {
if err := validate.Required("original", "body", m.Original); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *AlertmanagerConfig) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AlertmanagerConfig) UnmarshalBinary(b []byte) error {
var res AlertmanagerConfig
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -6,8 +6,6 @@ package models
// 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"
@ -19,33 +17,41 @@ import (
// swagger:model alertmanagerStatus
type AlertmanagerStatus struct {
// name
// cluster
// Required: true
Name *string `json:"name"`
Cluster *ClusterStatus `json:"cluster"`
// peers
// config
// Required: true
// Minimum: 0
Peers []*PeerStatus `json:"peers"`
Config *AlertmanagerConfig `json:"config"`
// status in cluster
// uptime
// Required: true
StatusInCluster *string `json:"statusInCluster"`
// Format: date-time
Uptime *strfmt.DateTime `json:"uptime"`
// version info
// Required: true
VersionInfo *VersionInfo `json:"versionInfo"`
}
// Validate validates this alertmanager status
func (m *AlertmanagerStatus) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateName(formats); err != nil {
if err := m.validateCluster(formats); err != nil {
res = append(res, err)
}
if err := m.validatePeers(formats); err != nil {
if err := m.validateConfig(formats); err != nil {
res = append(res, err)
}
if err := m.validateStatusInCluster(formats); err != nil {
if err := m.validateUptime(formats); err != nil {
res = append(res, err)
}
if err := m.validateVersionInfo(formats); err != nil {
res = append(res, err)
}
@ -55,46 +61,70 @@ func (m *AlertmanagerStatus) Validate(formats strfmt.Registry) error {
return nil
}
func (m *AlertmanagerStatus) validateName(formats strfmt.Registry) error {
func (m *AlertmanagerStatus) validateCluster(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
if err := validate.Required("cluster", "body", m.Cluster); err != nil {
return err
}
return nil
}
func (m *AlertmanagerStatus) validatePeers(formats strfmt.Registry) error {
if err := validate.Required("peers", "body", m.Peers); err != nil {
return err
}
for i := 0; i < len(m.Peers); i++ {
if swag.IsZero(m.Peers[i]) { // not required
continue
}
if m.Peers[i] != nil {
if err := m.Peers[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("peers" + "." + strconv.Itoa(i))
}
return err
if m.Cluster != nil {
if err := m.Cluster.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("cluster")
}
return err
}
}
return nil
}
func (m *AlertmanagerStatus) validateStatusInCluster(formats strfmt.Registry) error {
func (m *AlertmanagerStatus) validateConfig(formats strfmt.Registry) error {
if err := validate.Required("statusInCluster", "body", m.StatusInCluster); err != nil {
if err := validate.Required("config", "body", m.Config); err != nil {
return err
}
if m.Config != nil {
if err := m.Config.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("config")
}
return err
}
}
return nil
}
func (m *AlertmanagerStatus) validateUptime(formats strfmt.Registry) error {
if err := validate.Required("uptime", "body", m.Uptime); err != nil {
return err
}
if err := validate.FormatOf("uptime", "body", "date-time", m.Uptime.String(), formats); err != nil {
return err
}
return nil
}
func (m *AlertmanagerStatus) validateVersionInfo(formats strfmt.Registry) error {
if err := validate.Required("versionInfo", "body", m.VersionInfo); err != nil {
return err
}
if m.VersionInfo != nil {
if err := m.VersionInfo.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("versionInfo")
}
return err
}
}
return nil
}

View File

@ -0,0 +1,117 @@
// Code generated by go-swagger; DO NOT EDIT.
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"
"github.com/go-openapi/validate"
)
// ClusterStatus cluster status
// swagger:model clusterStatus
type ClusterStatus struct {
// name
// Required: true
Name *string `json:"name"`
// peers
// Required: true
// Minimum: 0
Peers []*PeerStatus `json:"peers"`
// status
// Required: true
Status *string `json:"status"`
}
// Validate validates this cluster status
func (m *ClusterStatus) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateName(formats); err != nil {
res = append(res, err)
}
if err := m.validatePeers(formats); err != nil {
res = append(res, err)
}
if err := m.validateStatus(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ClusterStatus) validateName(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
return err
}
return nil
}
func (m *ClusterStatus) validatePeers(formats strfmt.Registry) error {
if err := validate.Required("peers", "body", m.Peers); err != nil {
return err
}
for i := 0; i < len(m.Peers); i++ {
if swag.IsZero(m.Peers[i]) { // not required
continue
}
if m.Peers[i] != nil {
if err := m.Peers[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("peers" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *ClusterStatus) validateStatus(formats strfmt.Registry) error {
if err := validate.Required("status", "body", m.Status); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *ClusterStatus) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ClusterStatus) UnmarshalBinary(b []byte) error {
var res ClusterStatus
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -8,7 +8,9 @@ package models
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// Matcher matcher
@ -16,20 +18,64 @@ import (
type Matcher struct {
// is regex
IsRegex bool `json:"isRegex,omitempty"`
// Required: true
IsRegex *bool `json:"isRegex"`
// name
Name string `json:"name,omitempty"`
// regex
Regex string `json:"regex,omitempty"`
// Required: true
Name *string `json:"name"`
// value
Value string `json:"value,omitempty"`
// Required: true
Value *string `json:"value"`
}
// Validate validates this matcher
func (m *Matcher) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateIsRegex(formats); err != nil {
res = append(res, err)
}
if err := m.validateName(formats); err != nil {
res = append(res, err)
}
if err := m.validateValue(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *Matcher) validateIsRegex(formats strfmt.Registry) error {
if err := validate.Required("isRegex", "body", m.IsRegex); err != nil {
return err
}
return nil
}
func (m *Matcher) validateName(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
return err
}
return nil
}
func (m *Matcher) validateValue(formats strfmt.Registry) error {
if err := validate.Required("value", "body", m.Value); err != nil {
return err
}
return nil
}

View File

@ -8,7 +8,9 @@ package models
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// PeerStatus peer status
@ -16,14 +18,47 @@ import (
type PeerStatus struct {
// address
Address string `json:"address,omitempty"`
// Required: true
Address *string `json:"address"`
// name
Name string `json:"name,omitempty"`
// Required: true
Name *string `json:"name"`
}
// Validate validates this peer status
func (m *PeerStatus) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateAddress(formats); err != nil {
res = append(res, err)
}
if err := m.validateName(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *PeerStatus) validateAddress(formats strfmt.Registry) error {
if err := validate.Required("address", "body", m.Address); err != nil {
return err
}
return nil
}
func (m *PeerStatus) validateName(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
return err
}
return nil
}

View File

@ -8,7 +8,9 @@ package models
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// Receiver receiver
@ -16,11 +18,30 @@ import (
type Receiver struct {
// name
Name string `json:"name,omitempty"`
// Required: true
Name *string `json:"name"`
}
// Validate validates this receiver
func (m *Receiver) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateName(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *Receiver) validateName(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
return err
}
return nil
}

View File

@ -6,8 +6,6 @@ package models
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
@ -20,14 +18,17 @@ import (
type Silence struct {
// comment
Comment string `json:"comment,omitempty"`
// Required: true
Comment *string `json:"comment"`
// created by
CreatedBy string `json:"createdBy,omitempty"`
// Required: true
CreatedBy *string `json:"createdBy"`
// ends at
// Required: true
// Format: date-time
EndsAt strfmt.DateTime `json:"endsAt,omitempty"`
EndsAt *strfmt.DateTime `json:"endsAt"`
// id
ID string `json:"id,omitempty"`
@ -37,21 +38,30 @@ type Silence struct {
Matchers Matchers `json:"matchers"`
// starts at
// Required: true
// Format: date-time
StartsAt strfmt.DateTime `json:"startsAt,omitempty"`
StartsAt *strfmt.DateTime `json:"startsAt"`
// status
Status *SilenceStatus `json:"status,omitempty"`
// updated at
// Format: date-time
UpdatedAt strfmt.DateTime `json:"updatedAt,omitempty"`
UpdatedAt *strfmt.DateTime `json:"updatedAt,omitempty"`
}
// Validate validates this silence
func (m *Silence) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateComment(formats); err != nil {
res = append(res, err)
}
if err := m.validateCreatedBy(formats); err != nil {
res = append(res, err)
}
if err := m.validateEndsAt(formats); err != nil {
res = append(res, err)
}
@ -78,10 +88,28 @@ func (m *Silence) Validate(formats strfmt.Registry) error {
return nil
}
func (m *Silence) validateComment(formats strfmt.Registry) error {
if err := validate.Required("comment", "body", m.Comment); err != nil {
return err
}
return nil
}
func (m *Silence) validateCreatedBy(formats strfmt.Registry) error {
if err := validate.Required("createdBy", "body", m.CreatedBy); err != nil {
return err
}
return nil
}
func (m *Silence) validateEndsAt(formats strfmt.Registry) error {
if swag.IsZero(m.EndsAt) { // not required
return nil
if err := validate.Required("endsAt", "body", m.EndsAt); err != nil {
return err
}
if err := validate.FormatOf("endsAt", "body", "date-time", m.EndsAt.String(), formats); err != nil {
@ -109,8 +137,8 @@ func (m *Silence) validateMatchers(formats strfmt.Registry) error {
func (m *Silence) validateStartsAt(formats strfmt.Registry) error {
if swag.IsZero(m.StartsAt) { // not required
return nil
if err := validate.Required("startsAt", "body", m.StartsAt); err != nil {
return err
}
if err := validate.FormatOf("startsAt", "body", "date-time", m.StartsAt.String(), formats); err != nil {
@ -168,90 +196,3 @@ func (m *Silence) UnmarshalBinary(b []byte) error {
*m = res
return nil
}
// SilenceStatus silence status
// swagger:model SilenceStatus
type SilenceStatus struct {
// state
// Enum: [expired active pending]
State string `json:"state,omitempty"`
}
// Validate validates this silence status
func (m *SilenceStatus) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateState(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
var silenceStatusTypeStatePropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["expired","active","pending"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
silenceStatusTypeStatePropEnum = append(silenceStatusTypeStatePropEnum, v)
}
}
const (
// SilenceStatusStateExpired captures enum value "expired"
SilenceStatusStateExpired string = "expired"
// SilenceStatusStateActive captures enum value "active"
SilenceStatusStateActive string = "active"
// SilenceStatusStatePending captures enum value "pending"
SilenceStatusStatePending string = "pending"
)
// prop value enum
func (m *SilenceStatus) validateStateEnum(path, location string, value string) error {
if err := validate.Enum(path, location, value, silenceStatusTypeStatePropEnum); err != nil {
return err
}
return nil
}
func (m *SilenceStatus) validateState(formats strfmt.Registry) error {
if swag.IsZero(m.State) { // not required
return nil
}
// value enum
if err := m.validateStateEnum("status"+"."+"state", "body", m.State); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *SilenceStatus) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *SilenceStatus) UnmarshalBinary(b []byte) error {
var res SilenceStatus
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -0,0 +1,104 @@
// Code generated by go-swagger; DO NOT EDIT.
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 (
"encoding/json"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// SilenceStatus silence status
// swagger:model silenceStatus
type SilenceStatus struct {
// state
// Required: true
// Enum: [expired active pending]
State *string `json:"state"`
}
// Validate validates this silence status
func (m *SilenceStatus) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateState(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
var silenceStatusTypeStatePropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["expired","active","pending"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
silenceStatusTypeStatePropEnum = append(silenceStatusTypeStatePropEnum, v)
}
}
const (
// SilenceStatusStateExpired captures enum value "expired"
SilenceStatusStateExpired string = "expired"
// SilenceStatusStateActive captures enum value "active"
SilenceStatusStateActive string = "active"
// SilenceStatusStatePending captures enum value "pending"
SilenceStatusStatePending string = "pending"
)
// prop value enum
func (m *SilenceStatus) validateStateEnum(path, location string, value string) error {
if err := validate.Enum(path, location, value, silenceStatusTypeStatePropEnum); err != nil {
return err
}
return nil
}
func (m *SilenceStatus) validateState(formats strfmt.Registry) error {
if err := validate.Required("state", "body", m.State); err != nil {
return err
}
// value enum
if err := m.validateStateEnum("state", "body", *m.State); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *SilenceStatus) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *SilenceStatus) UnmarshalBinary(b []byte) error {
var res SilenceStatus
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -0,0 +1,149 @@
// Code generated by go-swagger; DO NOT EDIT.
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 (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// VersionInfo version info
// swagger:model versionInfo
type VersionInfo struct {
// branch
// Required: true
Branch *string `json:"branch"`
// build date
// Required: true
BuildDate *string `json:"buildDate"`
// build user
// Required: true
BuildUser *string `json:"buildUser"`
// go version
// Required: true
GoVersion *string `json:"goVersion"`
// revision
// Required: true
Revision *string `json:"revision"`
// version
// Required: true
Version *string `json:"version"`
}
// Validate validates this version info
func (m *VersionInfo) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateBranch(formats); err != nil {
res = append(res, err)
}
if err := m.validateBuildDate(formats); err != nil {
res = append(res, err)
}
if err := m.validateBuildUser(formats); err != nil {
res = append(res, err)
}
if err := m.validateGoVersion(formats); err != nil {
res = append(res, err)
}
if err := m.validateRevision(formats); err != nil {
res = append(res, err)
}
if err := m.validateVersion(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *VersionInfo) validateBranch(formats strfmt.Registry) error {
if err := validate.Required("branch", "body", m.Branch); err != nil {
return err
}
return nil
}
func (m *VersionInfo) validateBuildDate(formats strfmt.Registry) error {
if err := validate.Required("buildDate", "body", m.BuildDate); err != nil {
return err
}
return nil
}
func (m *VersionInfo) validateBuildUser(formats strfmt.Registry) error {
if err := validate.Required("buildUser", "body", m.BuildUser); err != nil {
return err
}
return nil
}
func (m *VersionInfo) validateGoVersion(formats strfmt.Registry) error {
if err := validate.Required("goVersion", "body", m.GoVersion); err != nil {
return err
}
return nil
}
func (m *VersionInfo) validateRevision(formats strfmt.Registry) error {
if err := validate.Required("revision", "body", m.Revision); err != nil {
return err
}
return nil
}
func (m *VersionInfo) validateVersion(formats strfmt.Registry) error {
if err := validate.Required("version", "body", m.Version); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *VersionInfo) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *VersionInfo) UnmarshalBinary(b []byte) error {
var res VersionInfo
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -205,11 +205,28 @@ responses:
definitions:
alertmanagerStatus:
type: object
properties:
cluster:
$ref: '#/definitions/clusterStatus'
versionInfo:
$ref: '#/definitions/versionInfo'
config:
$ref: '#/definitions/alertmanagerConfig'
uptime:
type: string
format: date-time
required:
- cluster
- versionInfo
- config
- uptime
clusterStatus:
type: object
properties:
name:
type: string
statusInCluster:
status:
type: string
peers:
type: array
@ -218,8 +235,37 @@ definitions:
$ref: '#/definitions/peerStatus'
required:
- name
- statusInCluster
- status
- peers
alertmanagerConfig:
type: object
properties:
original:
type: string
required:
- original
versionInfo:
type: object
properties:
version:
type: string
revision:
type: string
branch:
type: string
buildUser:
type: string
buildDate:
type: string
goVersion:
type: string
required:
- version
- revision
- branch
- buildUser
- buildDate
- goVersion
peerStatus:
type: object
properties:
@ -227,6 +273,9 @@ definitions:
type: string
address:
type: string
required:
- name
- address
silence:
type: object
properties:
@ -243,18 +292,27 @@ definitions:
updatedAt:
type: string
format: date-time
x-nullable: true
createdBy:
type: string
comment:
type: string
status:
type: object
properties:
state:
type: string
enum: ["expired", "active", "pending"]
$ref: '#/definitions/silenceStatus'
required:
- matchers
- startsAt
- endsAt
- createdBy
- comment
silenceStatus:
type: object
properties:
state:
type: string
enum: ["expired", "active", "pending"]
required:
- state
silences:
type: array
items:
@ -273,8 +331,10 @@ definitions:
type: string
isRegex:
type: boolean
regex:
type: string
required:
- name
- value
- isRegex
# Define required properties for 'alert'
alerts:
type: array
@ -306,24 +366,34 @@ definitions:
fingerprint:
type: string
status:
type: object
properties:
state:
type: string
enum: ['unprocessed', 'active', 'suppressed']
silencedBy:
type: array
items:
type: string
inhibitedBy:
type: array
items:
type: string
$ref: '#/definitions/alertStatus'
required:
- labels
alertStatus:
type: object
properties:
state:
type: string
enum: ['unprocessed', 'active', 'suppressed']
silencedBy:
type: array
items:
type: string
inhibitedBy:
type: array
items:
type: string
required:
- state
- silencedBy
- inhibitedBy
receiver:
type: object
properties:
name:
type: string
required:
- name
labelSet:
type: object
additionalProperties:

View File

@ -299,6 +299,9 @@ func init() {
"definitions": {
"alert": {
"type": "object",
"required": [
"labels"
],
"properties": {
"annotations": {
"$ref": "#/definitions/labelSet"
@ -328,29 +331,7 @@ func init() {
"format": "date-time"
},
"status": {
"type": "object",
"properties": {
"inhibitedBy": {
"type": "array",
"items": {
"type": "string"
}
},
"silencedBy": {
"type": "array",
"items": {
"type": "string"
}
},
"state": {
"type": "string",
"enum": [
"unprocessed",
"active",
"suppressed"
]
}
}
"$ref": "#/definitions/alertStatus"
},
"updatedAt": {
"type": "string",
@ -358,11 +339,82 @@ func init() {
}
}
},
"alertStatus": {
"type": "object",
"required": [
"state",
"silencedBy",
"inhibitedBy"
],
"properties": {
"inhibitedBy": {
"type": "array",
"items": {
"type": "string"
}
},
"silencedBy": {
"type": "array",
"items": {
"type": "string"
}
},
"state": {
"type": "string",
"enum": [
"unprocessed",
"active",
"suppressed"
]
}
}
},
"alertmanagerConfig": {
"type": "object",
"required": [
"original"
],
"properties": {
"original": {
"type": "string"
}
}
},
"alertmanagerStatus": {
"type": "object",
"required": [
"cluster",
"versionInfo",
"config",
"uptime"
],
"properties": {
"cluster": {
"$ref": "#/definitions/clusterStatus"
},
"config": {
"$ref": "#/definitions/alertmanagerConfig"
},
"uptime": {
"type": "string",
"format": "date-time"
},
"versionInfo": {
"$ref": "#/definitions/versionInfo"
}
}
},
"alerts": {
"type": "array",
"items": {
"$ref": "#/definitions/alert"
}
},
"clusterStatus": {
"type": "object",
"required": [
"name",
"statusInCluster",
"status",
"peers"
],
"properties": {
@ -376,17 +428,11 @@ func init() {
"$ref": "#/definitions/peerStatus"
}
},
"statusInCluster": {
"status": {
"type": "string"
}
}
},
"alerts": {
"type": "array",
"items": {
"$ref": "#/definitions/alert"
}
},
"labelSet": {
"type": "object",
"additionalProperties": {
@ -395,6 +441,11 @@ func init() {
},
"matcher": {
"type": "object",
"required": [
"name",
"value",
"isRegex"
],
"properties": {
"isRegex": {
"type": "boolean"
@ -402,9 +453,6 @@ func init() {
"name": {
"type": "string"
},
"regex": {
"type": "string"
},
"value": {
"type": "string"
}
@ -419,6 +467,10 @@ func init() {
},
"peerStatus": {
"type": "object",
"required": [
"name",
"address"
],
"properties": {
"address": {
"type": "string"
@ -430,6 +482,9 @@ func init() {
},
"receiver": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
@ -439,7 +494,11 @@ func init() {
"silence": {
"type": "object",
"required": [
"matchers"
"matchers",
"startsAt",
"endsAt",
"createdBy",
"comment"
],
"properties": {
"comment": {
@ -463,21 +522,28 @@ func init() {
"format": "date-time"
},
"status": {
"type": "object",
"properties": {
"state": {
"type": "string",
"enum": [
"expired",
"active",
"pending"
]
}
}
"$ref": "#/definitions/silenceStatus"
},
"updatedAt": {
"type": "string",
"format": "date-time"
"format": "date-time",
"x-nullable": true
}
}
},
"silenceStatus": {
"type": "object",
"required": [
"state"
],
"properties": {
"state": {
"type": "string",
"enum": [
"expired",
"active",
"pending"
]
}
}
},
@ -486,6 +552,37 @@ func init() {
"items": {
"$ref": "#/definitions/silence"
}
},
"versionInfo": {
"type": "object",
"required": [
"version",
"revision",
"branch",
"buildUser",
"buildDate",
"goVersion"
],
"properties": {
"branch": {
"type": "string"
},
"buildDate": {
"type": "string"
},
"buildUser": {
"type": "string"
},
"goVersion": {
"type": "string"
},
"revision": {
"type": "string"
},
"version": {
"type": "string"
}
}
}
},
"responses": {
@ -827,6 +924,9 @@ func init() {
"definitions": {
"alert": {
"type": "object",
"required": [
"labels"
],
"properties": {
"annotations": {
"$ref": "#/definitions/labelSet"
@ -856,29 +956,7 @@ func init() {
"format": "date-time"
},
"status": {
"type": "object",
"properties": {
"inhibitedBy": {
"type": "array",
"items": {
"type": "string"
}
},
"silencedBy": {
"type": "array",
"items": {
"type": "string"
}
},
"state": {
"type": "string",
"enum": [
"unprocessed",
"active",
"suppressed"
]
}
}
"$ref": "#/definitions/alertStatus"
},
"updatedAt": {
"type": "string",
@ -886,11 +964,82 @@ func init() {
}
}
},
"alertStatus": {
"type": "object",
"required": [
"state",
"silencedBy",
"inhibitedBy"
],
"properties": {
"inhibitedBy": {
"type": "array",
"items": {
"type": "string"
}
},
"silencedBy": {
"type": "array",
"items": {
"type": "string"
}
},
"state": {
"type": "string",
"enum": [
"unprocessed",
"active",
"suppressed"
]
}
}
},
"alertmanagerConfig": {
"type": "object",
"required": [
"original"
],
"properties": {
"original": {
"type": "string"
}
}
},
"alertmanagerStatus": {
"type": "object",
"required": [
"cluster",
"versionInfo",
"config",
"uptime"
],
"properties": {
"cluster": {
"$ref": "#/definitions/clusterStatus"
},
"config": {
"$ref": "#/definitions/alertmanagerConfig"
},
"uptime": {
"type": "string",
"format": "date-time"
},
"versionInfo": {
"$ref": "#/definitions/versionInfo"
}
}
},
"alerts": {
"type": "array",
"items": {
"$ref": "#/definitions/alert"
}
},
"clusterStatus": {
"type": "object",
"required": [
"name",
"statusInCluster",
"status",
"peers"
],
"properties": {
@ -904,17 +1053,11 @@ func init() {
"$ref": "#/definitions/peerStatus"
}
},
"statusInCluster": {
"status": {
"type": "string"
}
}
},
"alerts": {
"type": "array",
"items": {
"$ref": "#/definitions/alert"
}
},
"labelSet": {
"type": "object",
"additionalProperties": {
@ -923,6 +1066,11 @@ func init() {
},
"matcher": {
"type": "object",
"required": [
"name",
"value",
"isRegex"
],
"properties": {
"isRegex": {
"type": "boolean"
@ -930,9 +1078,6 @@ func init() {
"name": {
"type": "string"
},
"regex": {
"type": "string"
},
"value": {
"type": "string"
}
@ -947,6 +1092,10 @@ func init() {
},
"peerStatus": {
"type": "object",
"required": [
"name",
"address"
],
"properties": {
"address": {
"type": "string"
@ -958,6 +1107,9 @@ func init() {
},
"receiver": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
@ -967,7 +1119,11 @@ func init() {
"silence": {
"type": "object",
"required": [
"matchers"
"matchers",
"startsAt",
"endsAt",
"createdBy",
"comment"
],
"properties": {
"comment": {
@ -991,21 +1147,28 @@ func init() {
"format": "date-time"
},
"status": {
"type": "object",
"properties": {
"state": {
"type": "string",
"enum": [
"expired",
"active",
"pending"
]
}
}
"$ref": "#/definitions/silenceStatus"
},
"updatedAt": {
"type": "string",
"format": "date-time"
"format": "date-time",
"x-nullable": true
}
}
},
"silenceStatus": {
"type": "object",
"required": [
"state"
],
"properties": {
"state": {
"type": "string",
"enum": [
"expired",
"active",
"pending"
]
}
}
},
@ -1014,6 +1177,37 @@ func init() {
"items": {
"$ref": "#/definitions/silence"
}
},
"versionInfo": {
"type": "object",
"required": [
"version",
"revision",
"branch",
"buildUser",
"buildDate",
"goVersion"
],
"properties": {
"branch": {
"type": "string"
},
"buildDate": {
"type": "string"
},
"buildUser": {
"type": "string"
},
"goVersion": {
"type": "string"
},
"revision": {
"type": "string"
},
"version": {
"type": "string"
}
}
}
},
"responses": {

File diff suppressed because one or more lines are too long

View File

@ -59,9 +59,9 @@ type AcceptanceOpts struct {
func (opts *AcceptanceOpts) alertString(a *models.Alert) string {
if time.Time(a.EndsAt).IsZero() {
return fmt.Sprintf("%s[%v:]", a, opts.relativeTime(time.Time(a.StartsAt)))
return fmt.Sprintf("%v[%v:]", a, opts.relativeTime(time.Time(a.StartsAt)))
}
return fmt.Sprintf("%s[%v:%v]", a, opts.relativeTime(time.Time(a.StartsAt)), opts.relativeTime(time.Time(a.EndsAt)))
return fmt.Sprintf("%v[%v:%v]", a, opts.relativeTime(time.Time(a.StartsAt)), opts.relativeTime(time.Time(a.EndsAt)))
}
// expandTime returns the absolute time for the relative time
@ -352,7 +352,7 @@ func (am *Alertmanager) WaitForCluster(size int) error {
return err
}
if len(status.Payload.Peers) == size {
if len(status.Payload.Cluster.Peers) == size {
return nil
}
time.Sleep(100 * time.Millisecond)
@ -362,7 +362,7 @@ func (am *Alertmanager) WaitForCluster(size int) error {
"failed to wait for Alertmanager instance %q to join cluster: expected %v peers, but got %v",
am.clusterAddr,
size,
len(status.Payload.Peers),
len(status.Payload.Cluster.Peers),
)
}
@ -437,7 +437,7 @@ func (am *Alertmanager) Push(at float64, alerts ...*TestAlert) {
_, err := am.clientV2.Alert.PostAlerts(&params)
if err != nil {
am.t.Errorf("Error pushing %v: %s", cas, err)
am.t.Errorf("Error pushing %v: %v", cas, err)
}
})
}

View File

@ -6,10 +6,11 @@ package alert
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"golang.org/x/net/context"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"

View File

@ -6,10 +6,11 @@ package alert
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"golang.org/x/net/context"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"

View File

@ -1,113 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
package general
// 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"
strfmt "github.com/go-openapi/strfmt"
)
// NewGetReceiversParams creates a new GetReceiversParams object
// with the default values initialized.
func NewGetReceiversParams() *GetReceiversParams {
return &GetReceiversParams{
timeout: cr.DefaultTimeout,
}
}
// NewGetReceiversParamsWithTimeout creates a new GetReceiversParams object
// with the default values initialized, and the ability to set a timeout on a request
func NewGetReceiversParamsWithTimeout(timeout time.Duration) *GetReceiversParams {
return &GetReceiversParams{
timeout: timeout,
}
}
// NewGetReceiversParamsWithContext creates a new GetReceiversParams object
// with the default values initialized, and the ability to set a context for a request
func NewGetReceiversParamsWithContext(ctx context.Context) *GetReceiversParams {
return &GetReceiversParams{
Context: ctx,
}
}
// NewGetReceiversParamsWithHTTPClient creates a new GetReceiversParams object
// with the default values initialized, and the ability to set a custom HTTPClient for a request
func NewGetReceiversParamsWithHTTPClient(client *http.Client) *GetReceiversParams {
return &GetReceiversParams{
HTTPClient: client,
}
}
/*GetReceiversParams contains all the parameters to send to the API endpoint
for the get receivers operation typically these are written to a http.Request
*/
type GetReceiversParams struct {
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithTimeout adds the timeout to the get receivers params
func (o *GetReceiversParams) WithTimeout(timeout time.Duration) *GetReceiversParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the get receivers params
func (o *GetReceiversParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the get receivers params
func (o *GetReceiversParams) WithContext(ctx context.Context) *GetReceiversParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the get receivers params
func (o *GetReceiversParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the get receivers params
func (o *GetReceiversParams) WithHTTPClient(client *http.Client) *GetReceiversParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the get receivers params
func (o *GetReceiversParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WriteToRequest writes these params to a swagger request
func (o *GetReceiversParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@ -1,65 +0,0 @@
// Code generated by go-swagger; DO NOT EDIT.
package general
// 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/test/with_api_v2/api_v2_client/models"
)
// GetReceiversReader is a Reader for the GetReceivers structure.
type GetReceiversReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *GetReceiversReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewGetReceiversOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
return nil, runtime.NewAPIError("unknown error", response, response.Code())
}
}
// NewGetReceiversOK creates a GetReceiversOK with default headers values
func NewGetReceiversOK() *GetReceiversOK {
return &GetReceiversOK{}
}
/*GetReceiversOK handles this case with default header values.
Receivers response
*/
type GetReceiversOK struct {
Payload []models.Receiver
}
func (o *GetReceiversOK) Error() string {
return fmt.Sprintf("[GET /receivers][%d] getReceiversOK %+v", 200, o.Payload)
}
func (o *GetReceiversOK) 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

@ -6,10 +6,11 @@ package general
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"golang.org/x/net/context"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"

View File

@ -6,10 +6,11 @@ package receiver
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"golang.org/x/net/context"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"

View File

@ -6,10 +6,11 @@ package silence
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"golang.org/x/net/context"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"

View File

@ -6,10 +6,11 @@ package silence
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"golang.org/x/net/context"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"

View File

@ -6,10 +6,11 @@ package silence
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"golang.org/x/net/context"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"

View File

@ -6,10 +6,11 @@ package silence
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"golang.org/x/net/context"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"

View File

@ -6,7 +6,6 @@ package models
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"strconv"
strfmt "github.com/go-openapi/strfmt"
@ -35,7 +34,8 @@ type Alert struct {
GeneratorURL strfmt.URI `json:"generatorURL,omitempty"`
// labels
Labels LabelSet `json:"labels,omitempty"`
// Required: true
Labels LabelSet `json:"labels"`
// receivers
Receivers []*Receiver `json:"receivers"`
@ -138,10 +138,6 @@ func (m *Alert) validateGeneratorURL(formats strfmt.Registry) error {
func (m *Alert) 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")
@ -238,96 +234,3 @@ func (m *Alert) UnmarshalBinary(b []byte) error {
*m = res
return nil
}
// AlertStatus alert status
// swagger:model AlertStatus
type AlertStatus struct {
// inhibited by
InhibitedBy []string `json:"inhibitedBy"`
// silenced by
SilencedBy []string `json:"silencedBy"`
// state
// Enum: [unprocessed active suppressed]
State string `json:"state,omitempty"`
}
// Validate validates this alert status
func (m *AlertStatus) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateState(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
var alertStatusTypeStatePropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["unprocessed","active","suppressed"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
alertStatusTypeStatePropEnum = append(alertStatusTypeStatePropEnum, v)
}
}
const (
// AlertStatusStateUnprocessed captures enum value "unprocessed"
AlertStatusStateUnprocessed string = "unprocessed"
// AlertStatusStateActive captures enum value "active"
AlertStatusStateActive string = "active"
// AlertStatusStateSuppressed captures enum value "suppressed"
AlertStatusStateSuppressed string = "suppressed"
)
// prop value enum
func (m *AlertStatus) validateStateEnum(path, location string, value string) error {
if err := validate.Enum(path, location, value, alertStatusTypeStatePropEnum); err != nil {
return err
}
return nil
}
func (m *AlertStatus) validateState(formats strfmt.Registry) error {
if swag.IsZero(m.State) { // not required
return nil
}
// value enum
if err := m.validateStateEnum("status"+"."+"state", "body", m.State); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *AlertStatus) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AlertStatus) UnmarshalBinary(b []byte) error {
var res AlertStatus
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -0,0 +1,138 @@
// Code generated by go-swagger; DO NOT EDIT.
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 (
"encoding/json"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// AlertStatus alert status
// swagger:model alertStatus
type AlertStatus struct {
// inhibited by
// Required: true
InhibitedBy []string `json:"inhibitedBy"`
// silenced by
// Required: true
SilencedBy []string `json:"silencedBy"`
// state
// Required: true
// Enum: [unprocessed active suppressed]
State *string `json:"state"`
}
// Validate validates this alert status
func (m *AlertStatus) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateInhibitedBy(formats); err != nil {
res = append(res, err)
}
if err := m.validateSilencedBy(formats); err != nil {
res = append(res, err)
}
if err := m.validateState(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *AlertStatus) validateInhibitedBy(formats strfmt.Registry) error {
if err := validate.Required("inhibitedBy", "body", m.InhibitedBy); err != nil {
return err
}
return nil
}
func (m *AlertStatus) validateSilencedBy(formats strfmt.Registry) error {
if err := validate.Required("silencedBy", "body", m.SilencedBy); err != nil {
return err
}
return nil
}
var alertStatusTypeStatePropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["unprocessed","active","suppressed"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
alertStatusTypeStatePropEnum = append(alertStatusTypeStatePropEnum, v)
}
}
const (
// AlertStatusStateUnprocessed captures enum value "unprocessed"
AlertStatusStateUnprocessed string = "unprocessed"
// AlertStatusStateActive captures enum value "active"
AlertStatusStateActive string = "active"
// AlertStatusStateSuppressed captures enum value "suppressed"
AlertStatusStateSuppressed string = "suppressed"
)
// prop value enum
func (m *AlertStatus) validateStateEnum(path, location string, value string) error {
if err := validate.Enum(path, location, value, alertStatusTypeStatePropEnum); err != nil {
return err
}
return nil
}
func (m *AlertStatus) validateState(formats strfmt.Registry) error {
if err := validate.Required("state", "body", m.State); err != nil {
return err
}
// value enum
if err := m.validateStateEnum("state", "body", *m.State); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *AlertStatus) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AlertStatus) UnmarshalBinary(b []byte) error {
var res AlertStatus
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -0,0 +1,64 @@
// Code generated by go-swagger; DO NOT EDIT.
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 (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// AlertmanagerConfig alertmanager config
// swagger:model alertmanagerConfig
type AlertmanagerConfig struct {
// original
// Required: true
Original *string `json:"original"`
}
// Validate validates this alertmanager config
func (m *AlertmanagerConfig) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateOriginal(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *AlertmanagerConfig) validateOriginal(formats strfmt.Registry) error {
if err := validate.Required("original", "body", m.Original); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *AlertmanagerConfig) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AlertmanagerConfig) UnmarshalBinary(b []byte) error {
var res AlertmanagerConfig
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -6,8 +6,6 @@ package models
// 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"
@ -19,33 +17,41 @@ import (
// swagger:model alertmanagerStatus
type AlertmanagerStatus struct {
// name
// cluster
// Required: true
Name *string `json:"name"`
Cluster *ClusterStatus `json:"cluster"`
// peers
// config
// Required: true
// Minimum: 0
Peers []*PeerStatus `json:"peers"`
Config *AlertmanagerConfig `json:"config"`
// status in cluster
// uptime
// Required: true
StatusInCluster *string `json:"statusInCluster"`
// Format: date-time
Uptime *strfmt.DateTime `json:"uptime"`
// version info
// Required: true
VersionInfo *VersionInfo `json:"versionInfo"`
}
// Validate validates this alertmanager status
func (m *AlertmanagerStatus) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateName(formats); err != nil {
if err := m.validateCluster(formats); err != nil {
res = append(res, err)
}
if err := m.validatePeers(formats); err != nil {
if err := m.validateConfig(formats); err != nil {
res = append(res, err)
}
if err := m.validateStatusInCluster(formats); err != nil {
if err := m.validateUptime(formats); err != nil {
res = append(res, err)
}
if err := m.validateVersionInfo(formats); err != nil {
res = append(res, err)
}
@ -55,46 +61,70 @@ func (m *AlertmanagerStatus) Validate(formats strfmt.Registry) error {
return nil
}
func (m *AlertmanagerStatus) validateName(formats strfmt.Registry) error {
func (m *AlertmanagerStatus) validateCluster(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
if err := validate.Required("cluster", "body", m.Cluster); err != nil {
return err
}
return nil
}
func (m *AlertmanagerStatus) validatePeers(formats strfmt.Registry) error {
if err := validate.Required("peers", "body", m.Peers); err != nil {
return err
}
for i := 0; i < len(m.Peers); i++ {
if swag.IsZero(m.Peers[i]) { // not required
continue
}
if m.Peers[i] != nil {
if err := m.Peers[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("peers" + "." + strconv.Itoa(i))
}
return err
if m.Cluster != nil {
if err := m.Cluster.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("cluster")
}
return err
}
}
return nil
}
func (m *AlertmanagerStatus) validateStatusInCluster(formats strfmt.Registry) error {
func (m *AlertmanagerStatus) validateConfig(formats strfmt.Registry) error {
if err := validate.Required("statusInCluster", "body", m.StatusInCluster); err != nil {
if err := validate.Required("config", "body", m.Config); err != nil {
return err
}
if m.Config != nil {
if err := m.Config.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("config")
}
return err
}
}
return nil
}
func (m *AlertmanagerStatus) validateUptime(formats strfmt.Registry) error {
if err := validate.Required("uptime", "body", m.Uptime); err != nil {
return err
}
if err := validate.FormatOf("uptime", "body", "date-time", m.Uptime.String(), formats); err != nil {
return err
}
return nil
}
func (m *AlertmanagerStatus) validateVersionInfo(formats strfmt.Registry) error {
if err := validate.Required("versionInfo", "body", m.VersionInfo); err != nil {
return err
}
if m.VersionInfo != nil {
if err := m.VersionInfo.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("versionInfo")
}
return err
}
}
return nil
}

View File

@ -0,0 +1,117 @@
// Code generated by go-swagger; DO NOT EDIT.
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"
"github.com/go-openapi/validate"
)
// ClusterStatus cluster status
// swagger:model clusterStatus
type ClusterStatus struct {
// name
// Required: true
Name *string `json:"name"`
// peers
// Required: true
// Minimum: 0
Peers []*PeerStatus `json:"peers"`
// status
// Required: true
Status *string `json:"status"`
}
// Validate validates this cluster status
func (m *ClusterStatus) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateName(formats); err != nil {
res = append(res, err)
}
if err := m.validatePeers(formats); err != nil {
res = append(res, err)
}
if err := m.validateStatus(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ClusterStatus) validateName(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
return err
}
return nil
}
func (m *ClusterStatus) validatePeers(formats strfmt.Registry) error {
if err := validate.Required("peers", "body", m.Peers); err != nil {
return err
}
for i := 0; i < len(m.Peers); i++ {
if swag.IsZero(m.Peers[i]) { // not required
continue
}
if m.Peers[i] != nil {
if err := m.Peers[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("peers" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *ClusterStatus) validateStatus(formats strfmt.Registry) error {
if err := validate.Required("status", "body", m.Status); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *ClusterStatus) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ClusterStatus) UnmarshalBinary(b []byte) error {
var res ClusterStatus
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -8,7 +8,9 @@ package models
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// Matcher matcher
@ -16,20 +18,64 @@ import (
type Matcher struct {
// is regex
IsRegex bool `json:"isRegex,omitempty"`
// Required: true
IsRegex *bool `json:"isRegex"`
// name
Name string `json:"name,omitempty"`
// regex
Regex string `json:"regex,omitempty"`
// Required: true
Name *string `json:"name"`
// value
Value string `json:"value,omitempty"`
// Required: true
Value *string `json:"value"`
}
// Validate validates this matcher
func (m *Matcher) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateIsRegex(formats); err != nil {
res = append(res, err)
}
if err := m.validateName(formats); err != nil {
res = append(res, err)
}
if err := m.validateValue(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *Matcher) validateIsRegex(formats strfmt.Registry) error {
if err := validate.Required("isRegex", "body", m.IsRegex); err != nil {
return err
}
return nil
}
func (m *Matcher) validateName(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
return err
}
return nil
}
func (m *Matcher) validateValue(formats strfmt.Registry) error {
if err := validate.Required("value", "body", m.Value); err != nil {
return err
}
return nil
}

View File

@ -8,7 +8,9 @@ package models
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// PeerStatus peer status
@ -16,14 +18,47 @@ import (
type PeerStatus struct {
// address
Address string `json:"address,omitempty"`
// Required: true
Address *string `json:"address"`
// name
Name string `json:"name,omitempty"`
// Required: true
Name *string `json:"name"`
}
// Validate validates this peer status
func (m *PeerStatus) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateAddress(formats); err != nil {
res = append(res, err)
}
if err := m.validateName(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *PeerStatus) validateAddress(formats strfmt.Registry) error {
if err := validate.Required("address", "body", m.Address); err != nil {
return err
}
return nil
}
func (m *PeerStatus) validateName(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
return err
}
return nil
}

View File

@ -8,7 +8,9 @@ package models
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// Receiver receiver
@ -16,11 +18,30 @@ import (
type Receiver struct {
// name
Name string `json:"name,omitempty"`
// Required: true
Name *string `json:"name"`
}
// Validate validates this receiver
func (m *Receiver) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateName(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *Receiver) validateName(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
return err
}
return nil
}

View File

@ -6,8 +6,6 @@ package models
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
@ -20,14 +18,17 @@ import (
type Silence struct {
// comment
Comment string `json:"comment,omitempty"`
// Required: true
Comment *string `json:"comment"`
// created by
CreatedBy string `json:"createdBy,omitempty"`
// Required: true
CreatedBy *string `json:"createdBy"`
// ends at
// Required: true
// Format: date-time
EndsAt strfmt.DateTime `json:"endsAt,omitempty"`
EndsAt *strfmt.DateTime `json:"endsAt"`
// id
ID string `json:"id,omitempty"`
@ -37,21 +38,30 @@ type Silence struct {
Matchers Matchers `json:"matchers"`
// starts at
// Required: true
// Format: date-time
StartsAt strfmt.DateTime `json:"startsAt,omitempty"`
StartsAt *strfmt.DateTime `json:"startsAt"`
// status
Status *SilenceStatus `json:"status,omitempty"`
// updated at
// Format: date-time
UpdatedAt strfmt.DateTime `json:"updatedAt,omitempty"`
UpdatedAt *strfmt.DateTime `json:"updatedAt,omitempty"`
}
// Validate validates this silence
func (m *Silence) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateComment(formats); err != nil {
res = append(res, err)
}
if err := m.validateCreatedBy(formats); err != nil {
res = append(res, err)
}
if err := m.validateEndsAt(formats); err != nil {
res = append(res, err)
}
@ -78,10 +88,28 @@ func (m *Silence) Validate(formats strfmt.Registry) error {
return nil
}
func (m *Silence) validateComment(formats strfmt.Registry) error {
if err := validate.Required("comment", "body", m.Comment); err != nil {
return err
}
return nil
}
func (m *Silence) validateCreatedBy(formats strfmt.Registry) error {
if err := validate.Required("createdBy", "body", m.CreatedBy); err != nil {
return err
}
return nil
}
func (m *Silence) validateEndsAt(formats strfmt.Registry) error {
if swag.IsZero(m.EndsAt) { // not required
return nil
if err := validate.Required("endsAt", "body", m.EndsAt); err != nil {
return err
}
if err := validate.FormatOf("endsAt", "body", "date-time", m.EndsAt.String(), formats); err != nil {
@ -109,8 +137,8 @@ func (m *Silence) validateMatchers(formats strfmt.Registry) error {
func (m *Silence) validateStartsAt(formats strfmt.Registry) error {
if swag.IsZero(m.StartsAt) { // not required
return nil
if err := validate.Required("startsAt", "body", m.StartsAt); err != nil {
return err
}
if err := validate.FormatOf("startsAt", "body", "date-time", m.StartsAt.String(), formats); err != nil {
@ -168,90 +196,3 @@ func (m *Silence) UnmarshalBinary(b []byte) error {
*m = res
return nil
}
// SilenceStatus silence status
// swagger:model SilenceStatus
type SilenceStatus struct {
// state
// Enum: [expired active pending]
State string `json:"state,omitempty"`
}
// Validate validates this silence status
func (m *SilenceStatus) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateState(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
var silenceStatusTypeStatePropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["expired","active","pending"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
silenceStatusTypeStatePropEnum = append(silenceStatusTypeStatePropEnum, v)
}
}
const (
// SilenceStatusStateExpired captures enum value "expired"
SilenceStatusStateExpired string = "expired"
// SilenceStatusStateActive captures enum value "active"
SilenceStatusStateActive string = "active"
// SilenceStatusStatePending captures enum value "pending"
SilenceStatusStatePending string = "pending"
)
// prop value enum
func (m *SilenceStatus) validateStateEnum(path, location string, value string) error {
if err := validate.Enum(path, location, value, silenceStatusTypeStatePropEnum); err != nil {
return err
}
return nil
}
func (m *SilenceStatus) validateState(formats strfmt.Registry) error {
if swag.IsZero(m.State) { // not required
return nil
}
// value enum
if err := m.validateStateEnum("status"+"."+"state", "body", m.State); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *SilenceStatus) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *SilenceStatus) UnmarshalBinary(b []byte) error {
var res SilenceStatus
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -0,0 +1,104 @@
// Code generated by go-swagger; DO NOT EDIT.
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 (
"encoding/json"
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// SilenceStatus silence status
// swagger:model silenceStatus
type SilenceStatus struct {
// state
// Required: true
// Enum: [expired active pending]
State *string `json:"state"`
}
// Validate validates this silence status
func (m *SilenceStatus) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateState(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
var silenceStatusTypeStatePropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["expired","active","pending"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
silenceStatusTypeStatePropEnum = append(silenceStatusTypeStatePropEnum, v)
}
}
const (
// SilenceStatusStateExpired captures enum value "expired"
SilenceStatusStateExpired string = "expired"
// SilenceStatusStateActive captures enum value "active"
SilenceStatusStateActive string = "active"
// SilenceStatusStatePending captures enum value "pending"
SilenceStatusStatePending string = "pending"
)
// prop value enum
func (m *SilenceStatus) validateStateEnum(path, location string, value string) error {
if err := validate.Enum(path, location, value, silenceStatusTypeStatePropEnum); err != nil {
return err
}
return nil
}
func (m *SilenceStatus) validateState(formats strfmt.Registry) error {
if err := validate.Required("state", "body", m.State); err != nil {
return err
}
// value enum
if err := m.validateStateEnum("state", "body", *m.State); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *SilenceStatus) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *SilenceStatus) UnmarshalBinary(b []byte) error {
var res SilenceStatus
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -0,0 +1,149 @@
// Code generated by go-swagger; DO NOT EDIT.
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 (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/errors"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// VersionInfo version info
// swagger:model versionInfo
type VersionInfo struct {
// branch
// Required: true
Branch *string `json:"branch"`
// build date
// Required: true
BuildDate *string `json:"buildDate"`
// build user
// Required: true
BuildUser *string `json:"buildUser"`
// go version
// Required: true
GoVersion *string `json:"goVersion"`
// revision
// Required: true
Revision *string `json:"revision"`
// version
// Required: true
Version *string `json:"version"`
}
// Validate validates this version info
func (m *VersionInfo) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateBranch(formats); err != nil {
res = append(res, err)
}
if err := m.validateBuildDate(formats); err != nil {
res = append(res, err)
}
if err := m.validateBuildUser(formats); err != nil {
res = append(res, err)
}
if err := m.validateGoVersion(formats); err != nil {
res = append(res, err)
}
if err := m.validateRevision(formats); err != nil {
res = append(res, err)
}
if err := m.validateVersion(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *VersionInfo) validateBranch(formats strfmt.Registry) error {
if err := validate.Required("branch", "body", m.Branch); err != nil {
return err
}
return nil
}
func (m *VersionInfo) validateBuildDate(formats strfmt.Registry) error {
if err := validate.Required("buildDate", "body", m.BuildDate); err != nil {
return err
}
return nil
}
func (m *VersionInfo) validateBuildUser(formats strfmt.Registry) error {
if err := validate.Required("buildUser", "body", m.BuildUser); err != nil {
return err
}
return nil
}
func (m *VersionInfo) validateGoVersion(formats strfmt.Registry) error {
if err := validate.Required("goVersion", "body", m.GoVersion); err != nil {
return err
}
return nil
}
func (m *VersionInfo) validateRevision(formats strfmt.Registry) error {
if err := validate.Required("revision", "body", m.Revision); err != nil {
return err
}
return nil
}
func (m *VersionInfo) validateVersion(formats strfmt.Registry) error {
if err := validate.Required("version", "body", m.Version); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *VersionInfo) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *VersionInfo) UnmarshalBinary(b []byte) error {
var res VersionInfo
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@ -108,26 +108,31 @@ func (s *TestSilence) nativeSilence(opts *AcceptanceOpts) *models.Silence {
for i := 0; i < len(s.match); i += 2 {
nsil.Matchers = append(nsil.Matchers, &models.Matcher{
Name: s.match[i],
Value: s.match[i+1],
Name: &s.match[i],
Value: &s.match[i+1],
})
}
t := true
for i := 0; i < len(s.matchRE); i += 2 {
nsil.Matchers = append(nsil.Matchers, &models.Matcher{
Name: s.matchRE[i],
Value: s.matchRE[i+1],
IsRegex: true,
Name: &s.matchRE[i],
Value: &s.matchRE[i+1],
IsRegex: &t,
})
}
if s.startsAt > 0 {
nsil.StartsAt = strfmt.DateTime(opts.expandTime(s.startsAt))
start := strfmt.DateTime(opts.expandTime(s.startsAt))
nsil.StartsAt = &start
}
if s.endsAt > 0 {
nsil.EndsAt = strfmt.DateTime(opts.expandTime(s.endsAt))
end := strfmt.DateTime(opts.expandTime(s.endsAt))
nsil.EndsAt = &end
}
nsil.Comment = "some comment"
nsil.CreatedBy = "admin@example.com"
comment := "some comment"
createdBy := "admin@example.com"
nsil.Comment = &comment
nsil.CreatedBy = &createdBy
return nsil
}
@ -161,7 +166,7 @@ func Alert(keyval ...interface{}) *TestAlert {
}
// nativeAlert converts the declared test alert into a full alert based
// on the given paramters.
// on the given parameters.
func (a *TestAlert) nativeAlert(opts *AcceptanceOpts) *models.Alert {
na := &models.Alert{
Labels: a.labels,
@ -169,7 +174,8 @@ func (a *TestAlert) nativeAlert(opts *AcceptanceOpts) *models.Alert {
}
if a.startsAt > 0 {
na.StartsAt = strfmt.DateTime(opts.expandTime(a.startsAt))
start := strfmt.DateTime(opts.expandTime(a.startsAt))
na.StartsAt = start
}
if a.endsAt > 0 {
na.EndsAt = strfmt.DateTime(opts.expandTime(a.endsAt))
@ -301,10 +307,12 @@ func (ws *MockWebhook) ServeHTTP(w http.ResponseWriter, req *http.Request) {
annotations[k] = v
}
start := strfmt.DateTime(a.StartsAt)
alerts = append(alerts, &models.Alert{
Labels: labels,
Annotations: annotations,
StartsAt: strfmt.DateTime(a.StartsAt),
StartsAt: start,
EndsAt: strfmt.DateTime(a.EndsAt),
GeneratorURL: strfmt.URI(a.GeneratorURL),
})

View File

@ -1,16 +1,19 @@
ELM_FILES := $(shell find src -iname *.elm)
# Use `=` instead of `:=` expanding variable lazely, not at beginning. Needed as
# elm files change during execution.
ELM_FILES = $(shell find src -iname *.elm)
DOCKER_IMG := elm-env
DOCKER_CMD := docker run --rm -t -v $(PWD):/app -w /app $(DOCKER_IMG)
# macOS requires mktemp template to be at the end of the filename.
TEMPFILE := $(shell mktemp ./elm-XXXXXXXXXX)
# --output flag for elm make must end in .js or .html.
TEMPFILE_JS := "$(TEMPFILE).js"
TEMPOPENAPI := $(shell mktemp -d ./openapi-XXXXXXXXXX)
ifeq ($(NO_DOCKER), true)
DOCKER_CMD=
endif
all: test script.js
all: script.js test
elm-env:
@(if [ "$(NO_DOCKER)" != "true" ] ; then \
@ -22,7 +25,7 @@ format: elm-env $(ELM_FILES)
@echo ">> format front-end code"
@$(DOCKER_CMD) elm-format --yes $(ELM_FILES)
test: elm-env
test: src/Data elm-env
@$(DOCKER_CMD) rm -rf elm-stuff/generated-code
@$(DOCKER_CMD) elm-format $(ELM_FILES) --validate
@$(DOCKER_CMD) elm-test
@ -30,7 +33,7 @@ test: elm-env
dev-server:
elm reactor
script.js: elm-env format $(ELM_FILES)
script.js: src/Data elm-env format $(ELM_FILES)
@echo ">> building script.js"
@$(DOCKER_CMD) rm -rf elm-stuff
@$(DOCKER_CMD) elm make src/Main.elm --optimize --output $(TEMPFILE_JS)
@ -38,7 +41,26 @@ script.js: elm-env format $(ELM_FILES)
@rm -rf $(TEMPFILE_JS)
@rm -rf $(TEMPFILE)
src/Data: ../../api/v2/openapi.yaml
-rm -r src/Data
# TODO: Don't use :latest tag.
docker run --user=$(shell id -u $(USER)):$(shell id -g $(USER)) --rm -v ${PWD}/../..:/local openapitools/openapi-generator-cli:latest generate \
-i /local/api/v2/openapi.yaml\
-g elm \
-o /local/ui/app/$(TEMPOPENAPI)
# We only want data directory & DateTime package.
cp -r $(TEMPOPENAPI)/src/Data src/Data
cp -r $(TEMPOPENAPI)/src/DateTime.elm src/DateTime.elm
# openapi-generator still generates LabelSet, will be resolved with
# https://github.com/OpenAPITools/openapi-generator/issues/1140#issuecomment-432796436
rm src/Data/LabelSet.elm
rm -rf $(TEMPOPENAPI)
clean:
- @rm script.js
- @rm -rf elm-stuff
- @rm -rf src/Data
- @rm -f src/DateTime.elm
- @docker rmi $(DOCKER_IMG)
- rm -r openapi-*

View File

@ -15,7 +15,8 @@
"elm/regex": "1.0.0",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"rtfeldman/elm-iso8601-date-strings": "1.1.2"
"rtfeldman/elm-iso8601-date-strings": "1.1.2",
"NoRedInk/elm-json-decode-pipeline": "1.0.0"
},
"indirect": {
"elm/virtual-dom": "1.0.0",

63
ui/app/src/Data/Alert.elm Normal file
View File

@ -0,0 +1,63 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.Alert exposing (Alert, decoder, encoder)
import Data.AlertStatus as AlertStatus exposing (AlertStatus)
import Data.Receiver as Receiver exposing (Receiver)
import DateTime exposing (DateTime)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias Alert =
{ startsAt : Maybe DateTime
, updatedAt : Maybe DateTime
, endsAt : Maybe DateTime
, generatorURL : Maybe String
, labels : Dict String String
, annotations : Maybe (Dict String String)
, receivers : Maybe (List Receiver)
, fingerprint : Maybe String
, status : Maybe AlertStatus
}
decoder : Decoder Alert
decoder =
Decode.succeed Alert
|> optional "startsAt" (Decode.nullable DateTime.decoder) Nothing
|> optional "updatedAt" (Decode.nullable DateTime.decoder) Nothing
|> optional "endsAt" (Decode.nullable DateTime.decoder) Nothing
|> optional "generatorURL" (Decode.nullable Decode.string) Nothing
|> required "labels" (Decode.dict Decode.string)
|> optional "annotations" (Decode.nullable (Decode.dict Decode.string)) Nothing
|> optional "receivers" (Decode.nullable (Decode.list Receiver.decoder)) Nothing
|> optional "fingerprint" (Decode.nullable Decode.string) Nothing
|> optional "status" (Decode.nullable AlertStatus.decoder) Nothing
encoder : Alert -> Encode.Value
encoder model =
Encode.object
[ ( "startsAt", Maybe.withDefault Encode.null (Maybe.map DateTime.encoder model.startsAt) )
, ( "updatedAt", Maybe.withDefault Encode.null (Maybe.map DateTime.encoder model.updatedAt) )
, ( "endsAt", Maybe.withDefault Encode.null (Maybe.map DateTime.encoder model.endsAt) )
, ( "generatorURL", Maybe.withDefault Encode.null (Maybe.map Encode.string model.generatorURL) )
, ( "labels", Encode.dict identity Encode.string model.labels )
, ( "annotations", Maybe.withDefault Encode.null (Maybe.map (Encode.dict identity Encode.string) model.annotations) )
, ( "receivers", Maybe.withDefault Encode.null (Maybe.map (Encode.list Receiver.encoder) model.receivers) )
, ( "fingerprint", Maybe.withDefault Encode.null (Maybe.map Encode.string model.fingerprint) )
, ( "status", Maybe.withDefault Encode.null (Maybe.map AlertStatus.encoder model.status) )
]

View File

@ -0,0 +1,81 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.AlertStatus exposing (AlertStatus, State(..), decoder, encoder)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias AlertStatus =
{ state : State
, silencedBy : List String
, inhibitedBy : List String
}
type State
= Unprocessed
| Active
| Suppressed
decoder : Decoder AlertStatus
decoder =
Decode.succeed AlertStatus
|> required "state" stateDecoder
|> required "silencedBy" (Decode.list Decode.string)
|> required "inhibitedBy" (Decode.list Decode.string)
encoder : AlertStatus -> Encode.Value
encoder model =
Encode.object
[ ( "state", stateEncoder model.state )
, ( "silencedBy", Encode.list Encode.string model.silencedBy )
, ( "inhibitedBy", Encode.list Encode.string model.inhibitedBy )
]
stateDecoder : Decoder State
stateDecoder =
Decode.string
|> Decode.andThen
(\str ->
case str of
"unprocessed" ->
Decode.succeed Unprocessed
"active" ->
Decode.succeed Active
"suppressed" ->
Decode.succeed Suppressed
other ->
Decode.fail <| "Unknown type: " ++ other
)
stateEncoder : State -> Encode.Value
stateEncoder model =
case model of
Unprocessed ->
Encode.string "unprocessed"
Active ->
Encode.string "active"
Suppressed ->
Encode.string "suppressed"

View File

@ -0,0 +1,36 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.AlertmanagerConfig exposing (AlertmanagerConfig, decoder, encoder)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias AlertmanagerConfig =
{ original : String
}
decoder : Decoder AlertmanagerConfig
decoder =
Decode.succeed AlertmanagerConfig
|> required "original" Decode.string
encoder : AlertmanagerConfig -> Encode.Value
encoder model =
Encode.object
[ ( "original", Encode.string model.original )
]

View File

@ -0,0 +1,49 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.AlertmanagerStatus exposing (AlertmanagerStatus, decoder, encoder)
import Data.AlertmanagerConfig as AlertmanagerConfig exposing (AlertmanagerConfig)
import Data.ClusterStatus as ClusterStatus exposing (ClusterStatus)
import Data.VersionInfo as VersionInfo exposing (VersionInfo)
import DateTime exposing (DateTime)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias AlertmanagerStatus =
{ cluster : ClusterStatus
, versionInfo : VersionInfo
, config : AlertmanagerConfig
, uptime : DateTime
}
decoder : Decoder AlertmanagerStatus
decoder =
Decode.succeed AlertmanagerStatus
|> required "cluster" ClusterStatus.decoder
|> required "versionInfo" VersionInfo.decoder
|> required "config" AlertmanagerConfig.decoder
|> required "uptime" DateTime.decoder
encoder : AlertmanagerStatus -> Encode.Value
encoder model =
Encode.object
[ ( "cluster", ClusterStatus.encoder model.cluster )
, ( "versionInfo", VersionInfo.encoder model.versionInfo )
, ( "config", AlertmanagerConfig.encoder model.config )
, ( "uptime", DateTime.encoder model.uptime )
]

View File

@ -0,0 +1,33 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.Alerts exposing (Alerts, decoder, encoder)
import Data.Alert as Alert exposing (Alert)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias Alerts =
List Alert
decoder : Decoder Alerts
decoder =
Decode.list Alert.decoder
encoder : Alerts -> Encode.Value
encoder items =
Encode.list Alert.encoder items

View File

@ -0,0 +1,43 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.ClusterStatus exposing (ClusterStatus, decoder, encoder)
import Data.PeerStatus as PeerStatus exposing (PeerStatus)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias ClusterStatus =
{ name : String
, status : String
, peers : List PeerStatus
}
decoder : Decoder ClusterStatus
decoder =
Decode.succeed ClusterStatus
|> required "name" Decode.string
|> required "status" Decode.string
|> required "peers" (Decode.list PeerStatus.decoder)
encoder : ClusterStatus -> Encode.Value
encoder model =
Encode.object
[ ( "name", Encode.string model.name )
, ( "status", Encode.string model.status )
, ( "peers", Encode.list PeerStatus.encoder model.peers )
]

View File

@ -0,0 +1,36 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.InlineResponse200 exposing (InlineResponse200, decoder, encoder)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias InlineResponse200 =
{ silenceID : Maybe String
}
decoder : Decoder InlineResponse200
decoder =
Decode.succeed InlineResponse200
|> optional "silenceID" (Decode.nullable Decode.string) Nothing
encoder : InlineResponse200 -> Encode.Value
encoder model =
Encode.object
[ ( "silenceID", Maybe.withDefault Encode.null (Maybe.map Encode.string model.silenceID) )
]

View File

@ -0,0 +1,42 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.Matcher exposing (Matcher, decoder, encoder)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias Matcher =
{ name : String
, value : String
, isRegex : Bool
}
decoder : Decoder Matcher
decoder =
Decode.succeed Matcher
|> required "name" Decode.string
|> required "value" Decode.string
|> required "isRegex" Decode.bool
encoder : Matcher -> Encode.Value
encoder model =
Encode.object
[ ( "name", Encode.string model.name )
, ( "value", Encode.string model.value )
, ( "isRegex", Encode.bool model.isRegex )
]

View File

@ -0,0 +1,33 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.Matchers exposing (Matchers, decoder, encoder)
import Data.Matcher as Matcher exposing (Matcher)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias Matchers =
List Matcher
decoder : Decoder Matchers
decoder =
Decode.list Matcher.decoder
encoder : Matchers -> Encode.Value
encoder items =
Encode.list Matcher.encoder items

View File

@ -0,0 +1,39 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.PeerStatus exposing (PeerStatus, decoder, encoder)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias PeerStatus =
{ name : String
, address : String
}
decoder : Decoder PeerStatus
decoder =
Decode.succeed PeerStatus
|> required "name" Decode.string
|> required "address" Decode.string
encoder : PeerStatus -> Encode.Value
encoder model =
Encode.object
[ ( "name", Encode.string model.name )
, ( "address", Encode.string model.address )
]

View File

@ -0,0 +1,36 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.Receiver exposing (Receiver, decoder, encoder)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias Receiver =
{ name : String
}
decoder : Decoder Receiver
decoder =
Decode.succeed Receiver
|> required "name" Decode.string
encoder : Receiver -> Encode.Value
encoder model =
Encode.object
[ ( "name", Encode.string model.name )
]

View File

@ -0,0 +1,60 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.Silence exposing (Silence, decoder, encoder)
import Data.Matchers as Matchers exposing (Matchers)
import Data.SilenceStatus as SilenceStatus exposing (SilenceStatus)
import DateTime exposing (DateTime)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias Silence =
{ id : Maybe String
, matchers : Matchers
, startsAt : DateTime
, endsAt : DateTime
, updatedAt : Maybe DateTime
, createdBy : String
, comment : String
, status : Maybe SilenceStatus
}
decoder : Decoder Silence
decoder =
Decode.succeed Silence
|> optional "id" (Decode.nullable Decode.string) Nothing
|> required "matchers" Matchers.decoder
|> required "startsAt" DateTime.decoder
|> required "endsAt" DateTime.decoder
|> optional "updatedAt" (Decode.nullable DateTime.decoder) Nothing
|> required "createdBy" Decode.string
|> required "comment" Decode.string
|> optional "status" (Decode.nullable SilenceStatus.decoder) Nothing
encoder : Silence -> Encode.Value
encoder model =
Encode.object
[ ( "id", Maybe.withDefault Encode.null (Maybe.map Encode.string model.id) )
, ( "matchers", Matchers.encoder model.matchers )
, ( "startsAt", DateTime.encoder model.startsAt )
, ( "endsAt", DateTime.encoder model.endsAt )
, ( "updatedAt", Maybe.withDefault Encode.null (Maybe.map DateTime.encoder model.updatedAt) )
, ( "createdBy", Encode.string model.createdBy )
, ( "comment", Encode.string model.comment )
, ( "status", Maybe.withDefault Encode.null (Maybe.map SilenceStatus.encoder model.status) )
]

View File

@ -0,0 +1,75 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.SilenceStatus exposing (SilenceStatus, State(..), decoder, encoder)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias SilenceStatus =
{ state : State
}
type State
= Expired
| Active
| Pending
decoder : Decoder SilenceStatus
decoder =
Decode.succeed SilenceStatus
|> required "state" stateDecoder
encoder : SilenceStatus -> Encode.Value
encoder model =
Encode.object
[ ( "state", stateEncoder model.state )
]
stateDecoder : Decoder State
stateDecoder =
Decode.string
|> Decode.andThen
(\str ->
case str of
"expired" ->
Decode.succeed Expired
"active" ->
Decode.succeed Active
"pending" ->
Decode.succeed Pending
other ->
Decode.fail <| "Unknown type: " ++ other
)
stateEncoder : State -> Encode.Value
stateEncoder model =
case model of
Expired ->
Encode.string "expired"
Active ->
Encode.string "active"
Pending ->
Encode.string "pending"

View File

@ -0,0 +1,33 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.Silences exposing (Silences, decoder, encoder)
import Data.Silence as Silence exposing (Silence)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias Silences =
List Silence
decoder : Decoder Silences
decoder =
Decode.list Silence.decoder
encoder : Silences -> Encode.Value
encoder items =
Encode.list Silence.encoder items

View File

@ -0,0 +1,51 @@
{-
Alertmanager API
API of the Prometheus Alertmanager (https://github.com/prometheus/alertmanager)
OpenAPI spec version: 0.0.1
NOTE: This file is auto generated by the openapi-generator.
https://github.com/openapitools/openapi-generator.git
Do not edit this file manually.
-}
module Data.VersionInfo exposing (VersionInfo, decoder, encoder)
import Dict exposing (Dict)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (optional, required)
import Json.Encode as Encode
type alias VersionInfo =
{ version : String
, revision : String
, branch : String
, buildUser : String
, buildDate : String
, goVersion : String
}
decoder : Decoder VersionInfo
decoder =
Decode.succeed VersionInfo
|> required "version" Decode.string
|> required "revision" Decode.string
|> required "branch" Decode.string
|> required "buildUser" Decode.string
|> required "buildDate" Decode.string
|> required "goVersion" Decode.string
encoder : VersionInfo -> Encode.Value
encoder model =
Encode.object
[ ( "version", Encode.string model.version )
, ( "revision", Encode.string model.revision )
, ( "branch", Encode.string model.branch )
, ( "buildUser", Encode.string model.buildUser )
, ( "buildDate", Encode.string model.buildDate )
, ( "goVersion", Encode.string model.goVersion )
]

37
ui/app/src/DateTime.elm Normal file
View File

@ -0,0 +1,37 @@
module DateTime exposing (DateTime, decoder, encoder, toString)
import Iso8601
import Json.Decode as Decode exposing (Decoder)
import Json.Encode as Encode
import Result
import Time
type alias DateTime =
Time.Posix
decoder : Decoder DateTime
decoder =
Decode.string
|> Decode.andThen decodeIsoString
encoder : DateTime -> Encode.Value
encoder =
Encode.string << toString
decodeIsoString : String -> Decoder DateTime
decodeIsoString str =
case Iso8601.toTime str of
Result.Ok posix ->
Decode.succeed posix
Result.Err _ ->
Decode.fail <| "Invalid date: " ++ str
toString : DateTime -> String
toString =
Iso8601.fromTime

View File

@ -1,9 +1,9 @@
module Silences.Api exposing (create, destroy, getSilence, getSilences)
import Data.Silence exposing (Silence)
import Data.Silences
import Http
import Silences.Decoders exposing (create, destroy, list, show)
import Silences.Encoders
import Silences.Types exposing (Silence)
import Silences.Decoders
import Utils.Api
import Utils.Filter exposing (Filter, generateQueryString)
import Utils.Types exposing (ApiData(..))
@ -15,7 +15,7 @@ getSilences apiUrl filter msg =
url =
String.join "/" [ apiUrl, "silences" ++ generateQueryString filter ]
in
Utils.Api.send (Utils.Api.get url list)
Utils.Api.send (Utils.Api.get url Data.Silences.decoder)
|> Cmd.map msg
@ -25,7 +25,7 @@ getSilence apiUrl uuid msg =
url =
String.join "/" [ apiUrl, "silence", uuid ]
in
Utils.Api.send (Utils.Api.get url show)
Utils.Api.send (Utils.Api.get url Data.Silence.decoder)
|> Cmd.map msg
@ -36,7 +36,7 @@ create apiUrl silence =
String.join "/" [ apiUrl, "silences" ]
body =
Http.jsonBody <| Silences.Encoders.silence silence
Http.jsonBody <| Data.Silence.encoder silence
in
-- TODO: This should return the silence, not just the ID, so that we can
-- redirect to the silence show page.
@ -50,7 +50,9 @@ destroy apiUrl silence msg =
-- be matching on /silences and ignoring the :sid, should be getting a 404.
let
url =
String.join "/" [ apiUrl, "silence", silence.id ]
-- TODO: Maybe.withDefault is not perfect. Silences should always
-- have an id, what should we do?
String.join "/" [ apiUrl, "silence", Maybe.withDefault "" silence.id ]
responseDecoder =
-- Silences.Encoders.silence silence

View File

@ -1,77 +1,15 @@
module Silences.Decoders exposing (create, destroy, list, show)
module Silences.Decoders exposing (create, destroy)
import Json.Decode as Json exposing (fail, field, succeed)
import Silences.Types exposing (Silence, State(..), Status)
import Utils.Api exposing (andMap, iso8601Time)
import Utils.Types exposing (ApiData(..), Matcher, Time)
show : Json.Decoder Silence
show =
Json.at [ "data" ] silenceDecoder
list : Json.Decoder (List Silence)
list =
Json.at [ "data" ] (Json.list silenceDecoder)
create : Json.Decoder String
create =
Json.at [ "data", "silenceId" ] Json.string
Json.at [ "silenceID" ] Json.string
destroy : Json.Decoder String
destroy =
Json.at [ "status" ] Json.string
silenceDecoder : Json.Decoder Silence
silenceDecoder =
Json.succeed Silence
|> andMap (field "id" Json.string)
|> andMap (field "createdBy" Json.string)
-- Remove this maybe once the api either disallows empty comments on
-- creation, or returns an empty string.
|> andMap
(Json.maybe (field "comment" Json.string)
|> Json.andThen (\x -> Json.succeed <| Maybe.withDefault "" x)
)
|> andMap (field "startsAt" iso8601Time)
|> andMap (field "endsAt" iso8601Time)
|> andMap (field "updatedAt" iso8601Time)
|> andMap (field "matchers" (Json.list matcherDecoder))
|> andMap (field "status" statusDecoder)
statusDecoder : Json.Decoder Status
statusDecoder =
Json.succeed Status
|> andMap (field "state" Json.string |> Json.andThen stateDecoder)
stateDecoder : String -> Json.Decoder State
stateDecoder state =
case state of
"active" ->
succeed Active
"pending" ->
succeed Pending
"expired" ->
succeed Expired
_ ->
fail <|
"Silence.status.state must be one of 'active', 'pending' or 'expired' but was'"
++ state
++ "'."
matcherDecoder : Json.Decoder Matcher
matcherDecoder =
Json.map3 Matcher
(field "isRegex" Json.bool)
(field "name" Json.string)
(field "value" Json.string)

View File

@ -1,27 +0,0 @@
module Silences.Encoders exposing (matcher, silence)
import Json.Encode as Encode
import Silences.Types exposing (Silence)
import Utils.Date
import Utils.Types exposing (Matcher)
silence : Silence -> Encode.Value
silence silence_ =
Encode.object
[ ( "id", Encode.string silence_.id )
, ( "createdBy", Encode.string silence_.createdBy )
, ( "comment", Encode.string silence_.comment )
, ( "startsAt", Encode.string (Utils.Date.encode silence_.startsAt) )
, ( "endsAt", Encode.string (Utils.Date.encode silence_.endsAt) )
, ( "matchers", Encode.list matcher silence_.matchers )
]
matcher : Matcher -> Encode.Value
matcher m =
Encode.object
[ ( "name", Encode.string m.name )
, ( "value", Encode.string m.value )
, ( "isRegex", Encode.bool m.isRegex )
]

View File

@ -1,63 +1,44 @@
module Silences.Types exposing
( Silence
, SilenceId
, State(..)
, Status
, nullMatcher
( nullMatcher
, nullSilence
, nullSilenceStatus
, stateToString
)
import Data.Matcher exposing (Matcher)
import Data.Matchers exposing (Matchers)
import Data.Silence exposing (Silence)
import Data.SilenceStatus exposing (SilenceStatus, State(..))
import Time exposing (Posix)
import Utils.Types exposing (Matcher)
nullSilence : Silence
nullSilence =
{ id = ""
{ id = Nothing
, createdBy = ""
, comment = ""
, startsAt = Time.millisToPosix 0
, endsAt = Time.millisToPosix 0
, updatedAt = Time.millisToPosix 0
, matchers = [ nullMatcher ]
, status = nullSilenceStatus
, updatedAt = Nothing
, matchers = nullMatchers
, status = Nothing
}
nullSilenceStatus : Status
nullSilenceStatus : SilenceStatus
nullSilenceStatus =
{ state = Expired
}
nullMatchers : Matchers
nullMatchers =
[ nullMatcher ]
nullMatcher : Matcher
nullMatcher =
Matcher False "" ""
type alias Silence =
{ id : SilenceId
, createdBy : String
, comment : String
, startsAt : Posix
, endsAt : Posix
, updatedAt : Posix
, matchers : List Matcher
, status : Status
}
type alias Status =
{ state : State
}
type State
= Active
| Pending
| Expired
Matcher "" "" False
stateToString : State -> String
@ -71,7 +52,3 @@ stateToString state =
Expired ->
"expired"
type alias SilenceId =
String

View File

@ -1,19 +1,20 @@
module Status.Api exposing (getStatus)
import Data.AlertmanagerStatus exposing (AlertmanagerStatus)
import Json.Decode exposing (Decoder, at, bool, field, int, list, map2, maybe, string)
import Status.Types exposing (ClusterPeer, ClusterStatus, StatusResponse, VersionInfo)
import Utils.Api exposing (get, send)
import Utils.Types exposing (ApiData)
getStatus : String -> (ApiData StatusResponse -> msg) -> Cmd msg
getStatus : String -> (ApiData AlertmanagerStatus -> msg) -> Cmd msg
getStatus apiUrl msg =
let
url =
String.join "/" [ apiUrl, "status" ]
request =
get url decodeStatusResponse
get url Data.AlertmanagerStatus.decoder
in
Cmd.map msg <| send request

View File

@ -1,7 +1,8 @@
module Utils.List exposing (groupBy, lastElem, mjoin, mstring, nextElem, replaceIf, replaceIndex, zip)
import Data.Matcher exposing (Matcher)
import Data.Matchers exposing (Matchers)
import Dict exposing (Dict)
import Utils.Types exposing (Matcher, Matchers)
nextElem : a -> List a -> Maybe a

View File

@ -1,6 +1,7 @@
module Views.AlertList.AlertView exposing (addLabelMsg, view)
import Alerts.Types exposing (Alert)
import Dict
import Html exposing (..)
import Html.Attributes exposing (class, href, readonly, style, title, value)
import Html.Events exposing (onClick)
@ -105,7 +106,7 @@ silenceButton alert =
Nothing ->
a
[ class "btn btn-outline-info border-0"
, href (newSilenceFromAlertLabels alert.labels)
, href (newSilenceFromAlertLabels <| Dict.fromList alert.labels)
]
[ i [ class "fa fa-bell-slash-o mr-2" ] []
, text "Silence"

View File

@ -1,14 +1,16 @@
module Views.SilenceForm.Parsing exposing (newSilenceFromAlertLabels, silenceFormEditParser, silenceFormNewParser)
import Dict exposing (Dict)
import Url exposing (percentEncode)
import Url.Parser exposing ((</>), (<?>), Parser, map, oneOf, s, string)
import Url.Parser.Query as Query
import Utils.Filter exposing (Matcher, parseFilter)
newSilenceFromAlertLabels : List ( String, String ) -> String
newSilenceFromAlertLabels : Dict String String -> String
newSilenceFromAlertLabels labels =
labels
|> Dict.toList
|> List.map (\( k, v ) -> Utils.Filter.Matcher k Utils.Filter.Eq v)
|> Utils.Filter.stringifyFilter
|> percentEncode

View File

@ -15,7 +15,9 @@ module Views.SilenceForm.Types exposing
import Alerts.Types exposing (Alert)
import Browser.Navigation exposing (Key)
import Silences.Types exposing (Silence, SilenceId, nullSilence)
import Data.Matcher exposing (Matcher)
import Data.Silence exposing (Silence)
import Silences.Types exposing (nullSilence)
import Time exposing (Posix)
import Utils.Date exposing (addDuration, durationFormat, parseDuration, timeDifference, timeFromString, timeToString)
import Utils.Filter
@ -27,7 +29,7 @@ import Utils.FormValidation
, stringNotEmpty
, validate
)
import Utils.Types exposing (ApiData(..), Duration, Matcher)
import Utils.Types exposing (ApiData(..), Duration)
type alias Model =
@ -40,7 +42,7 @@ type alias Model =
type alias SilenceForm =
{ id : String
{ id : Maybe String
, createdBy : ValidatedField
, comment : ValidatedField
, startsAt : ValidatedField
@ -67,7 +69,7 @@ type SilenceFormMsg
| NewSilenceFromMatchers String (List Utils.Filter.Matcher)
| NewSilenceFromMatchersAndTime String (List Utils.Filter.Matcher) Posix
| SilenceFetch (ApiData Silence)
| SilenceCreate (ApiData SilenceId)
| SilenceCreate (ApiData String)
type SilenceFormFieldMsg
@ -167,7 +169,7 @@ validateMatcherForm { name, value, isRegex } =
empty : SilenceForm
empty =
{ id = ""
{ id = Nothing
, createdBy = initialField ""
, comment = initialField ""
, startsAt = initialField ""
@ -211,12 +213,12 @@ fromMatchersAndTime defaultCreator matchers now =
appendMatcher : MatcherForm -> Result String (List Matcher) -> Result String (List Matcher)
appendMatcher { isRegex, name, value } =
Result.map2 (::)
(Result.map2 (Matcher isRegex) (stringNotEmpty name.value) (Ok value.value))
(Result.map2 (\k v -> Matcher k v isRegex) (stringNotEmpty name.value) (Ok value.value))
filterMatcherToMatcher : Utils.Filter.Matcher -> Maybe Matcher
filterMatcherToMatcher { key, op, value } =
Maybe.map (\operator -> Matcher operator key value) <|
Maybe.map (\operator -> Matcher key value operator) <|
case op of
Utils.Filter.Eq ->
Just False

View File

@ -1,10 +1,10 @@
module Views.SilenceForm.Views exposing (view)
import Alerts.Types exposing (Alert)
import Data.Silence exposing (Silence)
import Html exposing (Html, a, button, div, fieldset, h1, input, label, legend, span, strong, text, textarea)
import Html.Attributes exposing (class, href)
import Html.Events exposing (onClick)
import Silences.Types exposing (Silence, SilenceId)
import Utils.Filter
import Utils.FormValidation exposing (ValidatedField, ValidationState(..))
import Utils.Types exposing (ApiData)
@ -14,7 +14,7 @@ import Views.Shared.Types exposing (Msg)
import Views.SilenceForm.Types exposing (MatcherForm, Model, SilenceForm, SilenceFormFieldMsg(..), SilenceFormMsg(..))
view : Maybe SilenceId -> List Utils.Filter.Matcher -> String -> Model -> Html SilenceFormMsg
view : Maybe String -> List Utils.Filter.Matcher -> String -> Model -> Html SilenceFormMsg
view maybeId matchers defaultCreator { form, silenceId, alerts, activeAlertId } =
let
( title, resetClick ) =
@ -95,7 +95,7 @@ matcherInput matchers =
]
informationBlock : Maybe String -> ApiData SilenceId -> ApiData (List Alert) -> Html SilenceFormMsg
informationBlock : Maybe String -> ApiData String -> ApiData (List Alert) -> Html SilenceFormMsg
informationBlock activeAlertId silence alerts =
case silence of
Utils.Types.Success _ ->

View File

@ -1,15 +1,18 @@
module Views.SilenceList.SilenceView exposing (deleteButton, editButton, view)
import Data.Matcher exposing (Matcher)
import Data.Matchers exposing (Matchers)
import Data.Silence exposing (Silence)
import Data.SilenceStatus exposing (State(..))
import Dict exposing (Dict)
import Html exposing (Html, a, b, button, div, h3, i, li, p, small, span, text)
import Html.Attributes exposing (class, href, style)
import Html.Events exposing (onClick)
import Silences.Types exposing (Silence, State(..))
import Time exposing (Posix)
import Types exposing (Msg(..))
import Utils.Date
import Utils.Filter
import Utils.List
import Utils.Types exposing (Matcher)
import Utils.Views exposing (buttonLink)
import Views.FilterBar.Types as FilterBarTypes
import Views.Shared.Dialog as Dialog
@ -26,15 +29,20 @@ view showConfirmationDialog silence =
, class "align-items-start list-group-item border-0 p-0 mb-4"
]
[ div [ class "w-100 mb-2 d-flex align-items-start" ]
[ case silence.status.state of
Active ->
dateView "Ends" silence.endsAt
[ case silence.status of
Just status ->
case status.state of
Active ->
dateView "Ends" silence.endsAt
Pending ->
dateView "Starts" silence.startsAt
Pending ->
dateView "Starts" silence.startsAt
Expired ->
dateView "Expired" silence.endsAt
Expired ->
dateView "Expired" silence.endsAt
Nothing ->
text ""
, detailsButton silence.id
, editButton silence
, deleteButton silence False
@ -100,53 +108,73 @@ editButton silence =
let
matchers =
List.map (\s -> ( s.name, s.value )) silence.matchers
in
case silence.status.state of
-- If the silence is expired, do not edit it, but instead create a new
-- one with the old matchers
Expired ->
a
[ class "btn btn-outline-info border-0"
, href (newSilenceFromAlertLabels matchers)
]
[ text "Recreate"
]
_ ->
let
editUrl =
String.join "/" [ "#/silences", silence.id, "edit" ]
in
editUrl =
-- TODO: silence.id should always be set. Can this be done nicer?
String.join "/" [ "#/silences", Maybe.withDefault "" silence.id, "edit" ]
default =
a [ class "btn btn-outline-info border-0", href editUrl ]
[ text "Edit"
]
in
case silence.status of
Just status ->
case status.state of
-- If the silence is expired, do not edit it, but instead create a new
-- one with the old matchers
Expired ->
a
[ class "btn btn-outline-info border-0"
, href (newSilenceFromAlertLabels <| Dict.fromList matchers)
]
[ text "Recreate"
]
_ ->
default
Nothing ->
default
deleteButton : Silence -> Bool -> Html Msg
deleteButton silence refresh =
case silence.status.state of
Expired ->
-- TODO: status should always be set, how to solve this better?
case silence.status of
Just status ->
case status.state of
Expired ->
text ""
Active ->
button
[ class "btn btn-outline-danger border-0"
, onClick (MsgForSilenceList (ConfirmDestroySilence silence refresh))
]
[ text "Expire"
]
Pending ->
button
[ class "btn btn-outline-danger border-0"
, onClick (MsgForSilenceList (ConfirmDestroySilence silence refresh))
]
[ text "Delete"
]
Nothing ->
text ""
Active ->
button
[ class "btn btn-outline-danger border-0"
, onClick (MsgForSilenceList (ConfirmDestroySilence silence refresh))
]
[ text "Expire"
detailsButton : Maybe String -> Html Msg
detailsButton maybeSilenceId =
-- TODO: Again, silence.id should not be Nothing here, how can this be done better?
case maybeSilenceId of
Just id ->
a [ class "btn btn-outline-info border-0", href ("#/silences/" ++ id) ]
[ text "View"
]
Pending ->
button
[ class "btn btn-outline-danger border-0"
, onClick (MsgForSilenceList (ConfirmDestroySilence silence refresh))
]
[ text "Delete"
]
detailsButton : String -> Html Msg
detailsButton silenceId =
a [ class "btn btn-outline-info border-0", href ("#/silences/" ++ silenceId) ]
[ text "View"
]
Nothing ->
text ""

View File

@ -1,7 +1,9 @@
module Views.SilenceList.Types exposing (Model, SilenceListMsg(..), SilenceTab, initSilenceList)
import Browser.Navigation exposing (Key)
import Silences.Types exposing (Silence, SilenceId, State(..))
import Data.Silence exposing (Silence)
import Data.SilenceStatus exposing (State(..))
import Data.Silences exposing (Silences)
import Utils.Types exposing (ApiData(..))
import Views.FilterBar.Types as FilterBar
@ -16,7 +18,7 @@ type SilenceListMsg
type alias SilenceTab =
{ silences : List Silence
{ silences : Silences
, tab : State
, count : Int
}
@ -26,7 +28,7 @@ type alias Model =
{ silences : ApiData (List SilenceTab)
, filterBar : FilterBar.Model
, tab : State
, showConfirmationDialog : Maybe SilenceId
, showConfirmationDialog : Maybe String
, key : Key
}

View File

@ -1,8 +1,10 @@
module Views.SilenceList.Updates exposing (update, urlUpdate)
import Browser.Navigation as Navigation
import Data.Silence exposing (Silence)
import Data.SilenceStatus exposing (State(..))
import Data.Silences exposing (Silences)
import Silences.Api as Api
import Silences.Types exposing (Silence, State(..))
import Utils.Api as ApiData
import Utils.Filter exposing (Filter, generateQueryString)
import Utils.Types as Types exposing (ApiData(..), Matchers, Time)
@ -33,7 +35,7 @@ update msg model filter basePath apiUrl =
)
ConfirmDestroySilence silence refresh ->
( { model | showConfirmationDialog = Just silence.id }
( { model | showConfirmationDialog = silence.id }
, Cmd.none
)
@ -79,9 +81,19 @@ states =
[ Active, Pending, Expired ]
filterSilencesByState : State -> List Silence -> List Silence
filterSilencesByState : State -> Silences -> Silences
filterSilencesByState state =
List.filter (.status >> .state >> (==) state)
List.filter (filterSilenceByState state)
filterSilenceByState : State -> Silence -> Bool
filterSilenceByState state silence =
case silence.status of
Just status ->
status.state == state
Nothing ->
False
urlUpdate : Maybe String -> ( SilenceListMsg, Filter )

View File

@ -1,10 +1,13 @@
module Views.SilenceList.Views exposing (filterSilencesByState, groupSilencesByState, silencesView, states, tabView, tabsView, view)
import Data.Silence exposing (Silence)
import Data.SilenceStatus exposing (State(..))
import Data.Silences exposing (Silences)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Keyed
import Html.Lazy exposing (lazy, lazy2, lazy3)
import Silences.Types exposing (Silence, SilenceId, State(..), stateToString)
import Silences.Types exposing (stateToString)
import Types exposing (Msg(..))
import Utils.String as StringUtils
import Utils.Types exposing (ApiData(..), Matcher)
@ -53,7 +56,7 @@ tabView currentTab count tab =
]
silencesView : Maybe SilenceId -> State -> ApiData (List SilenceTab) -> Html Msg
silencesView : Maybe String -> State -> ApiData (List SilenceTab) -> Html Msg
silencesView showConfirmationDialog tab silencesTab =
case silencesTab of
Success tabs ->
@ -70,9 +73,9 @@ silencesView showConfirmationDialog tab silencesTab =
Html.Keyed.ul [ class "list-group" ]
(List.map
(\silence ->
( silence.id
( Maybe.withDefault "" silence.id
, Views.SilenceList.SilenceView.view
(showConfirmationDialog == Just silence.id)
(showConfirmationDialog == silence.id)
silence
)
)
@ -97,6 +100,23 @@ states =
[ Active, Pending, Expired ]
filterSilencesByState : State -> List Silence -> List Silence
filterSilencesByState : State -> Silences -> Silences
filterSilencesByState state =
List.filter (.status >> .state >> (==) state)
List.filter (filterSilenceByState state)
filterSilenceByState : State -> Silence -> Bool
filterSilenceByState state silence =
-- TODO: Can this be done cleaner?
Maybe.withDefault False <| Maybe.map (.state >> (==) state) <| .status silence
{-
case silence.status of
Just status ->
status.state == state
Nothing ->
False
-}

View File

@ -2,7 +2,8 @@ module Views.SilenceView.Types exposing (Model, SilenceViewMsg(..), initSilenceV
import Alerts.Types exposing (Alert)
import Browser.Navigation exposing (Key)
import Silences.Types exposing (Silence, SilenceId)
import Data.Silence exposing (Silence)
import Data.Silences exposing (Silences)
import Utils.Types exposing (ApiData(..))
@ -11,7 +12,7 @@ type SilenceViewMsg
| SilenceFetched (ApiData Silence)
| SetActiveAlert (Maybe String)
| AlertGroupsPreview (ApiData (List Alert))
| InitSilenceView SilenceId
| InitSilenceView String
| ConfirmDestroySilence Silence Bool
| Reload String

View File

@ -45,6 +45,7 @@ update msg model apiUrl =
( { model | silence = silence, alerts = Initial }, Cmd.none )
InitSilenceView silenceId ->
-- TODO: silenceId should never be Nothing, can this be done cleaner?
( { model | showConfirmationDialog = False }, getSilence apiUrl silenceId SilenceFetched )
Reload silenceId ->

View File

@ -1,10 +1,13 @@
module Views.SilenceView.Views exposing (view)
import Alerts.Types exposing (Alert)
import Data.Silence exposing (Silence)
import Data.SilenceStatus
import Data.Silences exposing (Silences)
import Html exposing (Html, b, button, div, h1, h2, h3, label, p, span, text)
import Html.Attributes exposing (class, href)
import Html.Events exposing (onClick)
import Silences.Types exposing (Silence, stateToString)
import Silences.Types exposing (stateToString)
import Types exposing (Msg(..))
import Utils.Date exposing (dateTimeFormat)
import Utils.List
@ -54,13 +57,13 @@ viewSilence activeAlertId alerts silence showPromptDialog =
, expireButton silence False
]
]
, formGroup "ID" <| text silence.id
, formGroup "ID" <| text <| Maybe.withDefault "" silence.id
, formGroup "Starts at" <| text <| dateTimeFormat silence.startsAt
, formGroup "Ends at" <| text <| dateTimeFormat silence.endsAt
, formGroup "Updated at" <| text <| dateTimeFormat silence.updatedAt
, formGroup "Created by" <| text silence.createdBy
, formGroup "Updated at" <| text <| Maybe.withDefault "" <| Maybe.map dateTimeFormat silence.updatedAt
, formGroup "Created by" <| text <| silence.createdBy
, formGroup "Comment" <| text silence.comment
, formGroup "State" <| text <| stateToString silence.status.state
, formGroup "State" <| text <| Maybe.withDefault "" <| Maybe.map (.state >> stateToString) silence.status
, formGroup "Matchers" <|
div [] <|
List.map (Utils.List.mstring >> Utils.Views.labelButton Nothing) silence.matchers
@ -77,7 +80,8 @@ viewSilence activeAlertId alerts silence showPromptDialog =
confirmSilenceDeleteView : Silence -> Bool -> Dialog.Config Msg
confirmSilenceDeleteView silence refresh =
{ onClose = MsgForSilenceView (SilenceViewTypes.Reload silence.id)
-- TODO: silence.id should never be Nothing in this context. How to better handle this?
{ onClose = MsgForSilenceView (SilenceViewTypes.Reload <| Maybe.withDefault "" silence.id)
, title = "Expire Silence"
, body = text "Are you sure you want to expire this silence?"
, footer =
@ -101,22 +105,28 @@ formGroup key content =
expireButton : Silence -> Bool -> Html Msg
expireButton silence refresh =
case silence.status.state of
Silences.Types.Expired ->
-- TODO: .status should never be nothing, how can we handle this better?
case silence.status of
Just { state } ->
case state of
Data.SilenceStatus.Expired ->
text ""
Data.SilenceStatus.Active ->
button
[ class "btn btn-outline-danger border-0"
, onClick (MsgForSilenceView (SilenceViewTypes.ConfirmDestroySilence silence refresh))
]
[ text "Expire"
]
Data.SilenceStatus.Pending ->
button
[ class "btn btn-outline-danger border-0"
, onClick (MsgForSilenceView (SilenceViewTypes.ConfirmDestroySilence silence refresh))
]
[ text "Delete"
]
Nothing ->
text ""
Silences.Types.Active ->
button
[ class "btn btn-outline-danger border-0"
, onClick (MsgForSilenceView (SilenceViewTypes.ConfirmDestroySilence silence refresh))
]
[ text "Expire"
]
Silences.Types.Pending ->
button
[ class "btn btn-outline-danger border-0"
, onClick (MsgForSilenceView (SilenceViewTypes.ConfirmDestroySilence silence refresh))
]
[ text "Delete"
]

View File

@ -1,16 +1,17 @@
module Views.Status.Types exposing (StatusModel, StatusMsg(..), initStatusModel)
import Data.AlertmanagerStatus exposing (AlertmanagerStatus)
import Status.Types exposing (StatusResponse)
import Utils.Types exposing (ApiData(..))
type StatusMsg
= NewStatus (ApiData StatusResponse)
= NewStatus (ApiData AlertmanagerStatus)
| InitStatusView
type alias StatusModel =
{ statusInfo : ApiData StatusResponse
{ statusInfo : ApiData AlertmanagerStatus
}

View File

@ -12,4 +12,4 @@ update msg model basePath =
( { model | status = { statusInfo = apiResponse } }, Cmd.none )
InitStatusView ->
( model, getStatus basePath (NewStatus >> MsgForStatus) )
( model, getStatus "/api/v2/" (NewStatus >> MsgForStatus) )

View File

@ -1,9 +1,14 @@
module Views.Status.Views exposing (view)
import Data.AlertmanagerStatus exposing (AlertmanagerStatus)
import Data.ClusterStatus exposing (ClusterStatus)
import Data.PeerStatus exposing (PeerStatus)
import Data.VersionInfo exposing (VersionInfo)
import Html exposing (..)
import Html.Attributes exposing (class, classList, style)
import Status.Types exposing (ClusterPeer, ClusterStatus, StatusResponse, VersionInfo)
import Status.Types exposing (StatusResponse, VersionInfo)
import Types exposing (Msg(..))
import Utils.Date exposing (timeToString)
import Utils.Types exposing (ApiData(..))
import Utils.Views
import Views.Status.Types exposing (StatusModel)
@ -25,17 +30,17 @@ view { statusInfo } =
Utils.Views.error msg
viewStatusInfo : StatusResponse -> Html Types.Msg
viewStatusInfo : AlertmanagerStatus -> Html Types.Msg
viewStatusInfo status =
div []
[ h1 [] [ text "Status" ]
, div [ class "form-group row" ]
[ b [ class "col-sm-2" ] [ text "Uptime:" ]
, div [ class "col-sm-10" ] [ text status.uptime ]
, div [ class "col-sm-10" ] [ text <| timeToString status.uptime ]
]
, viewClusterStatus status.clusterStatus
, viewClusterStatus status.cluster
, viewVersionInformation status.versionInfo
, viewConfig status.config
, viewConfig status.config.original
]
@ -51,46 +56,36 @@ viewConfig config =
]
viewClusterStatus : Maybe ClusterStatus -> Html Types.Msg
viewClusterStatus clusterStatus =
case clusterStatus of
Just { name, status, peers } ->
span []
[ h2 [] [ text "Cluster Status" ]
, div [ class "form-group row" ]
[ b [ class "col-sm-2" ] [ text "Name:" ]
, div [ class "col-sm-10" ] [ text name ]
]
, div [ class "form-group row" ]
[ b [ class "col-sm-2" ] [ text "Status:" ]
, div [ class "col-sm-10" ]
[ span
[ classList
[ ( "badge", True )
, ( "badge-success", status == "ready" )
, ( "badge-warning", status == "settling" )
]
]
[ text status ]
viewClusterStatus : ClusterStatus -> Html Types.Msg
viewClusterStatus { name, status, peers } =
span []
[ h2 [] [ text "Cluster Status" ]
, div [ class "form-group row" ]
[ b [ class "col-sm-2" ] [ text "Name:" ]
, div [ class "col-sm-10" ] [ text name ]
]
, div [ class "form-group row" ]
[ b [ class "col-sm-2" ] [ text "Status:" ]
, div [ class "col-sm-10" ]
[ span
[ classList
[ ( "badge", True )
, ( "badge-success", status == "ready" )
, ( "badge-warning", status == "settling" )
]
]
, div [ class "form-group row" ]
[ b [ class "col-sm-2" ] [ text "Peers:" ]
, ul [ class "col-sm-10" ] <|
List.map viewClusterPeer peers
]
]
Nothing ->
span []
[ h2 [] [ text "Mesh Status" ]
, div [ class "form-group row" ]
[ div [ class "col-sm-10" ] [ text "Mesh not configured" ]
]
[ text status ]
]
]
, div [ class "form-group row" ]
[ b [ class "col-sm-2" ] [ text "Peers:" ]
, ul [ class "col-sm-10" ] <|
List.map viewClusterPeer peers
]
]
viewClusterPeer : ClusterPeer -> Html Types.Msg
viewClusterPeer : PeerStatus -> Html Types.Msg
viewClusterPeer peer =
li []
[ div [ class "" ]