Add maintenance windows for planned work
This commit is contained in:
@@ -6,16 +6,18 @@ import (
|
||||
)
|
||||
|
||||
type AlertEvent struct {
|
||||
EventID int64 `json:"eventId"`
|
||||
ID string `json:"id"`
|
||||
Severity string `json:"severity"`
|
||||
Source string `json:"source"`
|
||||
Title string `json:"title"`
|
||||
Message string `json:"message"`
|
||||
FirstSeen int64 `json:"firstSeen"`
|
||||
LastSeen int64 `json:"lastSeen"`
|
||||
ResolvedAt *int64 `json:"resolvedAt,omitempty"`
|
||||
AcknowledgedAt *int64 `json:"acknowledgedAt,omitempty"`
|
||||
EventID int64 `json:"eventId"`
|
||||
ID string `json:"id"`
|
||||
Severity string `json:"severity"`
|
||||
Source string `json:"source"`
|
||||
Title string `json:"title"`
|
||||
Message string `json:"message"`
|
||||
FirstSeen int64 `json:"firstSeen"`
|
||||
LastSeen int64 `json:"lastSeen"`
|
||||
ResolvedAt *int64 `json:"resolvedAt,omitempty"`
|
||||
AcknowledgedAt *int64 `json:"acknowledgedAt,omitempty"`
|
||||
Planned bool `json:"planned"`
|
||||
MaintenanceReason string `json:"maintenanceReason,omitempty"`
|
||||
}
|
||||
|
||||
type RecoveryEvent struct {
|
||||
@@ -24,13 +26,17 @@ type RecoveryEvent struct {
|
||||
}
|
||||
|
||||
func (s *Store) SyncAlerts(alerts []Alert) ([]Alert, error) {
|
||||
return s.SyncAlertsWithMaintenance(alerts, nil, "")
|
||||
}
|
||||
|
||||
func (s *Store) SyncAlertsWithMaintenance(alerts, plannedAlerts []Alert, maintenanceReason string) ([]Alert, error) {
|
||||
tx, err := s.db.Begin()
|
||||
if err != nil {
|
||||
return alerts, err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
now := time.Now().Unix()
|
||||
rows, err := tx.Query(`SELECT id,alert_key FROM alert_events WHERE resolved_at IS NULL`)
|
||||
rows, err := tx.Query(`SELECT id,alert_key,planned FROM alert_events WHERE resolved_at IS NULL`)
|
||||
if err != nil {
|
||||
return alerts, err
|
||||
}
|
||||
@@ -38,28 +44,43 @@ func (s *Store) SyncAlerts(alerts []Alert) ([]Alert, error) {
|
||||
for rows.Next() {
|
||||
var id int64
|
||||
var key string
|
||||
if err := rows.Scan(&id, &key); err != nil {
|
||||
var planned bool
|
||||
if err := rows.Scan(&id, &key, &planned); err != nil {
|
||||
rows.Close()
|
||||
return alerts, err
|
||||
}
|
||||
active[key] = id
|
||||
active[alertEventKey(key, planned)] = id
|
||||
}
|
||||
rows.Close()
|
||||
seen := map[string]bool{}
|
||||
for _, alert := range alerts {
|
||||
seen[alert.ID] = true
|
||||
if id, ok := active[alert.ID]; ok {
|
||||
_, err = tx.Exec(`UPDATE alert_events SET severity=?,source=?,title=?,message=?,last_seen=? WHERE id=?`, alert.Severity, alert.Source, alert.Title, alert.Message, now, id)
|
||||
} else {
|
||||
result, insertErr := tx.Exec(`INSERT INTO alert_events(alert_key,severity,source,title,message,first_seen,last_seen) VALUES(?,?,?,?,?,?,?)`, alert.ID, alert.Severity, alert.Source, alert.Title, alert.Message, now, now)
|
||||
if insertErr != nil {
|
||||
return alerts, insertErr
|
||||
syncGroup := func(group []Alert, planned bool) error {
|
||||
for _, alert := range group {
|
||||
key := alertEventKey(alert.ID, planned)
|
||||
seen[key] = true
|
||||
reason := ""
|
||||
if planned {
|
||||
reason = maintenanceReason
|
||||
}
|
||||
if id, ok := active[key]; ok {
|
||||
_, err = tx.Exec(`UPDATE alert_events SET severity=?,source=?,title=?,message=?,last_seen=?,maintenance_reason=? WHERE id=?`, alert.Severity, alert.Source, alert.Title, alert.Message, now, reason, id)
|
||||
} else {
|
||||
result, insertErr := tx.Exec(`INSERT INTO alert_events(alert_key,severity,source,title,message,first_seen,last_seen,planned,maintenance_reason) VALUES(?,?,?,?,?,?,?,?,?)`, alert.ID, alert.Severity, alert.Source, alert.Title, alert.Message, now, now, planned, reason)
|
||||
if insertErr != nil {
|
||||
return insertErr
|
||||
}
|
||||
active[key], _ = result.LastInsertId()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
active[alert.ID], _ = result.LastInsertId()
|
||||
}
|
||||
if err != nil {
|
||||
return alerts, err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err = syncGroup(alerts, false); err != nil {
|
||||
return alerts, err
|
||||
}
|
||||
if err = syncGroup(plannedAlerts, true); err != nil {
|
||||
return alerts, err
|
||||
}
|
||||
for key, id := range active {
|
||||
if !seen[key] {
|
||||
@@ -74,7 +95,7 @@ func (s *Store) SyncAlerts(alerts []Alert) ([]Alert, error) {
|
||||
if err = tx.Commit(); err != nil {
|
||||
return alerts, err
|
||||
}
|
||||
rows, err = s.db.Query(`SELECT id,alert_key,severity,source,title,message,first_seen,last_seen FROM alert_events WHERE resolved_at IS NULL AND acknowledged_at IS NULL ORDER BY CASE severity WHEN 'critical' THEN 0 WHEN 'warning' THEN 1 ELSE 2 END,first_seen DESC`)
|
||||
rows, err = s.db.Query(`SELECT id,alert_key,severity,source,title,message,first_seen,last_seen FROM alert_events WHERE resolved_at IS NULL AND acknowledged_at IS NULL AND planned=0 ORDER BY CASE severity WHEN 'critical' THEN 0 WHEN 'warning' THEN 1 ELSE 2 END,first_seen DESC`)
|
||||
if err != nil {
|
||||
return alerts, err
|
||||
}
|
||||
@@ -90,6 +111,13 @@ func (s *Store) SyncAlerts(alerts []Alert) ([]Alert, error) {
|
||||
return visible, rows.Err()
|
||||
}
|
||||
|
||||
func alertEventKey(id string, planned bool) string {
|
||||
if planned {
|
||||
return id + "\x00planned"
|
||||
}
|
||||
return id + "\x00active"
|
||||
}
|
||||
|
||||
func (s *Store) AcknowledgeAlert(eventID int64) error {
|
||||
_, err := s.db.Exec(`UPDATE alert_events SET acknowledged_at=? WHERE id=? AND acknowledged_at IS NULL`, time.Now().Unix(), eventID)
|
||||
return err
|
||||
@@ -99,7 +127,7 @@ func (s *Store) AlertHistory(limit int) ([]AlertEvent, error) {
|
||||
if limit < 1 || limit > 500 {
|
||||
limit = 200
|
||||
}
|
||||
rows, err := s.db.Query(`SELECT id,alert_key,severity,source,title,message,first_seen,last_seen,resolved_at,acknowledged_at FROM alert_events ORDER BY first_seen DESC LIMIT ?`, limit)
|
||||
rows, err := s.db.Query(`SELECT id,alert_key,severity,source,title,message,first_seen,last_seen,resolved_at,acknowledged_at,planned,maintenance_reason FROM alert_events ORDER BY first_seen DESC LIMIT ?`, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -108,7 +136,7 @@ func (s *Store) AlertHistory(limit int) ([]AlertEvent, error) {
|
||||
for rows.Next() {
|
||||
var e AlertEvent
|
||||
var resolved, acked sql.NullInt64
|
||||
if err = rows.Scan(&e.EventID, &e.ID, &e.Severity, &e.Source, &e.Title, &e.Message, &e.FirstSeen, &e.LastSeen, &resolved, &acked); err != nil {
|
||||
if err = rows.Scan(&e.EventID, &e.ID, &e.Severity, &e.Source, &e.Title, &e.Message, &e.FirstSeen, &e.LastSeen, &resolved, &acked, &e.Planned, &e.MaintenanceReason); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resolved.Valid {
|
||||
@@ -123,7 +151,7 @@ func (s *Store) AlertHistory(limit int) ([]AlertEvent, error) {
|
||||
}
|
||||
|
||||
func (s *Store) PendingEmailAlerts() ([]Alert, error) {
|
||||
rows, err := s.db.Query(`SELECT id,alert_key,severity,source,title,message FROM alert_events WHERE resolved_at IS NULL AND acknowledged_at IS NULL AND email_sent_at IS NULL ORDER BY first_seen`)
|
||||
rows, err := s.db.Query(`SELECT id,alert_key,severity,source,title,message FROM alert_events WHERE resolved_at IS NULL AND acknowledged_at IS NULL AND email_sent_at IS NULL AND planned=0 ORDER BY first_seen`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -155,7 +183,7 @@ func (s *Store) MarkAlertsEmailed(alerts []Alert) error {
|
||||
}
|
||||
|
||||
func (s *Store) PendingImmediateAlerts() ([]Alert, error) {
|
||||
rows, err := s.db.Query(`SELECT id,alert_key,severity,source,title,message FROM alert_events WHERE resolved_at IS NULL AND acknowledged_at IS NULL AND email_sent_at IS NULL AND (severity='critical' OR alert_key='ups-battery') ORDER BY first_seen`)
|
||||
rows, err := s.db.Query(`SELECT id,alert_key,severity,source,title,message FROM alert_events WHERE resolved_at IS NULL AND acknowledged_at IS NULL AND email_sent_at IS NULL AND planned=0 AND (severity='critical' OR alert_key='ups-battery') ORDER BY first_seen`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -171,7 +199,7 @@ func (s *Store) PendingImmediateAlerts() ([]Alert, error) {
|
||||
return out, rows.Err()
|
||||
}
|
||||
func (s *Store) PendingRecoveries() ([]RecoveryEvent, error) {
|
||||
rows, err := s.db.Query(`SELECT id,alert_key,severity,source,title,message FROM alert_events WHERE resolved_at IS NOT NULL AND email_sent_at IS NOT NULL AND recovery_sent_at IS NULL ORDER BY resolved_at`)
|
||||
rows, err := s.db.Query(`SELECT id,alert_key,severity,source,title,message FROM alert_events WHERE resolved_at IS NOT NULL AND email_sent_at IS NOT NULL AND recovery_sent_at IS NULL AND planned=0 ORDER BY resolved_at`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user