diff --git a/config/config.go b/config/config.go index a6696c1c..1ac83b2a 100644 --- a/config/config.go +++ b/config/config.go @@ -123,7 +123,22 @@ func (ch *MySqlConfigHandler) ReloadConfig(filename string, mysqldAddress string } } - cfg.ValueMapper = os.ExpandEnv + cfg.ValueMapper = func(val string) string { + i := 0 + for i < len(val) && val[i] == '$' { + i++ + } + + if i == 0 { + return val + } + + if i%2 == 0 { + return strings.Repeat("$", i/2) + val[i:] + } + + return os.ExpandEnv(val[i-1:]) + } config := &Config{} m := make(map[string]MySqlConfig) for _, sec := range cfg.Sections() { diff --git a/config/config_test.go b/config/config_test.go index d9237636..71658be0 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -153,6 +153,57 @@ func TestValidateConfig(t *testing.T) { convey.So(section.Password, convey.ShouldEqual, "foo") convey.So(section.EnableCleartextPlugin, convey.ShouldBeTrue) }) + + convey.Convey("Expand variables", t, func() { + c := MySqlConfigHandler{ + Config: &Config{}, + } + os.Setenv("MYSQLD_EXPORTER_PASSWORD", "supersecretpassword") + if err := c.ReloadConfig("testdata/expand_variables.cnf", "localhost:3306", "", true, promslog.NewNopLogger()); err != nil { + t.Error(err) + } + + cfg := c.GetConfig() + section := cfg.Sections["client.server1"] + convey.So(section.User, convey.ShouldEqual, "test") + convey.So(section.Password, convey.ShouldEqual, "foo") + + section = cfg.Sections["client.env"] + convey.So(section.User, convey.ShouldEqual, "test2") + convey.So(section.Password, convey.ShouldEqual, "supersecretpassword") + + section = cfg.Sections["client.notExpandEnv"] + convey.So(section.User, convey.ShouldEqual, "mysql_exporter") + convey.So(section.Password, convey.ShouldEqual, "SECRET_PA$SWORD") + + section = cfg.Sections["client.envNotExists"] + convey.So(section.User, convey.ShouldEqual, "test") + convey.So(section.Password, convey.ShouldEqual, "") + + section = cfg.Sections["client.envEscaped"] + convey.So(section.User, convey.ShouldEqual, "test") + convey.So(section.Password, convey.ShouldEqual, "$MYSQLD_EXPORTER_PASSWORD") + + section = cfg.Sections["client.password$$Escaped"] + convey.So(section.User, convey.ShouldEqual, "test") + convey.So(section.Password, convey.ShouldEqual, "$$MYSQLD_EXPORTER_PASSWORD") + + section = cfg.Sections["client.password$$$Env"] + convey.So(section.User, convey.ShouldEqual, "test") + convey.So(section.Password, convey.ShouldEqual, "supersecretpassword") + + section = cfg.Sections["client.password$$$Escaped"] + convey.So(section.User, convey.ShouldEqual, "test") + convey.So(section.Password, convey.ShouldEqual, "$$$MYSQLD_EXPORTER_PASSWORD") + + section = cfg.Sections["client.password$$$$Escaped"] + convey.So(section.User, convey.ShouldEqual, "test") + convey.So(section.Password, convey.ShouldEqual, "$$$$MYSQLD_EXPORTER_PASSWORD") + + section = cfg.Sections["client.password$$$$$Env"] + convey.So(section.User, convey.ShouldEqual, "test") + convey.So(section.Password, convey.ShouldEqual, "supersecretpassword") + }) } func TestFormDSN(t *testing.T) { diff --git a/config/testdata/expand_variables.cnf b/config/testdata/expand_variables.cnf new file mode 100644 index 00000000..eb488d52 --- /dev/null +++ b/config/testdata/expand_variables.cnf @@ -0,0 +1,30 @@ +[client.server1] +user = test +password = foo +[client.env] +user = test2 +password = $MYSQLD_EXPORTER_PASSWORD +[client.notExpandEnv] +user = mysql_exporter +password = SECRET_PA$SWORD +[client.envNotExists] +user = test +password = $ENV_NOT_EXISTS +[client.envEscaped] +user = test +password = $$MYSQLD_EXPORTER_PASSWORD +[client.password$$Escaped] +user = test +password = $$$$MYSQLD_EXPORTER_PASSWORD +[client.password$$$Env] +user = test +password = $$$MYSQLD_EXPORTER_PASSWORD +[client.password$$$Escaped] +user = test +password = $$$$$$MYSQLD_EXPORTER_PASSWORD +[client.password$$$$Escaped] +user = test +password = $$$$$$$$MYSQLD_EXPORTER_PASSWORD +[client.password$$$$$Env] +user = test +password = $$$$$MYSQLD_EXPORTER_PASSWORD