AzureMonitor: Remove `simplejson`

* tsdb: azuremonitor: Remove usage of simplejson

* Review fixes

* Fix lint errors; review fix
pull/68885/head
ZakharE 2 years ago committed by GitHub
parent 5e5c751ecd
commit 5e8bd48c3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      pkg/tsdb/azuremonitor/azuremonitor.go
  2. 20
      pkg/tsdb/azuremonitor/credentials.go
  3. 93
      pkg/tsdb/azuremonitor/credentials_test.go
  4. 26
      pkg/tsdb/azuremonitor/macros/macros.go
  5. 5
      pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource_test.go
  6. 3
      pkg/tsdb/azuremonitor/metrics/migrations_test.go
  7. 7
      pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource.go
  8. 3
      pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource_test.go
  9. 12
      pkg/tsdb/azuremonitor/types/types.go

@ -17,7 +17,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/setting"
@ -83,23 +82,19 @@ func getDatasourceService(settings *backend.DataSourceInstanceSettings, cfg *set
func NewInstanceSettings(cfg *setting.Cfg, clientProvider *httpclient.Provider, executors map[string]azDatasourceExecutor) datasource.InstanceFactoryFunc {
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
jsonData, err := simplejson.NewJson(settings.JSONData)
if err != nil {
return nil, fmt.Errorf("error reading settings: %w", err)
}
jsonDataObj := map[string]any{}
err = json.Unmarshal(settings.JSONData, &jsonDataObj)
err := json.Unmarshal(settings.JSONData, &jsonDataObj)
if err != nil {
return nil, fmt.Errorf("error reading settings: %w", err)
}
azMonitorSettings := types.AzureMonitorSettings{}
err = json.Unmarshal(settings.JSONData, &azMonitorSettings)
azSettings := types.AzureSettings{}
err = json.Unmarshal(settings.JSONData, &azSettings)
if err != nil {
return nil, fmt.Errorf("error reading settings: %w", err)
}
cloud, err := getAzureCloud(cfg, jsonData)
cloud, err := getAzureCloud(cfg, &azSettings.AzureClientSettings)
if err != nil {
return nil, fmt.Errorf("error getting credentials: %w", err)
}
@ -109,7 +104,7 @@ func NewInstanceSettings(cfg *setting.Cfg, clientProvider *httpclient.Provider,
return nil, err
}
credentials, err := getAzureCredentials(cfg, jsonData, settings.DecryptedSecureJSONData)
credentials, err := getAzureCredentials(cfg, &azSettings.AzureClientSettings, settings.DecryptedSecureJSONData)
if err != nil {
return nil, fmt.Errorf("error getting credentials: %w", err)
}
@ -117,7 +112,7 @@ func NewInstanceSettings(cfg *setting.Cfg, clientProvider *httpclient.Provider,
model := types.DatasourceInfo{
Cloud: cloud,
Credentials: credentials,
Settings: azMonitorSettings,
Settings: azSettings.AzureMonitorSettings,
JSONData: jsonDataObj,
DecryptedSecureJSONData: settings.DecryptedSecureJSONData,
DatasourceID: settings.ID,

@ -6,8 +6,8 @@ import (
"github.com/grafana/grafana-azure-sdk-go/azcredentials"
"github.com/grafana/grafana-azure-sdk-go/azsettings"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
)
// Azure cloud names specific to Azure Monitor
@ -18,12 +18,12 @@ const (
azureMonitorCustomized = "customizedazuremonitor"
)
func getAuthType(cfg *setting.Cfg, jsonData *simplejson.Json) string {
if azureAuthType := jsonData.Get("azureAuthType").MustString(); azureAuthType != "" {
func getAuthType(cfg *setting.Cfg, jsonData *types.AzureClientSettings) string {
if azureAuthType := jsonData.AzureAuthType; azureAuthType != "" {
return azureAuthType
} else {
tenantId := jsonData.Get("tenantId").MustString()
clientId := jsonData.Get("clientId").MustString()
tenantId := jsonData.TenantId
clientId := jsonData.ClientId
// If authentication type isn't explicitly specified and datasource has client credentials,
// then this is existing datasource which is configured for app registration (client secret)
@ -81,14 +81,14 @@ func normalizeAzureCloud(cloudName string) (string, error) {
}
}
func getAzureCloud(cfg *setting.Cfg, jsonData *simplejson.Json) (string, error) {
func getAzureCloud(cfg *setting.Cfg, jsonData *types.AzureClientSettings) (string, error) {
authType := getAuthType(cfg, jsonData)
switch authType {
case azcredentials.AzureAuthManagedIdentity:
// In case of managed identity, the cloud is always same as where Grafana is hosted
return getDefaultAzureCloud(cfg)
case azcredentials.AzureAuthClientSecret:
if cloud := jsonData.Get("cloudName").MustString(); cloud != "" {
if cloud := jsonData.CloudName; cloud != "" {
return normalizeAzureCloud(cloud)
} else {
return getDefaultAzureCloud(cfg)
@ -99,7 +99,7 @@ func getAzureCloud(cfg *setting.Cfg, jsonData *simplejson.Json) (string, error)
}
}
func getAzureCredentials(cfg *setting.Cfg, jsonData *simplejson.Json, secureJsonData map[string]string) (azcredentials.AzureCredentials, error) {
func getAzureCredentials(cfg *setting.Cfg, jsonData *types.AzureClientSettings, secureJsonData map[string]string) (azcredentials.AzureCredentials, error) {
authType := getAuthType(cfg, jsonData)
switch authType {
@ -117,8 +117,8 @@ func getAzureCredentials(cfg *setting.Cfg, jsonData *simplejson.Json, secureJson
}
credentials := &azcredentials.AzureClientSecretCredentials{
AzureCloud: cloud,
TenantId: jsonData.Get("tenantId").MustString(),
ClientId: jsonData.Get("clientId").MustString(),
TenantId: jsonData.TenantId,
ClientId: jsonData.ClientId,
ClientSecret: secureJsonData["clientSecret"],
}
return credentials, nil

@ -3,10 +3,11 @@ package azuremonitor
import (
"testing"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
"github.com/grafana/grafana-azure-sdk-go/azcredentials"
"github.com/grafana/grafana-azure-sdk-go/azsettings"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -21,9 +22,9 @@ func TestCredentials_getAuthType(t *testing.T) {
cfg.Azure.ManagedIdentityEnabled = true
t.Run("should be client secret if auth type is set to client secret", func(t *testing.T) {
jsonData := simplejson.NewFromAny(map[string]interface{}{
"azureAuthType": azcredentials.AzureAuthClientSecret,
})
jsonData := &types.AzureClientSettings{
AzureAuthType: azcredentials.AzureAuthClientSecret,
}
authType := getAuthType(cfg, jsonData)
@ -31,9 +32,9 @@ func TestCredentials_getAuthType(t *testing.T) {
})
t.Run("should be managed identity if datasource not configured", func(t *testing.T) {
jsonData := simplejson.NewFromAny(map[string]interface{}{
"azureAuthType": "",
})
jsonData := &types.AzureClientSettings{
AzureAuthType: "",
}
authType := getAuthType(cfg, jsonData)
@ -41,11 +42,11 @@ func TestCredentials_getAuthType(t *testing.T) {
})
t.Run("should be client secret if auth type not specified but credentials configured", func(t *testing.T) {
jsonData := simplejson.NewFromAny(map[string]interface{}{
"azureAuthType": "",
"tenantId": "9b9d90ee-a5cc-49c2-b97e-0d1b0f086b5c",
"clientId": "849ccbb0-92eb-4226-b228-ef391abd8fe6",
})
jsonData := &types.AzureClientSettings{
AzureAuthType: "",
TenantId: "9b9d90ee-a5cc-49c2-b97e-0d1b0f086b5c",
ClientId: "849ccbb0-92eb-4226-b228-ef391abd8fe6",
}
authType := getAuthType(cfg, jsonData)
@ -57,9 +58,9 @@ func TestCredentials_getAuthType(t *testing.T) {
cfg.Azure.ManagedIdentityEnabled = false
t.Run("should be managed identity if auth type is set to managed identity", func(t *testing.T) {
jsonData := simplejson.NewFromAny(map[string]interface{}{
"azureAuthType": azcredentials.AzureAuthManagedIdentity,
})
jsonData := &types.AzureClientSettings{
AzureAuthType: azcredentials.AzureAuthManagedIdentity,
}
authType := getAuthType(cfg, jsonData)
@ -67,9 +68,9 @@ func TestCredentials_getAuthType(t *testing.T) {
})
t.Run("should be client secret if datasource not configured", func(t *testing.T) {
jsonData := simplejson.NewFromAny(map[string]interface{}{
"azureAuthType": "",
})
jsonData := &types.AzureClientSettings{
AzureAuthType: "",
}
authType := getAuthType(cfg, jsonData)
@ -86,10 +87,10 @@ func TestCredentials_getAzureCloud(t *testing.T) {
}
t.Run("when auth type is managed identity", func(t *testing.T) {
jsonData := simplejson.NewFromAny(map[string]interface{}{
"azureAuthType": azcredentials.AzureAuthManagedIdentity,
"cloudName": azureMonitorUSGovernment,
})
jsonData := &types.AzureClientSettings{
AzureAuthType: azcredentials.AzureAuthManagedIdentity,
CloudName: azureMonitorUSGovernment,
}
t.Run("should be from server configuration regardless of datasource value", func(t *testing.T) {
cloud, err := getAzureCloud(cfg, jsonData)
@ -114,10 +115,10 @@ func TestCredentials_getAzureCloud(t *testing.T) {
t.Run("when auth type is client secret", func(t *testing.T) {
t.Run("should be from datasource value normalized to known cloud name", func(t *testing.T) {
jsonData := simplejson.NewFromAny(map[string]interface{}{
"azureAuthType": azcredentials.AzureAuthClientSecret,
"cloudName": azureMonitorUSGovernment,
})
jsonData := &types.AzureClientSettings{
AzureAuthType: azcredentials.AzureAuthClientSecret,
CloudName: azureMonitorUSGovernment,
}
cloud, err := getAzureCloud(cfg, jsonData)
require.NoError(t, err)
@ -126,10 +127,10 @@ func TestCredentials_getAzureCloud(t *testing.T) {
})
t.Run("should be from server configuration if not set in datasource", func(t *testing.T) {
jsonData := simplejson.NewFromAny(map[string]interface{}{
"azureAuthType": azcredentials.AzureAuthClientSecret,
"cloudName": "",
})
jsonData := &types.AzureClientSettings{
AzureAuthType: azcredentials.AzureAuthClientSecret,
CloudName: "",
}
cloud, err := getAzureCloud(cfg, jsonData)
require.NoError(t, err)
@ -151,12 +152,12 @@ func TestCredentials_getAzureCredentials(t *testing.T) {
}
t.Run("when auth type is managed identity", func(t *testing.T) {
jsonData := simplejson.NewFromAny(map[string]interface{}{
"azureAuthType": azcredentials.AzureAuthManagedIdentity,
"cloudName": azureMonitorUSGovernment,
"tenantId": "9b9d90ee-a5cc-49c2-b97e-0d1b0f086b5c",
"clientId": "849ccbb0-92eb-4226-b228-ef391abd8fe6",
})
jsonData := &types.AzureClientSettings{
AzureAuthType: azcredentials.AzureAuthManagedIdentity,
CloudName: azureMonitorUSGovernment,
TenantId: "9b9d90ee-a5cc-49c2-b97e-0d1b0f086b5c",
ClientId: "849ccbb0-92eb-4226-b228-ef391abd8fe6",
}
t.Run("should return managed identity credentials", func(t *testing.T) {
credentials, err := getAzureCredentials(cfg, jsonData, secureJsonData)
@ -170,26 +171,22 @@ func TestCredentials_getAzureCredentials(t *testing.T) {
})
t.Run("when auth type is client secret", func(t *testing.T) {
jsonData := simplejson.NewFromAny(map[string]interface{}{
"azureAuthType": azcredentials.AzureAuthClientSecret,
"cloudName": azUSGovManagement,
"tenantId": "9b9d90ee-a5cc-49c2-b97e-0d1b0f086b5c",
"clientId": "849ccbb0-92eb-4226-b228-ef391abd8fe6",
})
jsonData := &types.AzureClientSettings{
AzureAuthType: azcredentials.AzureAuthClientSecret,
CloudName: azureMonitorUSGovernment,
TenantId: "9b9d90ee-a5cc-49c2-b97e-0d1b0f086b5c",
ClientId: "849ccbb0-92eb-4226-b228-ef391abd8fe6",
}
t.Run("should return client secret credentials", func(t *testing.T) {
cfg := &setting.Cfg{
Azure: &azsettings.AzureSettings{
Cloud: azsettings.AzureChina,
},
}
cfg := &setting.Cfg{}
credentials, err := getAzureCredentials(cfg, jsonData, secureJsonData)
require.NoError(t, err)
require.IsType(t, &azcredentials.AzureClientSecretCredentials{}, credentials)
clientSecretCredentials := credentials.(*azcredentials.AzureClientSecretCredentials)
assert.Equal(t, azsettings.AzureChina, clientSecretCredentials.AzureCloud)
assert.Equal(t, azsettings.AzureUSGovernment, clientSecretCredentials.AzureCloud)
assert.Equal(t, "9b9d90ee-a5cc-49c2-b97e-0d1b0f086b5c", clientSecretCredentials.TenantId)
assert.Equal(t, "849ccbb0-92eb-4226-b228-ef391abd8fe6", clientSecretCredentials.ClientId)
assert.Equal(t, "59e3498f-eb12-4943-b8f0-a5aa42640058", clientSecretCredentials.ClientSecret)

@ -1,6 +1,7 @@
package macros
import (
"encoding/json"
"fmt"
"regexp"
"strings"
@ -8,12 +9,10 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/kinds/dataquery"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
"github.com/grafana/grafana/pkg/tsdb/legacydata/interval"
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
)
const rsIdentifier = `__(timeFilter|timeFrom|timeTo|interval|contains|escapeMulti)`
@ -90,6 +89,11 @@ func (m *kqlMacroEngine) Interpolate(logger log.Logger, query backend.DataQuery,
return kql, nil
}
type interval struct {
IntervalMs int64
Interval string
}
func (m *kqlMacroEngine) evaluateMacro(logger log.Logger, name string, defaultTimeField string, args []string, dsInfo types.DatasourceInfo) (string, error) {
switch name {
case "timeFilter":
@ -111,16 +115,22 @@ func (m *kqlMacroEngine) evaluateMacro(logger log.Logger, name string, defaultTi
from := m.timeRange.From.UnixNano()
// default to "100 datapoints" if nothing in the query is more specific
defaultInterval := time.Duration((to - from) / 60)
model, err := simplejson.NewJson(m.query.JSON)
var queryInterval interval
err := json.Unmarshal(m.query.JSON, &queryInterval)
if err != nil {
logger.Warn("Unable to parse model from query", "JSON", m.query.JSON)
it = defaultInterval
} else {
it, err = interval.GetIntervalFrom(&datasources.DataSource{
JsonData: simplejson.NewFromAny(dsInfo.JSONData),
}, model, defaultInterval)
var (
dsInterval string
ok bool
)
if dsInterval, ok = dsInfo.JSONData["interval"].(string); !ok {
dsInterval = ""
}
it, err = intervalv2.GetIntervalFrom(dsInterval, queryInterval.Interval, queryInterval.IntervalMs, defaultInterval)
if err != nil {
logger.Warn("Unable to get interval from query", "model", model)
logger.Warn("Unable to get interval from query", "model", queryInterval)
it = defaultInterval
}
}

@ -19,7 +19,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/testdata"
azTime "github.com/grafana/grafana/pkg/tsdb/azuremonitor/time"
@ -326,7 +325,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
azureMonitorQuery.URL = "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics"
}
if diff := cmp.Diff(azureMonitorQuery, queries[0], cmpopts.IgnoreUnexported(simplejson.Json{}), cmpopts.IgnoreFields(types.AzureMonitorQuery{}, "Params", "Dimensions")); diff != "" {
if diff := cmp.Diff(azureMonitorQuery, queries[0], cmpopts.IgnoreUnexported(struct{}{}), cmpopts.IgnoreFields(types.AzureMonitorQuery{}, "Params", "Dimensions")); diff != "" {
t.Errorf("Result mismatch (-want +got):\n%s", diff)
}
@ -353,7 +352,7 @@ func TestCustomNamespace(t *testing.T) {
{
JSON: []byte(`{
"azureMonitor": {
"customNamespace": "custom/namespace"
"customNamespace": "custom/namespace"
}
}`),
},

@ -5,7 +5,6 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
)
@ -54,7 +53,7 @@ func TestDimensionFiltersMigration(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
filters := MigrateDimensionFilters(tt.dimensionFilters)
if diff := cmp.Diff(tt.expectedDimensionFilters, filters, cmpopts.IgnoreUnexported(simplejson.Json{})); diff != "" {
if diff := cmp.Diff(tt.expectedDimensionFilters, filters, cmpopts.IgnoreUnexported(struct{}{})); diff != "" {
t.Errorf("Result mismatch (-want +got):\n%s", diff)
}
})

@ -15,7 +15,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data"
"go.opentelemetry.io/otel/attribute"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/kinds/dataquery"
@ -139,15 +138,15 @@ func (e *AzureResourceGraphDatasource) executeQuery(ctx context.Context, logger
dataResponse.Frames = frames
return dataResponse
}
model, err := simplejson.NewJson(query.JSON)
var model dataquery.AzureMonitorQuery
err := json.Unmarshal(query.JSON, &model)
if err != nil {
dataResponse.Error = err
return dataResponse
}
reqBody, err := json.Marshal(map[string]interface{}{
"subscriptions": model.Get("subscriptions").MustStringArray(),
"subscriptions": model.Subscriptions,
"query": query.InterpolatedQuery,
"options": map[string]string{"resultFormat": "table"},
})

@ -17,7 +17,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/loganalytics"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
@ -77,7 +76,7 @@ func TestBuildingAzureResourceGraphQueries(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
queries, err := datasource.buildQueries(logger, tt.queryModel, types.DatasourceInfo{})
tt.Err(t, err)
if diff := cmp.Diff(tt.azureResourceGraphQueries, queries, cmpopts.IgnoreUnexported(simplejson.Json{})); diff != "" {
if diff := cmp.Diff(tt.azureResourceGraphQueries, queries, cmpopts.IgnoreUnexported(struct{}{})); diff != "" {
t.Errorf("Result mismatch (-want +got):\n%s", diff)
}
})

@ -30,12 +30,24 @@ type AzRoute struct {
Headers map[string]string
}
type AzureSettings struct {
AzureMonitorSettings
AzureClientSettings
}
type AzureMonitorSettings struct {
SubscriptionId string `json:"subscriptionId"`
LogAnalyticsDefaultWorkspace string `json:"logAnalyticsDefaultWorkspace"`
AppInsightsAppId string `json:"appInsightsAppId"`
}
type AzureClientSettings struct {
AzureAuthType string
CloudName string
TenantId string
ClientId string
}
// AzureMonitorCustomizedCloudSettings is the extended Azure Monitor settings for customized cloud
type AzureMonitorCustomizedCloudSettings struct {
CustomizedRoutes map[string]AzRoute `json:"customizedRoutes"`

Loading…
Cancel
Save