diff --git a/manager/api.go b/manager/api.go index d8219597..041825f1 100644 --- a/manager/api.go +++ b/manager/api.go @@ -21,8 +21,9 @@ func NewAPI(r *route.Router, s State) *API { state: s, context: route.Context, } - // r.Get("/alerts", s.getAlerts) - // r.Post("/alerts", s.addAlerts) + + r.Get("/alerts", api.listAlerts) + r.Post("/alerts", api.addAlerts) r.Get("/silences", api.listSilences) r.Post("/silences", api.addSilence) @@ -52,6 +53,36 @@ func (e *apiError) Error() string { return fmt.Sprintf("%s: %s", e.typ, e.err) } +func (api *API) listAlerts(w http.ResponseWriter, r *http.Request) { + alerts, err := api.state.Alert().GetAll() + if err != nil { + respondError(w, apiError{ + typ: errorBadData, + err: err, + }, nil) + return + } + respond(w, alerts) +} + +func (api *API) addAlerts(w http.ResponseWriter, r *http.Request) { + var alerts []*Alert + if err := receive(r, &alerts); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + // TODO(fabxc): validate input. + if err := api.state.Alert().Add(alerts...); err != nil { + respondError(w, apiError{ + typ: errorBadData, + err: err, + }, nil) + return + } + + respond(w, nil) +} + func (api *API) addSilence(w http.ResponseWriter, r *http.Request) { var sil Silence if err := receive(r, &sil); err != nil { diff --git a/manager/state.go b/manager/state.go index aacaa71e..96b3e2eb 100644 --- a/manager/state.go +++ b/manager/state.go @@ -12,10 +12,13 @@ type State interface { Silence() SilenceState // Config() ConfigState // Notify() NotifyState - // Alert() AlertState + Alert() AlertState } -type AlertState interface{} +type AlertState interface { + Add(...*Alert) error + GetAll() ([]*Alert, error) +} type ConfigState interface{} @@ -34,7 +37,7 @@ type SilenceState interface { // memState implements the State interface based on in-memory storage. type memState struct { silences *memSilences - mtx sync.RWMutex + alerts *memAlerts } func NewMemState() State { @@ -43,13 +46,41 @@ func NewMemState() State { m: map[string]*Silence{}, nextID: 1, }, + alerts: &memAlerts{}, } } +func (s *memState) Alert() AlertState { + return s.alerts +} + func (s *memState) Silence() SilenceState { return s.silences } +type memAlerts struct { + alerts []*Alert + mtx sync.RWMutex +} + +func (s *memAlerts) GetAll() ([]*Alert, error) { + s.mtx.RLock() + defer s.mtx.RUnlock() + + alerts := make([]*Alert, len(s.alerts)) + copy(alerts, s.alerts) + + return alerts, nil +} + +func (s *memAlerts) Add(alerts ...*Alert) error { + s.mtx.Lock() + defer s.mtx.Unlock() + + s.alerts = append(s.alerts, alerts...) + return nil +} + type memSilences struct { m map[string]*Silence mtx sync.RWMutex