Skip to content

Commit

Permalink
initial minimal alert model
Browse files Browse the repository at this point in the history
  • Loading branch information
equinox0815 committed Oct 13, 2023
1 parent 28ec264 commit f06c68a
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 8 deletions.
18 changes: 18 additions & 0 deletions api/v1/alerts.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"net/http"

"github.com/gin-gonic/gin"
"github.com/whawty/alerts/store"
)

func (api *API) ListAlerts(c *gin.Context) {
Expand Down Expand Up @@ -61,6 +62,23 @@ func (api *API) ReadAlert(c *gin.Context) {
c.JSON(http.StatusOK, alert)
}

func (api *API) UpdateAlertState(c *gin.Context) {
id := c.Param("alert-id")

var state store.AlertState
if err := state.FromString(c.Query("state")); err != nil {
c.JSON(http.StatusBadRequest, ErrorResponse{Error: err.Error()})
return
}

alert, err := api.store.SetAlertState(id, state)
if err != nil {
sendError(c, err)
return
}
c.JSON(http.StatusOK, alert)
}

func (api *API) DeleteAlert(c *gin.Context) {
id := c.Param("alert-id")

Expand Down
1 change: 1 addition & 0 deletions api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func InstallHTTPHandler(r *gin.RouterGroup, st *store.Store) {
{
alerts.GET("", api.ListAlerts)
alerts.GET(":alert-id", api.ReadAlert)
alerts.PATCH(":alert-id/state", api.UpdateAlertState)
alerts.DELETE(":alert-id", api.DeleteAlert)
}

Expand Down
15 changes: 10 additions & 5 deletions api/v1/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,16 @@ func statusCodeFromError(err error) (code int, response ErrorResponse) {
code = http.StatusInternalServerError
response = ErrorResponse{Error: err.Error()}

switch err {
case store.ErrNotImplemented:
code = http.StatusNotImplemented
case store.ErrNotFound:
code = http.StatusNotFound
switch err.(type) {
case store.ErrInvalidStateTransition:
code = http.StatusConflict
default:
switch err {
case store.ErrNotImplemented:
code = http.StatusNotImplemented
case store.ErrNotFound:
code = http.StatusNotFound
}
}
return
}
Expand Down
5 changes: 5 additions & 0 deletions store/alerts.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ func (s *Store) GetAlert(id string) (*Alert, error) {
return nil, ErrNotImplemented
}

func (s *Store) SetAlertState(id string, new AlertState) (*Alert, error) {
// TODO: implement this
return nil, ErrNotImplemented
}

func (s *Store) DeleteAlert(id string) error {
// TODO: implement this
return ErrNotImplemented
Expand Down
119 changes: 116 additions & 3 deletions store/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,131 @@ package store

import (
"errors"
"fmt"
"time"
)

// Errors

var (
ErrNotImplemented = errors.New("not implemented")
ErrNotFound = errors.New("not found")
)

type ErrInvalidStateTransition struct {
old AlertState
new AlertState
}

func (e ErrInvalidStateTransition) Error() string {
return fmt.Sprintf("invalid alert state transition: %s -> %s", e.old.String(), e.new.String())
}

// Alerts

type AlertState uint

const (
StateNew AlertState = iota
StateOpen
StateAcknowledged
StateStale
StateClosed
)

func (s AlertState) String() string {
switch s {
case StateNew:
return "new"
case StateOpen:
return "open"
case StateAcknowledged:
return "acknowledged"
case StateStale:
return "stale"
case StateClosed:
return "closed"
}
return "unknown"
}

func (s *AlertState) FromString(str string) error {
switch str {
case "new":
*s = StateNew
case "open":
*s = StateOpen
case "acknowledged":
*s = StateAcknowledged
case "stale":
*s = StateStale
case "closed":
*s = StateClosed
default:
return errors.New("invalid alert state: '" + str + "'")
}
return nil
}

func (s AlertState) MarshalText() (data []byte, err error) {
data = []byte(s.String())
return
}

func (s *AlertState) UnmarshalText(data []byte) (err error) {
return s.FromString(string(data))
}

type AlertSeverity uint

const (
SeverityCritical AlertSeverity = iota
SeverityWarning
SeverityInformational
)

func (s AlertSeverity) String() string {
switch s {
case SeverityCritical:
return "critical"
case SeverityWarning:
return "warning"
case SeverityInformational:
return "informational"
}
return "unknown"
}

func (s *AlertSeverity) FromString(str string) error {
switch str {
case "critical":
*s = SeverityCritical
case "warning":
*s = SeverityWarning
case "informational":
*s = SeverityInformational
default:
return errors.New("invalid alert severity: '" + str + "'")
}
return nil
}

func (s AlertSeverity) MarshalText() (data []byte, err error) {
data = []byte(s.String())
return
}

func (s *AlertSeverity) UnmarshalText(data []byte) (err error) {
return s.FromString(string(data))
}

type Alert struct {
ID string `json:"id"`
CreatedAt time.Time `json:"created"`
UpdatedAt time.Time `json:"updated"`
ID string `json:"id"`
CreatedAt time.Time `json:"created"`
UpdatedAt time.Time `json:"updated"`
Name string `json:"name"`
State AlertState `json:"state"`
Severity AlertSeverity `json:"severity"`
}

func (a Alert) String() string {
Expand Down

0 comments on commit f06c68a

Please sign in to comment.