From 6a3a2f5f9448dafc5b61a038e27523001f409a24 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Wed, 10 Jul 2019 12:28:40 +0200 Subject: [PATCH] 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 --- .../encrypt_datasource_passwords.go | 18 ++++++++----- .../encrypt_datasource_passwords_test.go | 27 ++++++++++++++++--- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords.go b/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords.go index e55fa2d70b8..26418714a0d 100644 --- a/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords.go +++ b/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) diff --git a/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords_test.go b/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords_test.go index 64987423dec..2d9a04d3775 100644 --- a/pkg/cmd/grafana-cli/commands/datamigrations/encrypt_datasource_passwords_test.go +++ b/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") + } } }