瀏覽代碼

CLI: Fix encrypt-datasource-passwords fails with sql error (#18014)

Now handles secure_json_data stored as null in database when
running the encrypt-datasource-passwords migration.

Fixes #17948
Marcus Efraimsson 6 年之前
父節點
當前提交
6a3a2f5f94

+ 11 - 7
pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords.go

@@ -62,7 +62,7 @@ func EncryptDatasourcePaswords(c utils.CommandLine, sqlStore *sqlstore.SqlStore)
 }
 
 func migrateColumn(session *sqlstore.DBSession, column string) (int, error) {
-	var rows []map[string]string
+	var rows []map[string][]byte
 
 	session.Cols("id", column, "secure_json_data")
 	session.Table("data_source")
@@ -78,7 +78,7 @@ func migrateColumn(session *sqlstore.DBSession, column string) (int, error) {
 	return rowsUpdated, errutil.Wrapf(err, "failed to update column: %s", column)
 }
 
-func updateRows(session *sqlstore.DBSession, rows []map[string]string, passwordFieldName string) (int, error) {
+func updateRows(session *sqlstore.DBSession, rows []map[string][]byte, passwordFieldName string) (int, error) {
 	var rowsUpdated int
 
 	for _, row := range rows {
@@ -94,7 +94,7 @@ func updateRows(session *sqlstore.DBSession, rows []map[string]string, passwordF
 
 		newRow := map[string]interface{}{"secure_json_data": data, passwordFieldName: ""}
 		session.Table("data_source")
-		session.Where("id = ?", row["id"])
+		session.Where("id = ?", string(row["id"]))
 		// Setting both columns while having value only for secure_json_data should clear the [passwordFieldName] column
 		session.Cols("secure_json_data", passwordFieldName)
 
@@ -108,16 +108,20 @@ func updateRows(session *sqlstore.DBSession, rows []map[string]string, passwordF
 	return rowsUpdated, nil
 }
 
-func getUpdatedSecureJSONData(row map[string]string, passwordFieldName string) (map[string]interface{}, error) {
-	encryptedPassword, err := util.Encrypt([]byte(row[passwordFieldName]), setting.SecretKey)
+func getUpdatedSecureJSONData(row map[string][]byte, passwordFieldName string) (map[string]interface{}, error) {
+	encryptedPassword, err := util.Encrypt(row[passwordFieldName], setting.SecretKey)
 	if err != nil {
 		return nil, err
 	}
 
 	var secureJSONData map[string]interface{}
 
-	if err := json.Unmarshal([]byte(row["secure_json_data"]), &secureJSONData); err != nil {
-		return nil, err
+	if len(row["secure_json_data"]) > 0 {
+		if err := json.Unmarshal(row["secure_json_data"], &secureJSONData); err != nil {
+			return nil, err
+		}
+	} else {
+		secureJSONData = map[string]interface{}{}
 	}
 
 	jsonFieldName := util.ToCamelCase(passwordFieldName)

+ 24 - 3
pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords_test.go

@@ -20,19 +20,30 @@ func TestPasswordMigrationCommand(t *testing.T) {
 	datasources := []*models.DataSource{
 		{Type: "influxdb", Name: "influxdb", Password: "foobar"},
 		{Type: "graphite", Name: "graphite", BasicAuthPassword: "foobar"},
-		{Type: "prometheus", Name: "prometheus", SecureJsonData: securejsondata.GetEncryptedJsonData(map[string]string{})},
+		{Type: "prometheus", Name: "prometheus"},
+		{Type: "elasticsearch", Name: "elasticsearch", Password: "pwd"},
 	}
 
 	// set required default values
 	for _, ds := range datasources {
 		ds.Created = time.Now()
 		ds.Updated = time.Now()
-		ds.SecureJsonData = securejsondata.GetEncryptedJsonData(map[string]string{})
+		if ds.Name == "elasticsearch" {
+			ds.SecureJsonData = securejsondata.GetEncryptedJsonData(map[string]string{
+				"key": "value",
+			})
+		} else {
+			ds.SecureJsonData = securejsondata.GetEncryptedJsonData(map[string]string{})
+		}
 	}
 
 	_, err := session.Insert(&datasources)
 	assert.Nil(t, err)
 
+	// force secure_json_data to be null to verify that migration can handle that
+	_, err = session.Exec("update data_source set secure_json_data = null where name = 'influxdb'")
+	assert.Nil(t, err)
+
 	//run migration
 	err = EncryptDatasourcePaswords(&commandstest.FakeCommandLine{}, sqlstore)
 	assert.Nil(t, err)
@@ -41,7 +52,7 @@ func TestPasswordMigrationCommand(t *testing.T) {
 	var dss []*models.DataSource
 	err = session.SQL("select * from data_source").Find(&dss)
 	assert.Nil(t, err)
-	assert.Equal(t, len(dss), 3)
+	assert.Equal(t, len(dss), 4)
 
 	for _, ds := range dss {
 		sj := ds.SecureJsonData.Decrypt()
@@ -63,5 +74,15 @@ func TestPasswordMigrationCommand(t *testing.T) {
 		if ds.Name == "prometheus" {
 			assert.Equal(t, len(sj), 0)
 		}
+
+		if ds.Name == "elasticsearch" {
+			assert.Equal(t, ds.Password, "")
+			key, exist := sj["key"]
+			assert.True(t, exist)
+			password, exist := sj["password"]
+			assert.True(t, exist)
+			assert.Equal(t, password, "pwd", "expected password to be moved to securejson")
+			assert.Equal(t, key, "value", "expected existing key to be kept intact in securejson")
+		}
 	}
 }