diff --git a/influx/templates.go b/influx/templates.go index eeb980ff18..fe6a24a404 100644 --- a/influx/templates.go +++ b/influx/templates.go @@ -1,6 +1,7 @@ package influx import ( + "regexp" "sort" "strconv" "strings" @@ -49,13 +50,30 @@ func RenderTemplate(query string, t chronograf.TemplateVar, now time.Time) (stri return query, nil } + var q string + + // First render template variable usages appearing within an InfluxQL regular expression (value should appear unquoted) + switch t.Values[0].Type { + case "tagKey", "fieldKey", "measurement", "tagValue": + r, err := regexp.Compile(`(/[.^/]*)(` + regexp.QuoteMeta(t.Var) + `)([.^/]*/)`) + + if err != nil { + return "", err + } + + q = r.ReplaceAllString(query, `${1}`+t.Values[0].Value+`${3}`) + default: + q = query + } + + // Then render template variable usages not appearing in an InfluxQL regular expression (values may be quoted) switch t.Values[0].Type { case "tagKey", "fieldKey", "measurement", "database": - return strings.Replace(query, t.Var, `"`+t.Values[0].Value+`"`, -1), nil + return strings.Replace(q, t.Var, `"`+t.Values[0].Value+`"`, -1), nil case "tagValue", "timeStamp": - return strings.Replace(query, t.Var, `'`+t.Values[0].Value+`'`, -1), nil + return strings.Replace(q, t.Var, `'`+t.Values[0].Value+`'`, -1), nil case "csv", "constant": - return strings.Replace(query, t.Var, t.Values[0].Value, -1), nil + return strings.Replace(q, t.Var, t.Values[0].Value, -1), nil } tv := map[string]string{} diff --git a/influx/templates_test.go b/influx/templates_test.go index 5d131b416b..3da6ef421f 100644 --- a/influx/templates_test.go +++ b/influx/templates_test.go @@ -297,6 +297,32 @@ func TestTemplateReplace(t *testing.T) { }, want: `SHOW DATABASES`, }, + { + name: "query with some tagValue template variables inside a regex", + query: `SELECT "usage_active" FROM "cpu" WHERE host =~ /:host:/ AND time > :dashboardTime: FILL(null)`, + vars: []chronograf.TemplateVar{ + { + Var: ":host:", + Values: []chronograf.TemplateValue{ + { + Value: "my-host.local", + Type: "tagValue", + }, + }, + }, + { + Var: ":dashboardTime:", + Values: []chronograf.TemplateValue{ + { + Value: "now() - 1h", + Type: "constant", + Selected: true, + }, + }, + }, + }, + want: `SELECT "usage_active" FROM "cpu" WHERE host =~ /my-host.local/ AND time > now() - 1h FILL(null)`, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {