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

Make Update Summary and Description configurable per receiver #183

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
5 changes: 1 addition & 4 deletions cmd/jiralert/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ var (
logFormat = flag.String("log.format", logFormatLogfmt, "Log format to use ("+logFormatLogfmt+", "+logFormatJSON+")")
hashJiraLabel = flag.Bool("hash-jira-label", false, "if enabled: renames ALERT{...} to JIRALERT{...}; also hashes the key-value pairs inside of JIRALERT{...} in the created jira issue labels"+
"- this ensures that the label text does not overflow the allowed length in jira (255)")
updateSummary = flag.Bool("update-summary", true, "When false, jiralert does not update the summary of the existing jira issue, even when changes are spotted.")
updateDescription = flag.Bool("update-description", true, "When false, jiralert does not update the description of the existing jira issue, even when changes are spotted.")
reopenTickets = flag.Bool("reopen-tickets", true, "When false, jiralert does not reopen tickets.")
maxDescriptionLength = flag.Int("max-description-length", defaultMaxDescriptionLength, "Maximum length of Descriptions. Truncate to this size avoid server errors.")

// Version is the build version, set by make to latest git tag/hash via `-ldflags "-X main.Version=$(VERSION)"`.
Expand Down Expand Up @@ -126,7 +123,7 @@ func main() {
return
}

if retry, err := notify.NewReceiver(logger, conf, tmpl, client.Issue).Notify(&data, *hashJiraLabel, *updateSummary, *updateDescription, *reopenTickets, *maxDescriptionLength); err != nil {
if retry, err := notify.NewReceiver(logger, conf, tmpl, client.Issue).Notify(&data, *hashJiraLabel, *maxDescriptionLength); err != nil {
var status int
if retry {
// Instruct Alertmanager to retry.
Expand Down
3 changes: 3 additions & 0 deletions examples/jiralert.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ defaults:
other_projects: ["OTHER1", "OTHER2"]
# Include ticket update as comment. Optional (default: false).
update_in_comment: false
# Enable or disable automatic updates to the summary and description fields. Set to False to prevent updates. This setting can also be configured at the receiver level to override the global default.
update_summary: True
update_description: True

# Receiver definitions. At least one must be defined.
receivers:
Expand Down
15 changes: 15 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,15 @@ type ReceiverConfig struct {
// Flag to enable updates in comments.
UpdateInComment *bool `yaml:"update_in_comment" json:"update_in_comment"`

// Flag to enable updates in summary.
UpdateSummary *bool `yaml:"update_summary" json:"update_summary"`

// Flag to enable updates in description.
UpdateDescription *bool `yaml:"update_description" json:"update_description"`

// Flag to enable reopen tickets.
ReopenTickets *bool `yaml:"reopen_tickets" json:"reopen_tickets"`

// Flag to auto-resolve opened issue when the alert is resolved.
AutoResolve *AutoResolve `yaml:"auto_resolve" json:"auto_resolve"`

Expand Down Expand Up @@ -324,6 +333,12 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
if rc.UpdateInComment == nil {
rc.UpdateInComment = c.Defaults.UpdateInComment
}
if rc.UpdateSummary == nil {
rc.UpdateSummary = c.Defaults.UpdateSummary
}
if rc.UpdateDescription == nil {
rc.UpdateDescription = c.Defaults.UpdateDescription
}
}

if len(c.Receivers) == 0 {
Expand Down
19 changes: 19 additions & 0 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ defaults:
reopen_duration: 0h
update_in_comment: true
static_labels: ["defaultlabel"]
update_summary: true
update_description: true
reopen_tickets: true

# Receiver definitions. At least one must be defined.
receivers:
Expand All @@ -58,6 +61,9 @@ receivers:
# Copy all Prometheus labels into separate JIRA labels. Optional (default: false).
add_group_labels: false
update_in_comment: false
update_summary: false
update_description: true
reopen_tickets: false
static_labels: ["somelabel"]

- name: 'jira-xy'
Expand Down Expand Up @@ -132,6 +138,9 @@ type receiverTestConfig struct {
AddGroupLabels *bool `yaml:"add_group_labels,omitempty"`
UpdateInComment *bool `yaml:"update_in_comment,omitempty"`
StaticLabels []string `yaml:"static_labels" json:"static_labels"`
UpdateSummary *bool `yaml:"update_summary" json:"update_summary"`
UpdateDescription *bool `yaml:"update_description" json:"update_description"`
ReopenTickets *bool `yaml:"reopen_tickets" json:"reopen_tickets"`

AutoResolve *AutoResolve `yaml:"auto_resolve" json:"auto_resolve"`

Expand Down Expand Up @@ -320,6 +329,8 @@ func TestReceiverOverrides(t *testing.T) {
addGroupLabelsFalseVal := false
updateInCommentTrueVal := true
updateInCommentFalseVal := false
updateSummaryFalseVal := false
updateDescriptionFalseVal := false

// We'll override one key at a time and check the value in the receiver.
for _, test := range []struct {
Expand All @@ -340,6 +351,8 @@ func TestReceiverOverrides(t *testing.T) {
{"AddGroupLabels", &addGroupLabelsTrueVal, &addGroupLabelsTrueVal},
{"UpdateInComment", &updateInCommentFalseVal, &updateInCommentFalseVal},
{"UpdateInComment", &updateInCommentTrueVal, &updateInCommentTrueVal},
{"UpdateSummary", &updateSummaryFalseVal, &updateSummaryFalseVal},
{"UpdateDescription", &updateDescriptionFalseVal, &updateDescriptionFalseVal},
{"AutoResolve", &AutoResolve{State: "Done"}, &autoResolve},
{"StaticLabels", []string{"somelabel"}, []string{"somelabel"}},
} {
Expand Down Expand Up @@ -379,6 +392,8 @@ func newReceiverTestConfig(mandatory []string, optional []string) *receiverTestC
r := receiverTestConfig{}
addGroupLabelsDefaultVal := true
updateInCommentDefaultVal := true
updateSummaryDefaultVal := true
updateDescriptionDefaultVal := true

for _, name := range mandatory {
var value reflect.Value
Expand All @@ -399,6 +414,10 @@ func newReceiverTestConfig(mandatory []string, optional []string) *receiverTestC
value = reflect.ValueOf(&addGroupLabelsDefaultVal)
} else if name == "UpdateInComment" {
value = reflect.ValueOf(&updateInCommentDefaultVal)
} else if name == "UpdateSummary" {
value = reflect.ValueOf(&updateSummaryDefaultVal)
} else if name == "UpdateDescription" {
value = reflect.ValueOf(&updateDescriptionDefaultVal)
} else if name == "AutoResolve" {
value = reflect.ValueOf(&AutoResolve{State: "Done"})
} else if name == "StaticLabels" {
Expand Down
10 changes: 5 additions & 5 deletions pkg/notify/notify.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func NewReceiver(logger log.Logger, c *config.ReceiverConfig, t *template.Templa
}

// Notify manages JIRA issues based on alertmanager webhook notify message.
func (r *Receiver) Notify(data *alertmanager.Data, hashJiraLabel bool, updateSummary bool, updateDescription bool, reopenTickets bool, maxDescriptionLength int) (bool, error) {
func (r *Receiver) Notify(data *alertmanager.Data, hashJiraLabel bool, maxDescriptionLength int) (bool, error) {
project, err := r.tmpl.Execute(r.conf.Project, data)
if err != nil {
return false, errors.Wrap(err, "generate project from template")
Expand Down Expand Up @@ -94,7 +94,7 @@ func (r *Receiver) Notify(data *alertmanager.Data, hashJiraLabel bool, updateSum
if issue != nil {

// Update summary if needed.
if updateSummary {
if r.conf.UpdateSummary != nil && *r.conf.UpdateSummary {
if issue.Fields.Summary != issueSummary {
level.Debug(r.logger).Log("updateSummaryDisabled executing")
retry, err := r.updateSummary(issue.Key, issueSummary)
Expand Down Expand Up @@ -125,8 +125,8 @@ func (r *Receiver) Notify(data *alertmanager.Data, hashJiraLabel bool, updateSum
}
}

// update description if enabled. This has to be done after comment adding logic which needs to handle redundant commentary vs description case.
if updateDescription {
// update description after possibly adding a comment so that it's possible to detect redundant first comment
if r.conf.UpdateDescription != nil && *r.conf.UpdateDescription {
if issue.Fields.Description != issueDesc {
retry, err := r.updateDescription(issue.Key, issueDesc)
if err != nil {
Expand Down Expand Up @@ -155,7 +155,7 @@ func (r *Receiver) Notify(data *alertmanager.Data, hashJiraLabel bool, updateSum
return false, nil
}

if reopenTickets {
if r.conf.ReopenTickets != nil && *r.conf.ReopenTickets {
if r.conf.WontFixResolution != "" && issue.Fields.Resolution != nil &&
issue.Fields.Resolution.Name == r.conf.WontFixResolution {
level.Info(r.logger).Log("msg", "issue was resolved as won't fix, not reopening", "key", issue.Key, "label", issueGroupLabel, "resolution", issue.Fields.Resolution.Name)
Expand Down
24 changes: 23 additions & 1 deletion pkg/notify/notify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,30 +162,44 @@ func (f *fakeJira) DoTransition(ticketID, transitionID string) (*jira.Response,

func testReceiverConfig1() *config.ReceiverConfig {
reopen := config.Duration(1 * time.Hour)
updateSummary := true
updateDescription := true
reopenTickets := true
return &config.ReceiverConfig{
Project: "abc",
Summary: `[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .GroupLabels.SortedPairs.Values | join " " }} {{ if gt (len .CommonLabels) (len .GroupLabels) }}({{ with .CommonLabels.Remove .GroupLabels.Names }}{{ .Values | join " " }}{{ end }}){{ end }}`,
ReopenDuration: &reopen,
ReopenState: "reopened",
ReopenTickets: &reopenTickets,
UpdateSummary: &updateSummary,
UpdateDescription: &updateDescription,
WontFixResolution: "won't-fix",
}
}

func testReceiverConfig2() *config.ReceiverConfig {
reopen := config.Duration(1 * time.Hour)
updateSummary := true
updateDescription := true
reopenTickets := true
return &config.ReceiverConfig{
Project: "abc",
Summary: `[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .GroupLabels.SortedPairs.Values | join " " }} {{ if gt (len .CommonLabels) (len .GroupLabels) }}({{ with .CommonLabels.Remove .GroupLabels.Names }}{{ .Values | join " " }}{{ end }}){{ end }}`,
ReopenDuration: &reopen,
ReopenState: "reopened",
ReopenTickets: &reopenTickets,
Description: `{{ .Alerts.Firing | len }}`,
UpdateSummary: &updateSummary,
UpdateDescription: &updateDescription,
WontFixResolution: "won't-fix",
}
}

func testReceiverConfigAddComments() *config.ReceiverConfig {
reopen := config.Duration(1 * time.Hour)
updateInCommentValue := true
updateSummary := true
updateDescription := true
return &config.ReceiverConfig{
Project: "abc",
Summary: `[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .GroupLabels.SortedPairs.Values | join " " }} {{ if gt (len .CommonLabels) (len .GroupLabels) }}({{ with .CommonLabels.Remove .GroupLabels.Names }}{{ .Values | join " " }}{{ end }}){{ end }}`,
Expand All @@ -194,17 +208,25 @@ func testReceiverConfigAddComments() *config.ReceiverConfig {
Description: `{{ .Alerts.Firing | len }}`,
WontFixResolution: "won't-fix",
UpdateInComment: &updateInCommentValue,
UpdateSummary: &updateSummary,
UpdateDescription: &updateDescription,
}
}

func testReceiverConfigAutoResolve() *config.ReceiverConfig {
reopen := config.Duration(1 * time.Hour)
updateSummary := true
updateDescription := true
reopenTickets := true
autoResolve := config.AutoResolve{State: "Done"}
return &config.ReceiverConfig{
Project: "abc",
Summary: `[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .GroupLabels.SortedPairs.Values | join " " }} {{ if gt (len .CommonLabels) (len .GroupLabels) }}({{ with .CommonLabels.Remove .GroupLabels.Names }}{{ .Values | join " " }}{{ end }}){{ end }}`,
ReopenDuration: &reopen,
ReopenState: "reopened",
ReopenTickets: &reopenTickets,
UpdateSummary: &updateSummary,
UpdateDescription: &updateDescription,
WontFixResolution: "won't-fix",
AutoResolve: &autoResolve,
}
Expand Down Expand Up @@ -701,7 +723,7 @@ func TestNotify_JIRAInteraction(t *testing.T) {
return testNowTime
}

_, err := receiver.Notify(tcase.inputAlert, true, true, true, true, 32768)
_, err := receiver.Notify(tcase.inputAlert, true, 32768)
require.NoError(t, err)
require.Equal(t, tcase.expectedJiraIssues, fakeJira.issuesByKey)
}); !ok {
Expand Down
Loading