Skip to content

Commit

Permalink
Add option to re-escalate the alert
Browse files Browse the repository at this point in the history
Adds a key command (ctrl+e) to re-assign the alert to the escalation
policy level 1 (ie: re-escalate), to reassign at the end of an SRE's
shift.

Signed-off-by: Chris Collins <[email protected]>
  • Loading branch information
clcollins committed Jul 30, 2024
1 parent 5cebda4 commit b85e627
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 15 deletions.
29 changes: 20 additions & 9 deletions pkg/pd/pd.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,21 +103,33 @@ func NewListIncidentOptsFromDefaults() pagerduty.ListIncidentsOptions {
func AcknowledgeIncident(client PagerDutyClient, incidents []pagerduty.Incident, user *pagerduty.User) ([]pagerduty.Incident, error) {
var ctx = context.Background()
var i []pagerduty.Incident
var email string

opts := []pagerduty.ManageIncidentsOptions{}

for _, incident := range incidents {
opts = append(opts, pagerduty.ManageIncidentsOptions{
ID: incident.ID,
Status: "acknowledged",
Assignments: []pagerduty.Assignee{{
Assignee: user.APIObject,
}},
})
if user == nil {
email = ""
opts = append(opts, pagerduty.ManageIncidentsOptions{
ID: incident.ID,
EscalationLevel: 1,
})
} else {
email = user.Email
opts = append(opts, pagerduty.ManageIncidentsOptions{
ID: incident.ID,
Status: "acknowledged",
Assignments: []pagerduty.Assignee{
{
Assignee: user.APIObject,
},
},
})
}
}

for {
response, err := client.ManageIncidentsWithContext(ctx, user.Email, opts)
response, err := client.ManageIncidentsWithContext(ctx, email, opts)
if err != nil {
return i, fmt.Errorf("pd.AcknowledgeIncident(): failed to acknowledge incident(s) `%v`: %v", incidents, err)
}
Expand All @@ -131,7 +143,6 @@ func AcknowledgeIncident(client PagerDutyClient, incidents []pagerduty.Incident,
if !response.More {
break
}

}

return i, nil
Expand Down
24 changes: 22 additions & 2 deletions pkg/tui/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,23 +382,43 @@ type clearSelectedIncidentsMsg string
type acknowledgeIncidentsMsg struct {
incidents []pagerduty.Incident
}
type unAcknowledgeIncidentsMsg struct {
incidents []pagerduty.Incident
}
type acknowledgedIncidentsMsg struct {
incidents []pagerduty.Incident
err error
}
type unAcknowledgedIncidentsMsg struct {
incidents []pagerduty.Incident
err error
}

type waitForSelectedIncidentsThenAcknowledgeMsg string
type waitForSelectedIncidentsThenUnAcknowledgeMsg string

func acknowledgeIncidents(p *pd.Config, incidents []pagerduty.Incident) tea.Cmd {
func acknowledgeIncidents(p *pd.Config, incidents []pagerduty.Incident, reescalate bool) tea.Cmd {
return func() tea.Msg {
u, err := p.Client.GetCurrentUserWithContext(context.Background(), pagerduty.GetCurrentUserOptions{})
var u *pagerduty.User
var err error

if reescalate {
a, err := pd.AcknowledgeIncident(p.Client, incidents, u)
if err != nil {
return errMsg{err}
}
return unAcknowledgedIncidentsMsg{a, err}
}

u, err = p.Client.GetCurrentUserWithContext(context.Background(), pagerduty.GetCurrentUserOptions{})
if err != nil {
return errMsg{err}
}
a, err := pd.AcknowledgeIncident(p.Client, incidents, u)
if err != nil {
return errMsg{err}
}

return acknowledgedIncidentsMsg{a, err}
}
}
Expand Down
7 changes: 6 additions & 1 deletion pkg/tui/keymap.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func (k keymap) FullHelp() [][]key.Binding {
return [][]key.Binding{
// Each slice here is a column in the help window
{k.Up, k.Down, k.Enter, k.Back},
{k.Ack, k.Note, k.Silence},
{k.Ack, k.UnAck, k.Note, k.Silence},
{k.Login, k.Open},
{k.Team, k.Refresh, k.AutoRefresh, k.AutoAck},
{k.Quit, k.Help},
Expand All @@ -33,6 +33,7 @@ type keymap struct {
Note key.Binding
Silence key.Binding
Ack key.Binding
UnAck key.Binding
AutoAck key.Binding
Input key.Binding
Login key.Binding
Expand Down Expand Up @@ -96,6 +97,10 @@ var defaultKeyMap = keymap{
key.WithKeys("a"),
key.WithHelp("a", "acknowledge"),
),
UnAck: key.NewBinding(
key.WithKeys("ctrl+e"),
key.WithHelp("ctrl+e", "re-escalate"),
),
AutoAck: key.NewBinding(
key.WithKeys("ctrl+a"),
key.WithHelp("ctrl+a", "toggle auto-acknowledge"),
Expand Down
9 changes: 7 additions & 2 deletions pkg/tui/msgHandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ func (m model) windowSizeMsgHandler(msg tea.Msg) (tea.Model, tea.Cmd) {

estimatedExtraLinesFromComponents := 7 // TODO: figure out how to calculate this


horizontalScratchWidth := horizontalMargins + horizontalPadding + horizontalBorders
verticalScratchWidth := verticalMargins + verticalPadding + verticalBorders

Expand Down Expand Up @@ -219,7 +218,13 @@ func switchTableFocusMode(m model, msg tea.Msg) (tea.Model, tea.Cmd) {
case key.Matches(msg, defaultKeyMap.Ack):
return m, doIfIncidentSelected(&m, tea.Sequence(
func() tea.Msg { return getIncidentMsg(incidentID) },
func() tea.Msg { return waitForSelectedIncidentsThenAcknowledgeMsg("wait") },
func() tea.Msg { return waitForSelectedIncidentsThenAcknowledgeMsg("Ack") },
))

case key.Matches(msg, defaultKeyMap.UnAck):
return m, doIfIncidentSelected(&m, tea.Sequence(
func() tea.Msg { return getIncidentMsg(incidentID) },
func() tea.Msg { return waitForSelectedIncidentsThenUnAcknowledgeMsg("UnAck") },
))

case key.Matches(msg, defaultKeyMap.Note):
Expand Down
36 changes: 35 additions & 1 deletion pkg/tui/tui.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,18 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

return m, tea.Sequence(
acknowledgeIncidents(m.config, msg.incidents),
acknowledgeIncidents(m.config, msg.incidents, false),
func() tea.Msg { return clearSelectedIncidentsMsg("sender: acknowledgeIncidentsMsg") },
)

case unAcknowledgeIncidentsMsg:
if msg.incidents == nil {
m.setStatus("failed re-escalating incidents - no incidents provided")
return m, nil
}

return m, tea.Sequence(
acknowledgeIncidents(m.config, msg.incidents, true),
func() tea.Msg { return clearSelectedIncidentsMsg("sender: acknowledgeIncidentsMsg") },
)

Expand All @@ -381,6 +392,19 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

return m, func() tea.Msg { return updateIncidentListMsg("sender: acknowledgedIncidentsMsg") }

case unAcknowledgedIncidentsMsg:
var incidentIDs []string
if msg.err != nil {
return m, func() tea.Msg { return errMsg{msg.err} }
}
for _, i := range msg.incidents {
incidentIDs = append(incidentIDs, i.ID)
}
incidents := strings.Join(incidentIDs, " ")
m.setStatus(fmt.Sprintf("re-escalated incidents: " + incidents))

return m, func() tea.Msg { return updateIncidentListMsg("sender: acknowledgedIncidentsMsg") }

case waitForSelectedIncidentsThenAcknowledgeMsg:
if m.selectedIncident == nil {
time.Sleep(waitTime)
Expand All @@ -391,6 +415,16 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return acknowledgeIncidentsMsg{incidents: []pagerduty.Incident{*m.selectedIncident}}
}

case waitForSelectedIncidentsThenUnAcknowledgeMsg:
if m.selectedIncident == nil {
time.Sleep(waitTime)
m.setStatus("waiting for incident info...")
return m, func() tea.Msg { return waitForSelectedIncidentsThenUnAcknowledgeMsg(msg) }
}
return m, func() tea.Msg {
return unAcknowledgeIncidentsMsg{incidents: []pagerduty.Incident{*m.selectedIncident}}
}

case reassignIncidentsMsg:
if msg.incidents == nil {
m.setStatus("failed reassigning incidents - no incidents provided")
Expand Down

0 comments on commit b85e627

Please sign in to comment.