mirror of
https://github.com/prometheus/alertmanager
synced 2025-01-13 09:34:38 +00:00
cli: add new template render command (#2538)
* cli: add new template render command Add a new template rendering command that allows users to test out their templates. This is especially needed because small bugs in templates do not surface until alertmanager actually tries to render them. * cli: permit passing alert data via a file Add a new parameter `--templatefile` for `amtool` so that it would be possible to pass custom alert data. Use an example `template.Data` if none has been passed to permit simple use-cases. Signed-off-by: Giedrius Statkevičius <giedrius.statkevicius@vinted.com>
This commit is contained in:
parent
20a1f8fd3f
commit
3962da4073
11
README.md
11
README.md
@ -294,6 +294,17 @@ Expire all silences:
|
||||
$ amtool silence expire $(amtool silence query -q)
|
||||
```
|
||||
|
||||
Try out how a template works. Let's say you have this in your configuration file:
|
||||
```
|
||||
templates:
|
||||
- '/foo/bar/*.tmpl'
|
||||
```
|
||||
|
||||
Then you can test out how a template would look like with example by using this command:
|
||||
```
|
||||
amtool template render --template.glob='/foo/bar/*.tmpl' --template.text='{{ template "slack.default.markdown.v1" . }}'
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
`amtool` allows a configuration file to specify some options for convenience. The default configuration file paths are `$HOME/.config/amtool/config.yml` or `/etc/amtool/config.yml`
|
||||
|
@ -113,6 +113,7 @@ func Execute() {
|
||||
configureCheckConfigCmd(app)
|
||||
configureClusterCmd(app)
|
||||
configureConfigCmd(app)
|
||||
configureTemplateCmd(app)
|
||||
|
||||
err = resolver.Bind(app, os.Args[1:])
|
||||
if err != nil {
|
||||
|
24
cli/template.go
Normal file
24
cli/template.go
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2021 Prometheus Team
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
// configureTemplateCmd represents the template command.
|
||||
func configureTemplateCmd(app *kingpin.Application) {
|
||||
templateCmd := app.Command("template", "Render template files.")
|
||||
configureTemplateRenderCmd(templateCmd)
|
||||
}
|
139
cli/template_render.go
Normal file
139
cli/template_render.go
Normal file
@ -0,0 +1,139 @@
|
||||
// Copyright 2021 Prometheus Team
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/alertmanager/template"
|
||||
kingpin "gopkg.in/alecthomas/kingpin.v2"
|
||||
)
|
||||
|
||||
var defaultData = template.Data{
|
||||
Receiver: "receiver",
|
||||
Status: "alertstatus",
|
||||
Alerts: template.Alerts{
|
||||
template.Alert{
|
||||
Status: "alertstatus",
|
||||
Labels: template.KV{
|
||||
"label1": "value1",
|
||||
"label2": "value2",
|
||||
"instance": "foo.bar:1234",
|
||||
"commonlabelkey1": "commonlabelvalue1",
|
||||
"commonlabelkey2": "commonlabelvalue2",
|
||||
},
|
||||
Annotations: template.KV{
|
||||
"annotation1": "value1",
|
||||
"annotation2": "value2",
|
||||
"commonannotationkey1": "commonannotationvalue1",
|
||||
"commonannotationkey2": "commonannotationvalue2",
|
||||
},
|
||||
StartsAt: time.Now().Add(-5 * time.Minute),
|
||||
EndsAt: time.Now(),
|
||||
GeneratorURL: "https://generatorurl.com",
|
||||
Fingerprint: "fingerprint1",
|
||||
},
|
||||
template.Alert{
|
||||
Status: "alertstatus",
|
||||
Labels: template.KV{
|
||||
"foo": "bar",
|
||||
"baz": "qux",
|
||||
"commonlabelkey1": "commonlabelvalue1",
|
||||
"commonlabelkey2": "commonlabelvalue2",
|
||||
},
|
||||
Annotations: template.KV{
|
||||
"aaa": "bbb",
|
||||
"ccc": "ddd",
|
||||
"commonannotationkey1": "commonannotationvalue1",
|
||||
"commonannotationkey2": "commonannotationvalue2",
|
||||
},
|
||||
StartsAt: time.Now().Add(-10 * time.Minute),
|
||||
EndsAt: time.Now(),
|
||||
GeneratorURL: "https://generatorurl.com",
|
||||
Fingerprint: "fingerprint2",
|
||||
},
|
||||
},
|
||||
GroupLabels: template.KV{
|
||||
"grouplabelkey1": "grouplabelvalue1",
|
||||
"grouplabelkey2": "grouplabelvalue2",
|
||||
},
|
||||
CommonLabels: template.KV{
|
||||
"commonlabelkey1": "commonlabelvalue1",
|
||||
"commonlabelkey2": "commonlabelvalue2",
|
||||
},
|
||||
CommonAnnotations: template.KV{
|
||||
"commonannotationkey1": "commonannotationvalue1",
|
||||
"commonannotationkey2": "commonannotationvalue2",
|
||||
},
|
||||
ExternalURL: "https://example.com",
|
||||
}
|
||||
|
||||
type templateRenderCmd struct {
|
||||
templateFilesGlobs []string
|
||||
templateType string
|
||||
templateText string
|
||||
templateData *os.File
|
||||
}
|
||||
|
||||
func configureTemplateRenderCmd(cc *kingpin.CmdClause) {
|
||||
var (
|
||||
c = &templateRenderCmd{}
|
||||
renderCmd = cc.Command("render", "Render a given definition in a template file to standard output.")
|
||||
)
|
||||
|
||||
renderCmd.Flag("template.glob", "Glob of paths that will be expanded and used for rendering.").Required().StringsVar(&c.templateFilesGlobs)
|
||||
renderCmd.Flag("template.text", "The template that will be rendered.").Required().StringVar(&c.templateText)
|
||||
renderCmd.Flag("template.type", "The type of the template. Can be either text (default) or html.").EnumVar(&c.templateType, "html", "text")
|
||||
renderCmd.Flag("template.data", "Full path to a file which contains the data of the alert(-s) with which the --template.text will be rendered. Must be in JSON. File must be formatted according to the following layout: https://pkg.go.dev/github.com/prometheus/alertmanager/template#Data. If none has been specified then a predefined, simple alert will be used for rendering.").FileVar(&c.templateData)
|
||||
|
||||
renderCmd.Action(execWithTimeout(c.render))
|
||||
}
|
||||
|
||||
func (c *templateRenderCmd) render(ctx context.Context, _ *kingpin.ParseContext) error {
|
||||
tmpl, err := template.FromGlobs(c.templateFilesGlobs...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f := tmpl.ExecuteTextString
|
||||
if c.templateType == "html" {
|
||||
f = tmpl.ExecuteHTMLString
|
||||
}
|
||||
|
||||
var data template.Data
|
||||
if c.templateData == nil {
|
||||
data = defaultData
|
||||
} else {
|
||||
content, err := ioutil.ReadAll(c.templateData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(content, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
rendered, err := f(c.templateText, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Print(rendered)
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user