Support customization of template options in TemplateExpander (#9290)

Signed-off-by: George Robinson <george.robinson@grafana.com>
This commit is contained in:
George Robinson 2021-09-13 12:49:08 +01:00 committed by GitHub
parent 46286cb6ab
commit 049b4f4f13
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 56 additions and 4 deletions

View file

@ -239,6 +239,7 @@ func testTemplateParsing(rl *RuleNode) (errs []error) {
model.Time(timestamp.FromTime(time.Now())),
nil,
nil,
nil,
)
return tmpl.ParseTest()
}

View file

@ -338,6 +338,7 @@ func (r *AlertingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc,
model.Time(timestamp.FromTime(ts)),
template.QueryFunc(query),
externalURL,
nil,
)
result, err := tmpl.Expand()
if err != nil {

View file

@ -115,6 +115,7 @@ type Expander struct {
name string
data interface{}
funcMap text_template.FuncMap
options []string
}
// NewTemplateExpander returns a template expander ready to use.
@ -126,7 +127,11 @@ func NewTemplateExpander(
timestamp model.Time,
queryFunc QueryFunc,
externalURL *url.URL,
options []string,
) *Expander {
if options == nil {
options = []string{"missingkey=zero"}
}
return &Expander{
text: text,
name: name,
@ -291,6 +296,7 @@ func NewTemplateExpander(
return externalURL.String()
},
},
options: options,
}
}
@ -336,7 +342,9 @@ func (te Expander) Expand() (result string, resultErr error) {
templateTextExpansionTotal.Inc()
tmpl, err := text_template.New(te.name).Funcs(te.funcMap).Option("missingkey=zero").Parse(te.text)
tmpl := text_template.New(te.name).Funcs(te.funcMap)
tmpl.Option(te.options...)
tmpl, err := tmpl.Parse(te.text)
if err != nil {
return "", errors.Wrapf(err, "error parsing template %v", te.name)
}
@ -361,7 +369,7 @@ func (te Expander) ExpandHTML(templateFiles []string) (result string, resultErr
}()
tmpl := html_template.New(te.name).Funcs(html_template.FuncMap(te.funcMap))
tmpl.Option("missingkey=zero")
tmpl.Option(te.options...)
tmpl.Funcs(html_template.FuncMap{
"tmpl": func(name string, data interface{}) (html_template.HTML, error) {
var buffer bytes.Buffer

View file

@ -31,6 +31,7 @@ func TestTemplateExpansion(t *testing.T) {
text string
output string
input interface{}
options []string
queryResult promql.Vector
shouldFail bool
html bool
@ -153,6 +154,45 @@ func TestTemplateExpansion(t *testing.T) {
}},
output: "a:11: b:21: ",
},
{
// Missing value is no value for nil options.
text: "{{ .Foo }}",
output: "<no value>",
},
{
// Missing value is no value for no options.
text: "{{ .Foo }}",
options: make([]string, 0),
output: "<no value>",
},
{
// Assert that missing value returns error with missingkey=error.
text: "{{ .Foo }}",
options: []string{"missingkey=error"},
shouldFail: true,
errorMsg: `error executing template test: template: test:1:3: executing "test" at <.Foo>: nil data; no entry for key "Foo"`,
},
{
// Missing value is "" for nil options in ExpandHTML.
text: "{{ .Foo }}",
output: "",
html: true,
},
{
// Missing value is "" for no options in ExpandHTML.
text: "{{ .Foo }}",
options: make([]string, 0),
output: "",
html: true,
},
{
// Assert that missing value returns error with missingkey=error in ExpandHTML.
text: "{{ .Foo }}",
options: []string{"missingkey=error"},
shouldFail: true,
errorMsg: `error executing template test: template: test:1:3: executing "test" at <.Foo>: nil data; no entry for key "Foo"`,
html: true,
},
{
// Unparsable template.
text: "{{",
@ -341,7 +381,7 @@ func TestTemplateExpansion(t *testing.T) {
}
var result string
var err error
expander := NewTemplateExpander(context.Background(), s.text, "test", s.input, 0, queryFunc, extURL)
expander := NewTemplateExpander(context.Background(), s.text, "test", s.input, 0, queryFunc, extURL, s.options)
if s.html {
result, err = expander.ExpandHTML(nil)
} else {
@ -356,7 +396,7 @@ func TestTemplateExpansion(t *testing.T) {
require.NoError(t, err)
if err == nil {
require.Equal(t, result, s.output)
require.Equal(t, s.output, result)
}
}
}

View file

@ -709,6 +709,7 @@ func (h *Handler) consoles(w http.ResponseWriter, r *http.Request) {
h.now(),
template.QueryFunc(rules.EngineQueryFunc(h.queryEngine, h.storage)),
h.options.ExternalURL,
nil,
)
filenames, err := filepath.Glob(h.options.ConsoleLibrariesPath + "/*.lib")
if err != nil {
@ -1113,6 +1114,7 @@ func (h *Handler) executeTemplate(w http.ResponseWriter, name string, data inter
h.now(),
template.QueryFunc(rules.EngineQueryFunc(h.queryEngine, h.storage)),
h.options.ExternalURL,
nil,
)
tmpl.Funcs(tmplFuncs(h.consolesPath(), h.options))