Skip to content

Commit ab7b098

Browse files
committed
feat(conf): add optional field_labels to override Labels
Signed-off-by: Ricardo Melo <ricardo@cropa.ca>
1 parent d43cbab commit ab7b098

File tree

3 files changed

+84
-11
lines changed

3 files changed

+84
-11
lines changed

examples/jiralert.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ receivers:
4040
- name: 'jira-ab'
4141
# JIRA project to create the issue in. Required.
4242
project: AB
43+
# Define the jira field used by jiralert to avoid ticket duplication. Optional (default: Labels)
44+
field_labels: Labels
4345
# Copy all Prometheus labels into separate JIRA labels. Optional (default: false).
4446
add_group_labels: false
4547
# Include ticket update as comment too. Optional (default: false).

pkg/config/config.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"strings"
2424
"time"
2525

26+
"github.com/andygrunwald/go-jira"
2627
"github.com/go-kit/log"
2728
"github.com/go-kit/log/level"
2829

@@ -143,6 +144,8 @@ type ReceiverConfig struct {
143144
Priority string `yaml:"priority" json:"priority"`
144145
Description string `yaml:"description" json:"description"`
145146
WontFixResolution string `yaml:"wont_fix_resolution" json:"wont_fix_resolution"`
147+
FieldLabels string `yaml:"field_labels" json:"field_labels"`
148+
FieldLabelsKey string `yaml:"field_labels_key" json:"field_labels_key"`
146149
Fields map[string]interface{} `yaml:"fields" json:"fields"`
147150
Components []string `yaml:"components" json:"components"`
148151
StaticLabels []string `yaml:"static_labels" json:"static_labels"`
@@ -194,6 +197,30 @@ func (c Config) String() string {
194197
return string(b)
195198
}
196199

200+
// GetJiraFieldKey returns the jira key associated to a field.
201+
func GetJiraFieldKey(client *jira.Client, project string, issueType string, field string) (string, error) {
202+
options := &jira.GetQueryOptions{
203+
ProjectKeys: project,
204+
Expand: "projects.issuetypes.fields",
205+
}
206+
meta, _, err := client.Issue.GetCreateMetaWithOptions(options)
207+
if err != nil {
208+
return "", err
209+
}
210+
it := meta.Projects[0].GetIssueTypeWithName(issueType)
211+
if it == nil {
212+
return "", fmt.Errorf("jira: Issue type %s not found", issueType)
213+
}
214+
fields, err := it.GetAllFields()
215+
if err != nil {
216+
return "", err
217+
}
218+
if val, ok := fields[field]; ok {
219+
return val, nil
220+
}
221+
return "", fmt.Errorf("jira: Field %s not found in %s issue type", field, issueType)
222+
}
223+
197224
// UnmarshalYAML implements the yaml.Unmarshaler interface.
198225
func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
199226
// We want to set c to the defaults and then overwrite it with the input.
@@ -297,6 +324,41 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
297324
if rc.WontFixResolution == "" && c.Defaults.WontFixResolution != "" {
298325
rc.WontFixResolution = c.Defaults.WontFixResolution
299326
}
327+
if rc.FieldLabels == "" {
328+
if c.Defaults.FieldLabels != "" {
329+
rc.FieldLabels = c.Defaults.FieldLabels
330+
} else {
331+
rc.FieldLabels = "Labels"
332+
}
333+
}
334+
335+
// descover jira labels key.
336+
var client *jira.Client
337+
var err error
338+
if rc.User != "" && rc.Password != "" {
339+
tp := jira.BasicAuthTransport{
340+
Username: rc.User,
341+
Password: string(rc.Password),
342+
}
343+
client, err = jira.NewClient(tp.Client(), rc.APIURL)
344+
} else if rc.PersonalAccessToken != "" {
345+
tp := jira.PATAuthTransport{
346+
Token: string(rc.PersonalAccessToken),
347+
}
348+
client, err = jira.NewClient(tp.Client(), rc.APIURL)
349+
}
350+
351+
if err != nil {
352+
return err
353+
}
354+
355+
rc.FieldLabelsKey, err = GetJiraFieldKey(client, rc.Project, rc.IssueType, rc.FieldLabels)
356+
if err != nil {
357+
return err
358+
}
359+
fmt.Printf("\n\nrc.FieldLabelsKey=%s\n", rc.FieldLabels)
360+
fmt.Printf("rc.FieldLabelsKey=%s\n", rc.FieldLabelsKey)
361+
300362
if rc.AutoResolve != nil {
301363
if rc.AutoResolve.State == "" {
302364
return fmt.Errorf("bad config in receiver %q, 'auto_resolve' was defined with empty 'state' field", rc.Name)

pkg/notify/notify.go

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -137,32 +137,32 @@ func (r *Receiver) Notify(data *alertmanager.Data, hashJiraLabel bool, updateSum
137137

138138
if len(data.Alerts.Firing()) == 0 {
139139
if r.conf.AutoResolve != nil {
140-
level.Debug(r.logger).Log("msg", "no firing alert; resolving issue", "key", issue.Key, "label", issueGroupLabel)
140+
level.Debug(r.logger).Log("msg", "no firing alert; resolving issue", "key", issue.Key, r.conf.FieldLabels, issueGroupLabel)
141141
retry, err := r.resolveIssue(issue.Key)
142142
if err != nil {
143143
return retry, err
144144
}
145145
return false, nil
146146
}
147147

148-
level.Debug(r.logger).Log("msg", "no firing alert; summary checked, nothing else to do.", "key", issue.Key, "label", issueGroupLabel)
148+
level.Debug(r.logger).Log("msg", "no firing alert; summary checked, nothing else to do.", "key", issue.Key, r.conf.FieldLabels, issueGroupLabel)
149149
return false, nil
150150
}
151151

152152
// The set of JIRA status categories is fixed, this is a safe check to make.
153153
if issue.Fields.Status.StatusCategory.Key != "done" {
154-
level.Debug(r.logger).Log("msg", "issue is unresolved, all is done", "key", issue.Key, "label", issueGroupLabel)
154+
level.Debug(r.logger).Log("msg", "issue is unresolved, all is done", "key", issue.Key, r.conf.FieldLabels, issueGroupLabel)
155155
return false, nil
156156
}
157157

158158
if reopenTickets {
159159
if r.conf.WontFixResolution != "" && issue.Fields.Resolution != nil &&
160160
issue.Fields.Resolution.Name == r.conf.WontFixResolution {
161-
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)
161+
level.Info(r.logger).Log("msg", "issue was resolved as won't fix, not reopening", "key", issue.Key, r.conf.FieldLabels, issueGroupLabel, "resolution", issue.Fields.Resolution.Name)
162162
return false, nil
163163
}
164164

165-
level.Info(r.logger).Log("msg", "issue was recently resolved, reopening", "key", issue.Key, "label", issueGroupLabel)
165+
level.Info(r.logger).Log("msg", "issue was recently resolved, reopening", "key", issue.Key, r.conf.FieldLabels, issueGroupLabel)
166166
return r.reopen(issue.Key)
167167
}
168168

@@ -171,11 +171,11 @@ func (r *Receiver) Notify(data *alertmanager.Data, hashJiraLabel bool, updateSum
171171
}
172172

173173
if len(data.Alerts.Firing()) == 0 {
174-
level.Debug(r.logger).Log("msg", "no firing alert; nothing to do.", "label", issueGroupLabel)
174+
level.Debug(r.logger).Log("msg", "no firing alert; nothing to do.", r.conf.FieldLabels, issueGroupLabel)
175175
return false, nil
176176
}
177177

178-
level.Info(r.logger).Log("msg", "no recent matching issue found, creating new issue", "label", issueGroupLabel)
178+
level.Info(r.logger).Log("msg", "no recent matching issue found, creating new issue", r.conf.FieldLabels, issueGroupLabel)
179179

180180
issueType, err := r.tmpl.Execute(r.conf.IssueType, data)
181181
if err != nil {
@@ -190,10 +190,14 @@ func (r *Receiver) Notify(data *alertmanager.Data, hashJiraLabel bool, updateSum
190190
Type: jira.IssueType{Name: issueType},
191191
Description: issueDesc,
192192
Summary: issueSummary,
193-
Labels: append(staticLabels, issueGroupLabel),
194193
Unknowns: tcontainer.NewMarshalMap(),
195194
},
196195
}
196+
if r.conf.FieldLabels == "Labels" {
197+
issue.Fields.Labels = append(staticLabels, issueGroupLabel)
198+
} else {
199+
issue.Fields.Unknowns[r.conf.FieldLabelsKey] = append(staticLabels, issueGroupLabel)
200+
}
197201
if r.conf.Priority != "" {
198202
issuePrio, err := r.tmpl.Execute(r.conf.Priority, data)
199203
if err != nil {
@@ -312,9 +316,15 @@ func toGroupTicketLabel(groupLabels alertmanager.KV, hashJiraLabel bool) string
312316
}
313317

314318
func (r *Receiver) search(projects []string, issueLabel string) (*jira.Issue, bool, error) {
319+
var labelKey string
315320
// Search multiple projects in case issue was moved and further alert firings are desired in existing JIRA.
316321
projectList := "'" + strings.Join(projects, "', '") + "'"
317-
query := fmt.Sprintf("project in(%s) and labels=%q order by resolutiondate desc", projectList, issueLabel)
322+
if r.conf.FieldLabels == "Labels" {
323+
labelKey = "labels"
324+
} else {
325+
labelKey = fmt.Sprintf("cf[%s]", strings.Split(r.conf.FieldLabelsKey, "_")[1])
326+
}
327+
query := fmt.Sprintf("project in(%s) and %s=%q order by resolutiondate desc", projectList, labelKey, issueLabel)
318328
options := &jira.SearchOptions{
319329
Fields: []string{"summary", "status", "resolution", "resolutiondate", "description", "comment"},
320330
MaxResults: 2,
@@ -361,7 +371,7 @@ func (r *Receiver) findIssueToReuse(project string, issueGroupLabel string) (*ji
361371

362372
resolutionTime := time.Time(issue.Fields.Resolutiondate)
363373
if resolutionTime != (time.Time{}) && resolutionTime.Add(time.Duration(*r.conf.ReopenDuration)).Before(r.timeNow()) && *r.conf.ReopenDuration != 0 {
364-
level.Debug(r.logger).Log("msg", "existing resolved issue is too old to reopen, skipping", "key", issue.Key, "label", issueGroupLabel, "resolution_time", resolutionTime.Format(time.RFC3339), "reopen_duration", *r.conf.ReopenDuration)
374+
level.Debug(r.logger).Log("msg", "existing resolved issue is too old to reopen, skipping", "key", issue.Key, r.conf.FieldLabels, issueGroupLabel, "resolution_time", resolutionTime.Format(time.RFC3339), "reopen_duration", *r.conf.ReopenDuration)
365375
return nil, false, nil
366376
}
367377

@@ -423,7 +433,6 @@ func (r *Receiver) reopen(issueKey string) (bool, error) {
423433
}
424434

425435
func (r *Receiver) create(issue *jira.Issue) (bool, error) {
426-
level.Debug(r.logger).Log("msg", "create", "issue", fmt.Sprintf("%+v", *issue.Fields))
427436
newIssue, resp, err := r.client.Create(issue)
428437
if err != nil {
429438
return handleJiraErrResponse("Issue.Create", resp, err, r.logger)

0 commit comments

Comments
 (0)