Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: paginate silences #49

Merged
merged 1 commit into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ linters:
- mnd
- perfsprint
- testpackage
- interfacebloat
2 changes: 2 additions & 0 deletions pkg/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@
a.Bot.Handle("/alertmanager_unsilence", a.HandleDeleteSilenceViaCommand(a.Alertmanager))

// Callbacks
a.Bot.Handle("\f"+constants.GrafanaPaginatedSilencesList, a.HandleListSilencesFromCallback(a.Grafana))
a.Bot.Handle("\f"+constants.AlertmanagerPaginatedSilencesList, a.HandleListSilencesFromCallback(a.Alertmanager))

Check warning on line 86 in pkg/app/app.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/app.go#L85-L86

Added lines #L85 - L86 were not covered by tests
a.Bot.Handle("\f"+constants.GrafanaUnsilencePrefix, a.HandleCallbackDeleteSilence(a.Grafana))
a.Bot.Handle("\f"+constants.AlertmanagerUnsilencePrefix, a.HandleCallbackDeleteSilence(a.Alertmanager))
a.Bot.Handle("\f"+constants.GrafanaPrepareSilencePrefix, a.HandlePrepareNewSilenceFromCallback(a.Grafana, a.Grafana))
Expand Down
153 changes: 110 additions & 43 deletions pkg/app/silences_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"main/pkg/types"
"main/pkg/types/render"
"main/pkg/utils/generic"
"strconv"

tele "gopkg.in/telebot.v3"
)
Expand All @@ -18,57 +19,123 @@
Str("silence_manager", silenceManager.Name()).
Msg("Got list silence query")

if !silenceManager.Enabled() {
return c.Reply(silenceManager.Name() + " is disabled.")
}
return a.HandleListSilencesWithPagination(c, silenceManager, 0, false)
}

Check warning on line 23 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L22-L23

Added lines #L22 - L23 were not covered by tests
}

