Explorar o código

provisioning: escape literal '$' with '$$' to avoid interpolation (#18045)

fixes #17986
Kyle Brandt %!s(int64=6) %!d(string=hai) anos
pai
achega
76d08989f0

+ 2 - 0
docs/sources/administration/provisioning.md

@@ -45,6 +45,8 @@ datasources:
     password: $PASSWORD
 ```
 
+If you have a literal `$` in your value and want to avoid interpolation, `$$` can be used.
+
 <hr />
 
 ## Configuration Management Tools

+ 8 - 1
pkg/services/provisioning/values/values.go

@@ -14,6 +14,7 @@ import (
 	"os"
 	"reflect"
 	"strconv"
+	"strings"
 
 	"github.com/grafana/grafana/pkg/util/errutil"
 )
@@ -185,8 +186,14 @@ func transformMap(i map[interface{}]interface{}) interface{} {
 
 // interpolateValue returns final value after interpolation. At the moment only env var interpolation is done
 // here but in the future something like interpolation from file could be also done here.
+// For a literal '$', '$$' can be used to avoid interpolation.
 func interpolateValue(val string) string {
-	return os.ExpandEnv(val)
+	parts := strings.Split(val, "$$")
+	interpolated := make([]string, len(parts))
+	for i, v := range parts {
+		interpolated[i] = os.ExpandEnv(v)
+	}
+	return strings.Join(interpolated, "$")
 }
 
 type interpolated struct {

+ 23 - 2
pkg/services/provisioning/values/values_test.go

@@ -1,16 +1,18 @@
 package values
 
 import (
-	. "github.com/smartystreets/goconvey/convey"
-	"gopkg.in/yaml.v2"
 	"os"
 	"testing"
+
+	. "github.com/smartystreets/goconvey/convey"
+	"gopkg.in/yaml.v2"
 )
 
 func TestValues(t *testing.T) {
 	Convey("Values", t, func() {
 		os.Setenv("INT", "1")
 		os.Setenv("STRING", "test")
+		os.Setenv("EMPTYSTRING", "")
 		os.Setenv("BOOL", "true")
 
 		Convey("IntValue", func() {
@@ -61,6 +63,24 @@ func TestValues(t *testing.T) {
 				So(d.Val.Value(), ShouldEqual, "")
 				So(d.Val.Raw, ShouldEqual, "")
 			})
+
+			Convey("empty var should have empty value", func() {
+				unmarshalingTest(`val: $EMPTYSTRING`, d)
+				So(d.Val.Value(), ShouldEqual, "")
+				So(d.Val.Raw, ShouldEqual, "$EMPTYSTRING")
+			})
+
+			Convey("$$ should be a literal $", func() {
+				unmarshalingTest(`val: $$`, d)
+				So(d.Val.Value(), ShouldEqual, "$")
+				So(d.Val.Raw, ShouldEqual, "$$")
+			})
+
+			Convey("$$ should be a literal $ and not expanded within a string", func() {
+				unmarshalingTest(`val: mY,Passwo$$rd`, d)
+				So(d.Val.Value(), ShouldEqual, "mY,Passwo$rd")
+				So(d.Val.Raw, ShouldEqual, "mY,Passwo$$rd")
+			})
 		})
 
 		Convey("BoolValue", func() {
@@ -199,6 +219,7 @@ func TestValues(t *testing.T) {
 		Reset(func() {
 			os.Unsetenv("INT")
 			os.Unsetenv("STRING")
+			os.Unsetenv("EMPTYSTRING")
 			os.Unsetenv("BOOL")
 		})
 	})