0aaea8efb5
Assign logged only the assignee (user_id), archive/unarchive logged nothing. Migration 018 adds actor_user_id/actor_service_account_id to incident_events for 'assigned'; archive/unarchive now log archived/unarchived events with the caller via callerActorIDs. Timeline JSON gains actor_* fields; web timeline renders them. Service accounts are still not assignable.
120 lines
5.6 KiB
Go
120 lines
5.6 KiB
Go
package models
|
|
|
|
import "time"
|
|
|
|
// Incident is the human work item: the thing that gets acknowledged, assigned,
|
|
// snoozed, discussed and resolved. Alerts are the machine-owned signal records
|
|
// underneath it — many alerts map to one incident, correlated by the groupKey
|
|
// Alertmanager already computed from the operator's group_by configuration.
|
|
//
|
|
// Nothing here is ever written by the Alertmanager webhook except Status, which
|
|
// the webhook and the sweeper may flip to "resolved" once every member alert has
|
|
// stopped firing.
|
|
type Incident struct {
|
|
// EscalationLevel is which rung of its team's ladder this incident is on,
|
|
// 0 for none — either the team has no ladder, or somebody has answered.
|
|
// EscalationDueAt is when the current level runs out, so a client can say
|
|
// how long is left rather than only what already happened.
|
|
EscalationLevel int64 `json:"escalation_level"`
|
|
EscalationDueAt *time.Time `json:"escalation_due_at,omitempty"`
|
|
|
|
// TeamID is the team that owns this incident, fixed when it opens: an
|
|
// incident never moves between teams. TeamName rides along so the combined
|
|
// queue can badge each row without a second request.
|
|
TeamID int64 `json:"team_id"`
|
|
TeamName string `json:"team_name,omitempty"`
|
|
|
|
ID int64 `json:"id"`
|
|
GroupKey string `json:"group_key"`
|
|
Title string `json:"title"`
|
|
GroupLabels map[string]string `json:"group_labels"`
|
|
|
|
// Status is "triggered", "acknowledged" or "resolved".
|
|
Status string `json:"status"`
|
|
|
|
// Severity is the highest `severity` label across the alerts that were
|
|
// firing when it was last recomputed. It is deliberately not cleared when an
|
|
// incident resolves — a resolved incident should still say how bad it was.
|
|
Severity *string `json:"severity,omitempty"`
|
|
|
|
TriggeredAt time.Time `json:"triggered_at"`
|
|
|
|
AcknowledgedByID *int64 `json:"acknowledged_by_id,omitempty"`
|
|
AcknowledgedByUser *string `json:"acknowledged_by,omitempty"`
|
|
AcknowledgedAt *time.Time `json:"acknowledged_at,omitempty"`
|
|
|
|
// AcknowledgedByServiceAccountID/Name are the service-account-shaped
|
|
// parallel to AcknowledgedByID/User above: mutually exclusive with it,
|
|
// populated when a service account (not a human) acknowledged this
|
|
// incident. See migration 015 and terdut-server#25.
|
|
AcknowledgedByServiceAccountID *int64 `json:"acknowledged_by_service_account_id,omitempty"`
|
|
AcknowledgedByServiceAccountName *string `json:"acknowledged_by_service_account,omitempty"`
|
|
|
|
AssignedToID *int64 `json:"assigned_to_id,omitempty"`
|
|
AssignedToUser *string `json:"assigned_to,omitempty"`
|
|
|
|
// SnoozedUntil hides the incident from the default queue without closing it.
|
|
// A timestamp in the past reads as "not snoozed"; nothing sweeps it.
|
|
SnoozedUntil *time.Time `json:"snoozed_until,omitempty"`
|
|
|
|
ResolvedAt *time.Time `json:"resolved_at,omitempty"`
|
|
|
|
// ResolutionSource is "alerts" when every member alert stopped firing, or
|
|
// "manual" when a human closed it. Manual resolution is terminal: a later
|
|
// occurrence opens a new incident rather than reopening this one.
|
|
ResolutionSource *string `json:"resolution_source,omitempty"`
|
|
|
|
ArchivedAt *time.Time `json:"archived_at,omitempty"`
|
|
|
|
// Alerts is populated by GET /api/incidents/{id} only.
|
|
Alerts []Alert `json:"alerts,omitempty"`
|
|
}
|
|
|
|
// IncidentEvent is one entry in an incident's timeline. The table is append-only
|
|
// and is the only history this server keeps — alert rows are mutated in place.
|
|
//
|
|
// Type is one of: triggered, alert_added, alert_resolved, acknowledged,
|
|
// unacknowledged, assigned, archived, unarchived, snoozed, unsnoozed,
|
|
// resolved, note. UserID and
|
|
// ServiceAccountID are mutually exclusive; both nil means the server acted
|
|
// rather than any caller.
|
|
type IncidentEvent struct {
|
|
ID int64 `json:"id"`
|
|
IncidentID int64 `json:"incident_id"`
|
|
Type string `json:"type"`
|
|
UserID *int64 `json:"user_id,omitempty"`
|
|
Username *string `json:"username,omitempty"`
|
|
|
|
// ServiceAccountID/Name are the service-account-shaped parallel to
|
|
// UserID/Username above: mutually exclusive with it, populated when a
|
|
// service account (not a human, and not nil-meaning-the-server-acted)
|
|
// performed this event. Named Name, not Username — a ServiceAccount has
|
|
// a Name field, not a Username. See migration 015 and terdut-server#25.
|
|
ServiceAccountID *int64 `json:"service_account_id,omitempty"`
|
|
ServiceAccountName *string `json:"service_account_name,omitempty"`
|
|
|
|
// Actor* name who performed an 'assigned' event, whose UserID is the
|
|
// assignee. Mutually exclusive; unset on every other event type and on
|
|
// assignments made before migration 018. See terdut-server#35.
|
|
ActorUserID *int64 `json:"actor_user_id,omitempty"`
|
|
ActorUsername *string `json:"actor_username,omitempty"`
|
|
ActorServiceAccountID *int64 `json:"actor_service_account_id,omitempty"`
|
|
ActorServiceAccountName *string `json:"actor_service_account_name,omitempty"`
|
|
|
|
AlertID *int64 `json:"alert_id,omitempty"`
|
|
Detail *string `json:"detail,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// SimilarIncident is an earlier, resolved incident with the same signature as
|
|
// the one being looked at. ResolutionNotes are the "what fixed it" notes;
|
|
// NoteCount counts the plain working notes, which live on the timeline.
|
|
type SimilarIncident struct {
|
|
ID int64 `json:"id"`
|
|
Title string `json:"title"`
|
|
TriggeredAt time.Time `json:"triggered_at"`
|
|
ResolvedAt time.Time `json:"resolved_at"`
|
|
NoteCount int `json:"note_count"`
|
|
ResolutionNotes []IncidentEvent `json:"resolution_notes"`
|
|
}
|