func (a *App) HandleListSilencesFromCallback(silenceManager types.SilenceManager) func(c tele.Context) error {
return func(c tele.Context) error {
callback := c.Callback()

Check warning on line 28 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L26-L28

Added lines #L26 - L28 were not covered by tests

silencesWithAlerts, err := types.GetSilencesWithAlerts(silenceManager)
a.Logger.Info().
Str("sender", c.Sender().Username).
Str("silence_manager", silenceManager.Name()).
Str("data", callback.Data).
Msg("Got list silence query via callback")

page, err := strconv.Atoi(callback.Data)

Check warning on line 36 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L30-L36

Added lines #L30 - L36 were not covered by tests
if err != nil {
return c.Reply(fmt.Sprintf("Error fetching silences: %s\n", err))
return c.Reply("Failed to parse page number from callback!")

Check warning on line 38 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L38

Added line #L38 was not covered by tests
}

silencesGrouped := generic.SplitArrayIntoChunks(silencesWithAlerts, constants.SilencesInOneMessage)
if len(silencesGrouped) == 0 {
silencesGrouped = [][]types.SilenceWithAlerts{{}}
return a.HandleListSilencesWithPagination(c, silenceManager, page, true)

Check warning on line 41 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L41

Added line #L41 was not covered by tests
}
}

func (a *App) HandleListSilencesWithPagination(
c tele.Context,
silenceManager types.SilenceManager,
page int,
editPrevious bool,
) error {
if !silenceManager.Enabled() {
return c.Reply(silenceManager.Name() + " is disabled.")
}

Check warning on line 53 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L50-L53

Added lines #L50 - L53 were not covered by tests

silencesWithAlerts, err := types.GetSilencesWithAlerts(silenceManager)
if err != nil {
return c.Reply(fmt.Sprintf("Error fetching silences: %s\n", err))
}

Check warning on line 58 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L55-L58

Added lines #L55 - L58 were not covered by tests

silencesGrouped := generic.SplitArrayIntoChunks(silencesWithAlerts, constants.SilencesInOneMessage)
if len(silencesGrouped) == 0 {
silencesGrouped = [][]types.SilenceWithAlerts{{}}
}

Check warning on line 63 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L60-L63

Added lines #L60 - L63 were not covered by tests

chunk := []types.SilenceWithAlerts{}
if page < len(silencesGrouped) {
chunk = silencesGrouped[page]
}

Check warning on line 68 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L65-L68

Added lines #L65 - L68 were not covered by tests

template, renderErr := a.TemplateManager.Render("silences_list", render.RenderStruct{
Grafana: a.Grafana,
Alertmanager: a.Alertmanager,
Data: types.SilencesListStruct{
Silences: chunk,
ShowHeader: true,
Start: page*constants.SilencesInOneMessage + 1,
End: page*constants.SilencesInOneMessage + len(chunk),
SilencesCount: len(silencesWithAlerts),
},
})

if renderErr != nil {
a.Logger.Error().Err(renderErr).Msg("Error rendering silences_list template")
return c.Reply(fmt.Sprintf("Error rendering template: %s", renderErr))
}

Check warning on line 85 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L70-L85

Added lines #L70 - L85 were not covered by tests

menu := &tele.ReplyMarkup{ResizeKeyboard: true}

rows := make([]tele.Row, 0)

for _, silence := range chunk {
button := menu.Data(
fmt.Sprintf("❌Unsilence %s", silence.Silence.ID),
silenceManager.GetUnsilencePrefix(),
silence.Silence.ID,
)

rows = append(rows, menu.Row(button))
}

Check warning on line 99 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L87-L99

Added lines #L87 - L99 were not covered by tests

if len(chunk) > 0 {
buttons := []tele.Btn{}
if page >= 1 {
buttons = append(buttons, menu.Data(
fmt.Sprintf("⬅️Page %d", page),
silenceManager.GetPaginatedSilencesListPrefix(),
strconv.Itoa(page-1),
))

Check warning on line 108 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L101-L108

Added lines #L101 - L108 were not covered by tests
}

for index, chunk := range silencesGrouped {
template, renderErr := a.TemplateManager.Render("silences_list", render.RenderStruct{
Grafana: a.Grafana,
Alertmanager: a.Alertmanager,
Data: types.SilencesListStruct{
Silences: chunk,
ShowHeader: index == 0,
SilencesCount: len(silencesWithAlerts),
},
})

if renderErr != nil {
a.Logger.Error().Err(renderErr).Msg("Error rendering silences_list template")
return c.Reply(fmt.Sprintf("Error rendering template: %s", renderErr))
}

menu := &tele.ReplyMarkup{ResizeKeyboard: true}

rows := make([]tele.Row, constants.SilencesInOneMessage)

for silenceIndex, silence := range chunk {
button := menu.Data(
fmt.Sprintf("❌Unsilence %s", silence.Silence.ID),
silenceManager.GetUnsilencePrefix(),
silence.Silence.ID,
)

rows[silenceIndex] = menu.Row(button)
}

menu.Inline(rows...)

if sendErr := a.BotReply(c, template, menu); sendErr != nil {
a.Logger.Error().Err(sendErr).Msg("Error sending message")
}
if page < len(silencesGrouped)-1 {
buttons = append(buttons, menu.Data(
fmt.Sprintf("➡️Page %d", page+2),
silenceManager.GetPaginatedSilencesListPrefix(),
strconv.Itoa(page+1),
))
}

Check warning on line 117 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L111-L117

Added lines #L111 - L117 were not covered by tests

if len(buttons) > 0 {
rows = append(rows, menu.Row(buttons...))
}

Check warning on line 121 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L119-L121

Added lines #L119 - L121 were not covered by tests
}

menu.Inline(rows...)

if editPrevious {
if editErr := c.Edit(template, menu, tele.ModeHTML, tele.NoPreview); editErr != nil {
a.Logger.Error().Err(editErr).Msg("Error deleting previous message")
return editErr

Check warning on line 129 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L124-L129

Added lines #L124 - L129 were not covered by tests
}

return nil
}

if sendErr := a.BotReply(c, template, menu); sendErr != nil {
a.Logger.Error().Err(sendErr).Msg("Error sending message")
return sendErr
}

Check warning on line 138 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L135-L138

Added lines #L135 - L138 were not covered by tests

return nil

Check warning on line 140 in pkg/app/silences_list.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/silences_list.go#L140

Added line #L140 was not covered by tests
}
4 changes: 4 additions & 0 deletions pkg/clients/alertmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
return constants.AlertmanagerSilencePrefix
}

func (g *Alertmanager) GetPaginatedSilencesListPrefix() string {
return constants.AlertmanagerPaginatedSilencesList

Check warning on line 46 in pkg/clients/alertmanager.go

View check run for this annotation

Codecov / codecov/patch

pkg/clients/alertmanager.go#L45-L46

Added lines #L45 - L46 were not covered by tests
}

func (g *Alertmanager) GetMutesDurations() []string {
return g.Config.MutesDurations
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/clients/grafana.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
return constants.GrafanaSilencePrefix
}

func (g *Grafana) GetPaginatedSilencesListPrefix() string {
return constants.GrafanaPaginatedSilencesList

Check warning on line 47 in pkg/clients/grafana.go

View check run for this annotation

Codecov / codecov/patch

pkg/clients/grafana.go#L46-L47

Added lines #L46 - L47 were not covered by tests
}

func (g *Grafana) Name() string {
return "Grafana"
}
Expand Down
18 changes: 10 additions & 8 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ const (
SilenceMatcherEqual string = "="
SilenceMatcherNotEqual string = "!="

SilencesInOneMessage = 5
AlertsInOneMessage = 3
GrafanaUnsilencePrefix = "grafana_unsilence_"
AlertmanagerUnsilencePrefix = "alertmanager_unsilence_"
GrafanaSilencePrefix = "grafana_silence_"
AlertmanagerSilencePrefix = "alertmanager_silence_"
GrafanaPrepareSilencePrefix = "grafana_prepare_silence_"
AlertmanagerPrepareSilencePrefix = "alertmanager_prepare_silence_"
SilencesInOneMessage = 5
AlertsInOneMessage = 3
GrafanaPaginatedSilencesList = "grafana_paginated_silences_list"
AlertmanagerPaginatedSilencesList = "alertmanager_paginated_silences_list"
GrafanaUnsilencePrefix = "grafana_unsilence_"
AlertmanagerUnsilencePrefix = "alertmanager_unsilence_"
GrafanaSilencePrefix = "grafana_silence_"
AlertmanagerSilencePrefix = "alertmanager_silence_"
GrafanaPrepareSilencePrefix = "grafana_prepare_silence_"
AlertmanagerPrepareSilencePrefix = "alertmanager_prepare_silence_"
)
2 changes: 2 additions & 0 deletions pkg/types/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,7 @@ type FiringAlertsListStruct struct {
type SilencesListStruct struct {
Silences []SilenceWithAlerts
ShowHeader bool
Start int
End int
SilencesCount int
}
1 change: 1 addition & 0 deletions pkg/types/silence_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type SilenceManager interface {
CreateSilence(silence Silence) (SilenceCreateResponse, error)
GetSilenceMatchingAlerts(silence Silence) ([]AlertmanagerAlert, error)
DeleteSilence(silenceID string) error
GetPaginatedSilencesListPrefix() string
GetSilencePrefix() string
GetUnsilencePrefix() string
Name() string
Expand Down
4 changes: 4 additions & 0 deletions pkg/types/stub_silence_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@
return "stub_unsilence"
}

func (m *StubSilenceManager) GetPaginatedSilencesListPrefix() string {
return "stub_paginate_silences"

Check warning on line 88 in pkg/types/stub_silence_manager.go

View check run for this annotation

Codecov / codecov/patch

pkg/types/stub_silence_manager.go#L87-L88

Added lines #L87 - L88 were not covered by tests
}

func (m *StubSilenceManager) Name() string {
return "StubSilenceManager"
}
Expand Down
4 changes: 1 addition & 3 deletions templates/silences_list.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
{{- if .Data.ShowHeader }}
{{- if not .Data.Silences }}
<strong>Silences</strong>
No silences.
{{- else }}
<strong>Silences ({{ .Data.SilencesCount }}):</strong>
{{- end }}
<strong>Silences ({{.Data.Start}} - {{ .Data.End }} of {{ .Data.SilencesCount }}):</strong>
{{- end }}
{{ range $silenceId, $silenceInfo := .Data.Silences }}
<strong>ID:</strong> <code>{{ $silenceInfo.Silence.ID }}</code>
Expand Down
Loading