From eb9affc7e3f93300b3a21bdb6f5441d519163acd Mon Sep 17 00:00:00 2001 From: Elfo404 Date: Thu, 30 Jun 2022 18:17:43 +0100 Subject: [PATCH] Correlations: Make correlations work with provisioning --- devenv/datasources.yaml | 7 +++ pkg/services/datasources/models.go | 2 + .../provisioning/datasources/types.go | 33 +++++++++++++ pkg/services/provisioning/values/values.go | 34 +++++++++++++ .../provisioning/values/values_test.go | 49 +++++++++++++++++++ pkg/services/sqlstore/datasource.go | 3 +- 6 files changed, 127 insertions(+), 1 deletion(-) diff --git a/devenv/datasources.yaml b/devenv/datasources.yaml index a8c68ee1bb1..2321fd56911 100644 --- a/devenv/datasources.yaml +++ b/devenv/datasources.yaml @@ -247,6 +247,13 @@ datasources: access: proxy url: http://localhost:3100 editable: false + correlations: + - targetUid: gdev-jaeger + label: "Jaeger traces" + description: "Related traces stored in Jaeger" + - targetUid: gdev-zipkin + label: "Zipkin traces" + description: "Related traces stored in Zipkin" jsonData: manageAlerts: false derivedFields: diff --git a/pkg/services/datasources/models.go b/pkg/services/datasources/models.go index 9ecc80da9ab..677a9c5d188 100644 --- a/pkg/services/datasources/models.go +++ b/pkg/services/datasources/models.go @@ -101,6 +101,7 @@ type AddDataSourceCommand struct { BasicAuthUser string `json:"basicAuthUser"` WithCredentials bool `json:"withCredentials"` IsDefault bool `json:"isDefault"` + Correlations []Correlation `json:"-"` JsonData *simplejson.Json `json:"jsonData"` SecureJsonData map[string]string `json:"secureJsonData"` Uid string `json:"uid"` @@ -126,6 +127,7 @@ type UpdateDataSourceCommand struct { BasicAuthUser string `json:"basicAuthUser"` WithCredentials bool `json:"withCredentials"` IsDefault bool `json:"isDefault"` + Correlations []Correlation `json:"correlations"` JsonData *simplejson.Json `json:"jsonData"` SecureJsonData map[string]string `json:"secureJsonData"` Version int `json:"version"` diff --git a/pkg/services/provisioning/datasources/types.go b/pkg/services/provisioning/datasources/types.go index 6f2c24c3493..8f510ece1b9 100644 --- a/pkg/services/provisioning/datasources/types.go +++ b/pkg/services/provisioning/datasources/types.go @@ -42,6 +42,7 @@ type upsertDataSourceFromConfig struct { BasicAuthUser string WithCredentials bool IsDefault bool + Correlations []datasources.Correlation JSONData map[string]interface{} SecureJSONData map[string]string Editable bool @@ -86,6 +87,7 @@ type upsertDataSourceFromConfigV0 struct { BasicAuthUser string `json:"basic_auth_user" yaml:"basic_auth_user"` WithCredentials bool `json:"with_credentials" yaml:"with_credentials"` IsDefault bool `json:"is_default" yaml:"is_default"` + Correlations []interface{} `json:"correlations" yaml:"correlations"` JSONData map[string]interface{} `json:"json_data" yaml:"json_data"` SecureJSONData map[string]string `json:"secure_json_data" yaml:"secure_json_data"` Editable bool `json:"editable" yaml:"editable"` @@ -104,6 +106,7 @@ type upsertDataSourceFromConfigV1 struct { BasicAuthUser values.StringValue `json:"basicAuthUser" yaml:"basicAuthUser"` WithCredentials values.BoolValue `json:"withCredentials" yaml:"withCredentials"` IsDefault values.BoolValue `json:"isDefault" yaml:"isDefault"` + Correlations values.JSONSliceValue `json:"correlations" yaml:"correlations"` JSONData values.JSONValue `json:"jsonData" yaml:"jsonData"` SecureJSONData values.StringMapValue `json:"secureJsonData" yaml:"secureJsonData"` Editable values.BoolValue `json:"editable" yaml:"editable"` @@ -120,6 +123,19 @@ func (cfg *configsV1) mapToDatasourceFromConfig(apiVersion int64) *configs { } for _, ds := range cfg.Datasources { + correlations := make([]datasources.Correlation, 0) + for _, v := range ds.Correlations.Value() { + field, ok := v.(map[string]interface{}) + + if ok { + correlations = append(correlations, datasources.Correlation{ + Target: field["targetUid"].(string), + Description: field["description"].(string), + Label: field["label"].(string), + }) + } + } + r.Datasources = append(r.Datasources, &upsertDataSourceFromConfig{ OrgID: ds.OrgID.Value(), Name: ds.Name.Value(), @@ -132,6 +148,7 @@ func (cfg *configsV1) mapToDatasourceFromConfig(apiVersion int64) *configs { BasicAuthUser: ds.BasicAuthUser.Value(), WithCredentials: ds.WithCredentials.Value(), IsDefault: ds.IsDefault.Value(), + Correlations: correlations, JSONData: ds.JSONData.Value(), SecureJSONData: ds.SecureJSONData.Value(), Editable: ds.Editable.Value(), @@ -160,6 +177,19 @@ func (cfg *configsV0) mapToDatasourceFromConfig(apiVersion int64) *configs { } for _, ds := range cfg.Datasources { + correlations := make([]datasources.Correlation, 0) + for _, v := range ds.Correlations { + field, ok := v.(map[string]interface{}) + + if ok { + correlations = append(correlations, datasources.Correlation{ + Target: field["targetUid"].(string), + Description: field["description"].(string), + Label: field["label"].(string), + }) + } + } + r.Datasources = append(r.Datasources, &upsertDataSourceFromConfig{ OrgID: ds.OrgID, Name: ds.Name, @@ -172,6 +202,7 @@ func (cfg *configsV0) mapToDatasourceFromConfig(apiVersion int64) *configs { BasicAuthUser: ds.BasicAuthUser, WithCredentials: ds.WithCredentials, IsDefault: ds.IsDefault, + Correlations: correlations, JSONData: ds.JSONData, SecureJSONData: ds.SecureJSONData, Editable: ds.Editable, @@ -209,6 +240,7 @@ func createInsertCommand(ds *upsertDataSourceFromConfig) *datasources.AddDataSou BasicAuthUser: ds.BasicAuthUser, WithCredentials: ds.WithCredentials, IsDefault: ds.IsDefault, + Correlations: ds.Correlations, JsonData: jsonData, SecureJsonData: ds.SecureJSONData, ReadOnly: !ds.Editable, @@ -250,6 +282,7 @@ func createUpdateCommand(ds *upsertDataSourceFromConfig, id int64) *datasources. BasicAuthUser: ds.BasicAuthUser, WithCredentials: ds.WithCredentials, IsDefault: ds.IsDefault, + Correlations: ds.Correlations, JsonData: jsonData, SecureJsonData: ds.SecureJSONData, ReadOnly: !ds.Editable, diff --git a/pkg/services/provisioning/values/values.go b/pkg/services/provisioning/values/values.go index ce771310799..1b504605a57 100644 --- a/pkg/services/provisioning/values/values.go +++ b/pkg/services/provisioning/values/values.go @@ -188,6 +188,40 @@ func (val *StringMapValue) Value() map[string]string { return val.value } +// JSONSliceValue represents a slice value in a YAML +// config that can be overridden by environment variables + +type JSONSliceValue struct { + value []interface{} + Raw []interface{} +} + +// UnmarshalYAML converts YAML into an *JSONSliceValue +func (val *JSONSliceValue) UnmarshalYAML(unmarshal func(interface{}) error) error { + unmarshaled := make([]interface{}, 0) + err := unmarshal(&unmarshaled) + if err != nil { + return err + } + + for _, v := range unmarshaled { + interpolated, raw, err := transformInterface(v) + if err != nil { + return err + } + + val.value = append(val.value, interpolated) + val.Raw = append(val.Raw, raw) + } + + return err +} + +// Value returns the wrapped []interface{} value +func (val *JSONSliceValue) Value() []interface{} { + return val.value +} + // transformInterface tries to transform any interface type into proper value with env expansion. It traverses maps and // slices and the actual interpolation is done on all simple string values in the structure. It returns a copy of any // map or slice value instead of modifying them in place and also return value without interpolation but with converted diff --git a/pkg/services/provisioning/values/values_test.go b/pkg/services/provisioning/values/values_test.go index 3d7d3308e8f..3429d961368 100644 --- a/pkg/services/provisioning/values/values_test.go +++ b/pkg/services/provisioning/values/values_test.go @@ -220,6 +220,55 @@ func TestValues(t *testing.T) { }) }) + t.Run("JSONSliceValue", func(t *testing.T) { + type Data struct { + Val JSONSliceValue `yaml:"val"` + } + d := &Data{} + + t.Run("Should unmarshal top-level slices and nested structures", func(t *testing.T) { + doc := ` + val: + - $STRING + - $INT + - stringMap: + interpolatedString: $STRING + interpolatedInt: $INT + string: "just a string" + sameLevel: $STRING + ` + unmarshalingTest(t, doc, d) + + type stringMap = map[string]interface{} + + require.Equal(t, []interface{}{ + "test", + "1", + stringMap{ + "stringMap": stringMap{ + "interpolatedString": "test", + "interpolatedInt": "1", + "string": "just a string", + }, + "sameLevel": "test", + }, + }, d.Val.Value()) + + require.Equal(t, []interface{}{ + "$STRING", + "$INT", + stringMap{ + "stringMap": stringMap{ + "interpolatedString": "$STRING", + "interpolatedInt": "$INT", + "string": "just a string", + }, + "sameLevel": "$STRING", + }, + }, d.Val.Raw) + }) + }) + t.Run("StringMapValue", func(t *testing.T) { type Data struct { Val StringMapValue `yaml:"val"` diff --git a/pkg/services/sqlstore/datasource.go b/pkg/services/sqlstore/datasource.go index 198a448cf00..13b8a9bd44d 100644 --- a/pkg/services/sqlstore/datasource.go +++ b/pkg/services/sqlstore/datasource.go @@ -169,6 +169,7 @@ func (ss *SQLStore) AddDataSource(ctx context.Context, cmd *datasources.AddDataS BasicAuth: cmd.BasicAuth, BasicAuthUser: cmd.BasicAuthUser, WithCredentials: cmd.WithCredentials, + Correlations: cmd.Correlations, JsonData: cmd.JsonData, SecureJsonData: cmd.EncryptedSecureJsonData, Created: time.Now(), @@ -303,7 +304,7 @@ func (ss *SQLStore) UpdateCorrelations(ctx context.Context, cmd *datasources.Upd } if affected == 0 { - return datasources.ErrDataSourceUpdatingOldVersion + return datasources.ErrDataSourceNotFound } cmd.Result = cmd.Correlations