瀏覽代碼

Merge branch 'database_url' of https://github.com/Scalingo/grafana into Scalingo-database_url

bergquist 9 年之前
父節點
當前提交
c663e32ea8
共有 4 個文件被更改,包括 60 次插入7 次删除
  1. 3 0
      conf/defaults.ini
  2. 27 7
      pkg/services/sqlstore/sqlstore.go
  3. 16 0
      pkg/setting/setting.go
  4. 14 0
      pkg/setting/setting_test.go

+ 3 - 0
conf/defaults.ini

@@ -65,6 +65,9 @@ host = 127.0.0.1:3306
 name = grafana
 user = root
 password =
+# Use either URL or the previous fields to configure the database
+# Example: mysql://user:secret@host:port/database
+url =
 
 # For "postgres", use either "disable", "require" or "verify-full"
 # For "mysql", use either "true", "false", or "skip-verify".

+ 27 - 7
pkg/services/sqlstore/sqlstore.go

@@ -2,6 +2,7 @@ package sqlstore
 
 import (
 	"fmt"
+	"net/url"
 	"os"
 	"path"
 	"path/filepath"
@@ -155,16 +156,35 @@ func getEngine() (*xorm.Engine, error) {
 func LoadConfig() {
 	sec := setting.Cfg.Section("database")
 
-	DbCfg.Type = sec.Key("type").String()
+	cfgURL := sec.Key("url").String()
+	if len(cfgURL) != 0 {
+		dbURL, _ := url.Parse(cfgURL)
+		DbCfg.Type = dbURL.Scheme
+		DbCfg.Host = dbURL.Host
+
+		pathSplit := strings.Split(dbURL.Path, "/")
+		if len(pathSplit) > 1 {
+			DbCfg.Name = pathSplit[1]
+		}
+
+		userInfo := dbURL.User
+		if userInfo != nil {
+			DbCfg.User = userInfo.Username()
+			DbCfg.Pwd, _ = userInfo.Password()
+		}
+	} else {
+		DbCfg.Type = sec.Key("type").String()
+		DbCfg.Host = sec.Key("host").String()
+		DbCfg.Name = sec.Key("name").String()
+		DbCfg.User = sec.Key("user").String()
+		if len(DbCfg.Pwd) == 0 {
+			DbCfg.Pwd = sec.Key("password").String()
+		}
+	}
+
 	if DbCfg.Type == "sqlite3" {
 		UseSQLite3 = true
 	}
-	DbCfg.Host = sec.Key("host").String()
-	DbCfg.Name = sec.Key("name").String()
-	DbCfg.User = sec.Key("user").String()
-	if len(DbCfg.Pwd) == 0 {
-		DbCfg.Pwd = sec.Key("password").String()
-	}
 	DbCfg.SslMode = sec.Key("ssl_mode").String()
 	DbCfg.Path = sec.Key("path").MustString("data/grafana.db")
 

+ 16 - 0
pkg/setting/setting.go

@@ -183,6 +183,11 @@ func shouldRedactKey(s string) bool {
 	return strings.Contains(uppercased, "PASSWORD") || strings.Contains(uppercased, "SECRET")
 }
 
+func shouldRedactURLKey(s string) bool {
+	uppercased := strings.ToUpper(s)
+	return strings.Contains(uppercased, "DATABASE_URL")
+}
+
 func applyEnvVariableOverrides() {
 	appliedEnvOverrides = make([]string, 0)
 	for _, section := range Cfg.Sections() {
@@ -197,6 +202,17 @@ func applyEnvVariableOverrides() {
 				if shouldRedactKey(envKey) {
 					envValue = "*********"
 				}
+				if shouldRedactURLKey(envKey) {
+					u, _ := url.Parse(envValue)
+					ui := u.User
+					if ui != nil {
+						_, exists := ui.Password()
+						if exists {
+							u.User = url.UserPassword(ui.Username(), "-redacted-")
+							envValue = u.String()
+						}
+					}
+				}
 				appliedEnvOverrides = append(appliedEnvOverrides, fmt.Sprintf("%s=%s", envKey, envValue))
 			}
 		}

+ 14 - 0
pkg/setting/setting_test.go

@@ -29,6 +29,20 @@ func TestLoadingSettings(t *testing.T) {
 			So(LogsPath, ShouldEqual, filepath.Join(DataPath, "log"))
 		})
 
+		Convey("Should replace password when defined in environment", func() {
+			os.Setenv("GF_SECURITY_ADMIN_PASSWORD", "supersecret")
+			NewConfigContext(&CommandLineArgs{HomePath: "../../"})
+
+			So(appliedEnvOverrides, ShouldContain, "GF_SECURITY_ADMIN_PASSWORD=*********")
+		})
+
+		Convey("Should replace password in URL when url environment is defined", func() {
+			os.Setenv("GF_DATABASE_URL", "mysql://user:secret@localhost:3306/database")
+			NewConfigContext(&CommandLineArgs{HomePath: "../../"})
+
+			So(appliedEnvOverrides, ShouldContain, "GF_DATABASE_URL=mysql://user:-redacted-@localhost:3306/database")
+		})
+
 		Convey("Should get property map from command line args array", func() {
 			props := getCommandLineProperties([]string{"cfg:test=value", "cfg:map.test=1"})