Skip to content

Commit c9b4966

Browse files
committed
jiralert: Improved docs and config.
Signed-off-by: Bartek Plotka <[email protected]>
1 parent 88fb628 commit c9b4966

File tree

7 files changed

+65
-107
lines changed

7 files changed

+65
-107
lines changed

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,19 @@ $ curl -H "Content-type: application/json" -X POST \
5252

5353
## Configuration
5454

55-
The configuration file is essentially a list of receivers matching 1-to-1 all Alertmanager receivers using JIRAlert; plus defaults (in the form of a partially defined receiver); and a pointer to the template file.
55+
The configuration file is essentially a list of JiraAlert receivers plus defaults (in the form of a partially defined receiver); and a pointer to the template file.
5656

57-
Each receiver must have a unique name (matching the Alertmanager receiver name), JIRA API access fields (URL, username and password), a handful of required issue fields (such as the JIRA project and issue summary), some optional issue fields (e.g. priority) and a `fields` map for other (standard or custom) JIRA fields. Most of these may use [Go templating](https://golang.org/pkg/text/template/) to generate the actual field values based on the contents of the Alertmanager notification. The exact same data structures and functions as those defined in the [Alertmanager template reference](https://prometheus.io/docs/alerting/notifications/) are available in JIRAlert.
57+
You can find more docs in [the configuration itself](/pkg/config/config.go)
58+
59+
Each receiver must have:
60+
* a unique name (matching the Alertmanager receiver name)
61+
* JIRA API access fields (URL, username and password),
62+
* handful of required issue fields (such as the JIRA project and issue summary),
63+
* some optional issue fields (e.g. priority) and a `fields` map for other (standard or custom) JIRA fields.
64+
65+
Most of these may use [Go templating](https://golang.org/pkg/text/template/) to generate the actual field values based on the contents of the Alertmanager notification.
66+
67+
The exact same data structures and functions as those defined in the [Alertmanager template reference](https://prometheus.io/docs/alerting/notifications/) are available in JIRAlert.
5868

5969
## Alertmanager configuration
6070

cmd/jiralert/content.go

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,6 @@ const (
5353
<h2>Configuration</h2>
5454
<pre>{{ .Config }}</pre>
5555
{{- end }}
56-
57-
{{ define "content.error" -}}
58-
<h2>Error</h2>
59-
<pre>{{ .Err }}</pre>
60-
{{- end }}
6156
`
6257
)
6358

@@ -66,16 +61,12 @@ type tdata struct {
6661

6762
// `/config` only
6863
Config string
69-
70-
// `/error` only
71-
Err error
7264
}
7365

7466
var (
7567
allTemplates = template.Must(template.New("").Parse(templates))
7668
homeTemplate = pageTemplate("home")
7769
configTemplate = pageTemplate("config")
78-
// errorTemplate = pageTemplate("error")
7970
)
8071

8172
func pageTemplate(name string) *template.Template {
@@ -86,7 +77,7 @@ func pageTemplate(name string) *template.Template {
8677
// HomeHandlerFunc is the HTTP handler for the home page (`/`).
8778
func HomeHandlerFunc() func(http.ResponseWriter, *http.Request) {
8879
return func(w http.ResponseWriter, r *http.Request) {
89-
homeTemplate.Execute(w, &tdata{
80+
_ = homeTemplate.Execute(w, &tdata{
9081
DocsUrl: docsUrl,
9182
})
9283
}
@@ -95,19 +86,9 @@ func HomeHandlerFunc() func(http.ResponseWriter, *http.Request) {
9586
// ConfigHandlerFunc is the HTTP handler for the `/config` page. It outputs the configuration marshaled in YAML format.
9687
func ConfigHandlerFunc(config *config.Config) func(http.ResponseWriter, *http.Request) {
9788
return func(w http.ResponseWriter, r *http.Request) {
98-
configTemplate.Execute(w, &tdata{
89+
_ = configTemplate.Execute(w, &tdata{
9990
DocsUrl: docsUrl,
10091
Config: config.String(),
10192
})
10293
}
10394
}
104-
105-
// HandleError is an error handler that other handlers defer to in case of error. It is important to not have written
106-
// anything to w before calling HandleError(), or the 500 status code won't be set (and the content might be mixed up).
107-
//func HandleError(err error, metricsPath string, w http.ResponseWriter, r *http.Request) {
108-
// w.WriteHeader(http.StatusInternalServerError)
109-
// errorTemplate.Execute(w, &tdata{
110-
// DocsUrl: docsUrl,
111-
// Err: err,
112-
// })
113-
//}

cmd/jiralert/main.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,21 @@ func main() {
4848
var logger = setupLogger(*logLevel, *logFormat)
4949
level.Info(logger).Log("msg", "starting JIRAlert", "version", Version)
5050

51-
config, _, err := config.LoadFile(*configFile, logger)
51+
cfg, _, err := config.LoadFile(*configFile, logger)
5252
if err != nil {
5353
level.Error(logger).Log("msg", "error loading configuration", "path", *configFile, "err", err)
5454
os.Exit(1)
5555
}
5656

57-
tmpl, err := template.LoadTemplate(config.Template, logger)
57+
tmpl, err := template.LoadTemplate(cfg.Template, logger)
5858
if err != nil {
59-
level.Error(logger).Log("msg", "error loading templates", "path", config.Template, "err", err)
59+
level.Error(logger).Log("msg", "error loading templates", "path", cfg.Template, "err", err)
6060
os.Exit(1)
6161
}
6262

6363
http.HandleFunc("/alert", func(w http.ResponseWriter, req *http.Request) {
6464
level.Debug(logger).Log("msg", "handling /alert webhook request")
65-
defer req.Body.Close()
65+
defer func() { _ = req.Body.Close() }()
6666

6767
// https://godoc.org/github.com/prometheus/alertmanager/template#Data
6868
data := alertmanager.Data{}
@@ -71,7 +71,7 @@ func main() {
7171
return
7272
}
7373

74-
conf := config.ReceiverByName(data.Receiver)
74+
conf := cfg.ReceiverByName(data.Receiver)
7575
if conf == nil {
7676
errorHandler(w, http.StatusNotFound, fmt.Errorf("receiver missing: %s", data.Receiver), unknownReceiver, &data, logger)
7777
return
@@ -107,7 +107,7 @@ func main() {
107107
})
108108

109109
http.HandleFunc("/", HomeHandlerFunc())
110-
http.HandleFunc("/config", ConfigHandlerFunc(config))
110+
http.HandleFunc("/cfg", ConfigHandlerFunc(cfg))
111111
http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { http.Error(w, "OK", http.StatusOK) })
112112
http.Handle("/metrics", promhttp.Handler())
113113

examples/jiralert.tmpl

Lines changed: 0 additions & 10 deletions
This file was deleted.

examples/jiralert.yml

Lines changed: 0 additions & 51 deletions
This file was deleted.

pkg/config/config.go

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,31 +74,52 @@ func resolveFilepaths(baseDir string, cfg *Config, logger log.Logger) {
7474
cfg.Template = join(cfg.Template)
7575
}
7676

77-
// ReceiverConfig is the configuration for one receiver. It has a unique name and includes API access fields (URL, user
78-
// and password) and issue fields (required -- e.g. project, issue type -- and optional -- e.g. priority).
77+
// ReceiverConfig is the configuration for one receiver.
7978
type ReceiverConfig struct {
79+
// Name represents unique name for a receiver.
80+
// If Iiralert is used with Alertmanager, name it as Alertmanager receiver that sends alert via webhook to Jiralert for
81+
// desired propagation.
8082
Name string `yaml:"name" json:"name"`
8183

82-
// API access fields
84+
// APIURL specifies API URL for JIRA e.g https://<your org>.atlassian.net.
85+
// Required.
8386
APIURL string `yaml:"api_url" json:"api_url"`
87+
// User specifies user to pass in basicauth against JIRA.
8488
User string `yaml:"user" json:"user"`
89+
// Password specifies password in baiscauth against JIRA.
8590
Password Secret `yaml:"password" json:"password"`
8691

87-
// Required issue fields
92+
// Required issue fields.
93+
94+
// Projects specifies in what project within org to create/reopen JIRA issues.
8895
Project string `yaml:"project" json:"project"`
96+
// IssueType specifies what type of the issue to use for new JIRA issues.
8997
IssueType string `yaml:"issue_type" json:"issue_type"`
98+
// Summary specifies Golang template invocation for generating the issue summary.
9099
Summary string `yaml:"summary" json:"summary"`
100+
// ReopenState specifies the state to transition into when reopening a closed issue.
101+
// This state has to exists for the chosen project.
91102
ReopenState string `yaml:"reopen_state" json:"reopen_state"`
103+
// ReopenDuration specifies the time after being closed that an issue should be reopened, after which,
104+
// a new issue is created instead. Set to large value if you always want to reopen.
105+
ReopenDuration *Duration `yaml:"reopen_duration" json:"reopen_duration"`
106+
107+
// Optional issue fields.
92108

93-
// Optional issue fields
109+
// Priority represents issue priority.
94110
Priority string `yaml:"priority" json:"priority"`
111+
// Description specifies Golang template invocation for generating the issue description.
95112
Description string `yaml:"description" json:"description"`
113+
// WontFixResolution specifies to not reopen issues with this resolution. Useful for silencing alerts.
96114
WontFixResolution string `yaml:"wont_fix_resolution" json:"wont_fix_resolution"`
115+
// Fields specifies standard or custom field values to set on created issue.
116+
//
117+
// See https://developer.atlassian.com/server/jira/platform/jira-rest-api-examples/#setting-custom-field-data-for-other-field-types for further examples.
97118
Fields map[string]interface{} `yaml:"fields" json:"fields"`
119+
// Components specifies issue components. Sometimes required, depending on JIRA project.
98120
Components []string `yaml:"components" json:"components"`
99-
ReopenDuration *Duration `yaml:"reopen_duration" json:"reopen_duration"`
100-
101-
// Label copy settings
121+
// AddGroupLabels specifies if all Prometheus labels should be copied into separate JIRA labels.
122+
// Default: false.
102123
AddGroupLabels bool `yaml:"add_group_labels" json:"add_group_labels"`
103124

104125
// Catches all undefined fields and must be empty after parsing.
@@ -123,8 +144,13 @@ func (rc *ReceiverConfig) UnmarshalYAML(unmarshal func(interface{}) error) error
123144

124145
// Config is the top-level configuration for JIRAlert's config file.
125146
type Config struct {
147+
// Default specifies default values to be used in place of any ReceiverConfig' empty field.
126148
Defaults *ReceiverConfig `yaml:"defaults,omitempty" json:"defaults,omitempty"`
149+
150+
// Receivers contains configuration per each receiver.
127151
Receivers []*ReceiverConfig `yaml:"receivers,omitempty" json:"receivers,omitempty"`
152+
153+
// Template specifies an optional file with template definitions.
128154
Template string `yaml:"template" json:"template"`
129155

130156
// Catches all undefined fields and must be empty after parsing.
@@ -232,10 +258,6 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
232258
return fmt.Errorf("no receivers defined")
233259
}
234260

235-
if c.Template == "" {
236-
return fmt.Errorf("missing template file")
237-
}
238-
239261
return checkOverflow(c.XXX, "config")
240262
}
241263

pkg/template/template.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,19 @@ var funcs = template.FuncMap{
3232
}
3333

3434
// LoadTemplate reads and parses all templates defined in the given file and constructs a jiralert.Template.
35+
// If file is empty, or no file is passed, empty file template is returned.
3536
func LoadTemplate(path string, logger log.Logger) (*Template, error) {
36-
level.Debug(logger).Log("msg", "loading templates", "path", path)
37-
tmpl, err := template.New("").Option("missingkey=zero").Funcs(funcs).ParseFiles(path)
38-
if err != nil {
39-
return nil, err
37+
if len(path) > 0 {
38+
level.Debug(logger).Log("msg", "loading templates", "path", path)
39+
tmpl, err := template.New("").Option("missingkey=zero").Funcs(funcs).ParseFiles(path)
40+
if err != nil {
41+
return nil, err
42+
}
43+
return &Template{tmpl: tmpl}, nil
4044
}
41-
return &Template{tmpl: tmpl}, nil
45+
46+
level.Info(logger).Log("msg", "no template was passed.")
47+
return &Template{tmpl: template.New("")}, nil
4248
}
4349

4450
func (t *Template) Err() error {

0 commit comments

Comments
 (0)