diff --git a/go.mod b/go.mod index 8795ba6f163..8a948df1eeb 100644 --- a/go.mod +++ b/go.mod @@ -17,8 +17,6 @@ require ( cloud.google.com/go/storage v1.18.2 cuelang.org/go v0.4.0 github.com/Azure/azure-sdk-for-go v59.3.0+incompatible - github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0 - github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.10.0 github.com/Azure/go-autorest/autorest v0.11.22 github.com/BurntSushi/toml v0.3.1 github.com/Masterminds/semver v1.5.0 @@ -54,6 +52,7 @@ require ( github.com/gosimple/slug v1.9.0 github.com/grafana/cuetsy v0.0.0-20211119211437-8c25464cc9bf github.com/grafana/grafana-aws-sdk v0.10.1 + github.com/grafana/grafana-azure-sdk-go v1.0.0 github.com/grafana/grafana-plugin-sdk-go v0.129.0 github.com/grafana/loki v1.6.2-0.20211015002020-7832783b1caa github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 @@ -183,7 +182,7 @@ require ( github.com/gomodule/redigo v2.0.0+incompatible // indirect github.com/google/btree v1.0.1 // indirect github.com/google/flatbuffers v2.0.0+incompatible // indirect - github.com/googleapis/gax-go/v2 v2.1.1 + github.com/googleapis/gax-go/v2 v2.1.1 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/grafana/grafana-google-sdk-go v0.0.0-20211104130251-b190293eaf58 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect @@ -247,19 +246,20 @@ require ( golang.org/x/text v0.3.7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 + google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 // indirect gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect ) require ( cloud.google.com/go/kms v1.1.0 - github.com/Azure/go-autorest/autorest/adal v0.9.17 github.com/golang-migrate/migrate/v4 v4.7.0 - github.com/grafana/dskit v0.0.0-20211011144203-3a88ec0b675f gocloud.dev v0.24.0 ) require ( + github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.10.0 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.17 // indirect github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect github.com/chromedp/cdproto v0.0.0-20220208224320-6efb837e6bc2 // indirect github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect @@ -270,6 +270,7 @@ require ( github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect github.com/getkin/kin-openapi v0.91.0 // indirect github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 // indirect + github.com/grafana/dskit v0.0.0-20211011144203-3a88ec0b675f // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/klauspost/compress v1.13.6 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect diff --git a/go.sum b/go.sum index 792b3aa4a50..26accc85fd1 100644 --- a/go.sum +++ b/go.sum @@ -1335,6 +1335,8 @@ github.com/grafana/go-mssqldb v0.0.0-20210326084033-d0ce3c521036 h1:GplhUk6Xes5J github.com/grafana/go-mssqldb v0.0.0-20210326084033-d0ce3c521036/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/grafana/grafana-aws-sdk v0.10.1 h1:Ksguhjx6EuGLN/5Oc7oZoxuDReJ5RxIH99yqSMpLGUs= github.com/grafana/grafana-aws-sdk v0.10.1/go.mod h1:vFIOHEnY1u5nY0/tge1IHQjPuG6DRKr2ISf/HikUdjE= +github.com/grafana/grafana-azure-sdk-go v1.0.0 h1:RIVQyVb89/y/BnOVsVDcxiMtmWF8NmAX8ql0OJvzwNc= +github.com/grafana/grafana-azure-sdk-go v1.0.0/go.mod h1:xbzMaG74BN4rOP1NYEsCMNWkPbK7GfSU09PGYfQYm+g= github.com/grafana/grafana-google-sdk-go v0.0.0-20211104130251-b190293eaf58 h1:2ud7NNM7LrGPO4x0NFR8qLq68CqI4SmB7I2yRN2w9oE= github.com/grafana/grafana-google-sdk-go v0.0.0-20211104130251-b190293eaf58/go.mod h1:Vo2TKWfDVmNTELBUM+3lkrZvFtBws0qSZdXhQxRdJrE= github.com/grafana/grafana-plugin-sdk-go v0.94.0/go.mod h1:3VXz4nCv6wH5SfgB3mlW39s+c+LetqSCjFj7xxPC5+M= @@ -2462,8 +2464,6 @@ github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBn github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/vectordotdev/go-datemath v0.1.1-0.20220110192739-f9ce83ec349f h1:2upw/ZfjkCKpc4k6DXg7lMfCSLkfw/8epV5/y2ZUQ8U= -github.com/vectordotdev/go-datemath v0.1.1-0.20220110192739-f9ce83ec349f/go.mod h1:PnwzbSst7KD3vpBzzlntZU5gjVa455Uqa5QPiKSYJzQ= github.com/vectordotdev/go-datemath v0.1.1-0.20220323213446-f3954d0b18ae h1:oyiy3uBj1F4O3AaFh7hUGBrJjAssJhKyAbwxtkslxqo= github.com/vectordotdev/go-datemath v0.1.1-0.20220323213446-f3954d0b18ae/go.mod h1:PnwzbSst7KD3vpBzzlntZU5gjVa455Uqa5QPiKSYJzQ= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= diff --git a/pkg/api/pluginproxy/token_provider_azure.go b/pkg/api/pluginproxy/token_provider_azure.go index 15816788570..a0db3524c35 100644 --- a/pkg/api/pluginproxy/token_provider_azure.go +++ b/pkg/api/pluginproxy/token_provider_azure.go @@ -4,11 +4,12 @@ import ( "context" "strings" + "github.com/grafana/grafana-azure-sdk-go/azcredentials" + "github.com/grafana/grafana-azure-sdk-go/azsettings" + "github.com/grafana/grafana-azure-sdk-go/aztokenprovider" + "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/aztokenprovider" ) type azureAccessTokenProvider struct { diff --git a/pkg/plugins/config.go b/pkg/plugins/config.go index 203821d8a6f..66d74ac564d 100644 --- a/pkg/plugins/config.go +++ b/pkg/plugins/config.go @@ -1,8 +1,9 @@ package plugins import ( + "github.com/grafana/grafana-azure-sdk-go/azsettings" + "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" ) type Cfg struct { diff --git a/pkg/plugins/manager/manager_test.go b/pkg/plugins/manager/manager_test.go index 1061a66e632..b18609f6da9 100644 --- a/pkg/plugins/manager/manager_test.go +++ b/pkg/plugins/manager/manager_test.go @@ -7,8 +7,8 @@ import ( "testing" "time" + "github.com/grafana/grafana-azure-sdk-go/azsettings" "github.com/grafana/grafana-plugin-sdk-go/backend" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/plugins" diff --git a/pkg/services/datasources/service/datasource_service.go b/pkg/services/datasources/service/datasource_service.go index 17caf4808df..52ffe634707 100644 --- a/pkg/services/datasources/service/datasource_service.go +++ b/pkg/services/datasources/service/datasource_service.go @@ -12,6 +12,8 @@ import ( "sync" "time" + "github.com/grafana/grafana-azure-sdk-go/azcredentials" + "github.com/grafana/grafana-azure-sdk-go/azhttpclient" sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" "github.com/grafana/grafana/pkg/bus" @@ -24,8 +26,6 @@ import ( "github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azhttpclient" ) type Service struct { diff --git a/pkg/services/datasources/service/datasource_service_test.go b/pkg/services/datasources/service/datasource_service_test.go index dddb20ae754..72a85504867 100644 --- a/pkg/services/datasources/service/datasource_service_test.go +++ b/pkg/services/datasources/service/datasource_service_test.go @@ -8,7 +8,9 @@ import ( "testing" "time" + "github.com/grafana/grafana-azure-sdk-go/azsettings" sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" + "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/httpclient" @@ -22,7 +24,6 @@ import ( secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index b4111a0a061..6d5729b731c 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -20,8 +20,8 @@ import ( "time" "github.com/grafana/grafana-aws-sdk/pkg/awsds" + "github.com/grafana/grafana-azure-sdk-go/azsettings" "github.com/grafana/grafana-plugin-sdk-go/backend/gtime" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/util" diff --git a/pkg/setting/setting_azure.go b/pkg/setting/setting_azure.go index 2e226918b25..0a6d5cc4022 100644 --- a/pkg/setting/setting_azure.go +++ b/pkg/setting/setting_azure.go @@ -1,6 +1,6 @@ package setting -import "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" +import "github.com/grafana/grafana-azure-sdk-go/azsettings" func (cfg *Cfg) readAzureSettings() { azureSettings := &azsettings.AzureSettings{} diff --git a/pkg/setting/setting_azure_test.go b/pkg/setting/setting_azure_test.go index 0eada7af86e..b5fe304df49 100644 --- a/pkg/setting/setting_azure_test.go +++ b/pkg/setting/setting_azure_test.go @@ -3,7 +3,8 @@ package setting import ( "testing" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" + "github.com/grafana/grafana-azure-sdk-go/azsettings" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/tsdb/azuremonitor/azcredentials/builder.go b/pkg/tsdb/azuremonitor/azcredentials/builder.go deleted file mode 100644 index ee66d03fcea..00000000000 --- a/pkg/tsdb/azuremonitor/azcredentials/builder.go +++ /dev/null @@ -1,83 +0,0 @@ -package azcredentials - -import ( - "fmt" -) - -func FromDatasourceData(data map[string]interface{}, secureData map[string]string) (AzureCredentials, error) { - if credentialsObj, err := getMapOptional(data, "azureCredentials"); err != nil { - return nil, err - } else if credentialsObj == nil { - return nil, nil - } else { - return getFromCredentialsObject(credentialsObj, secureData) - } -} - -func getFromCredentialsObject(credentialsObj map[string]interface{}, secureData map[string]string) (AzureCredentials, error) { - authType, err := getStringValue(credentialsObj, "authType") - if err != nil { - return nil, err - } - - switch authType { - case AzureAuthManagedIdentity: - credentials := &AzureManagedIdentityCredentials{} - return credentials, nil - - case AzureAuthClientSecret: - cloud, err := getStringValue(credentialsObj, "azureCloud") - if err != nil { - return nil, err - } - tenantId, err := getStringValue(credentialsObj, "tenantId") - if err != nil { - return nil, err - } - clientId, err := getStringValue(credentialsObj, "clientId") - if err != nil { - return nil, err - } - clientSecret := secureData["azureClientSecret"] - - credentials := &AzureClientSecretCredentials{ - AzureCloud: cloud, - TenantId: tenantId, - ClientId: clientId, - ClientSecret: clientSecret, - } - return credentials, nil - - default: - err := fmt.Errorf("the authentication type '%s' not supported", authType) - return nil, err - } -} - -func getMapOptional(obj map[string]interface{}, key string) (map[string]interface{}, error) { - if untypedValue, ok := obj[key]; ok { - if value, ok := untypedValue.(map[string]interface{}); ok { - return value, nil - } else { - err := fmt.Errorf("the field '%s' should be an object", key) - return nil, err - } - } else { - // Value optional, not error - return nil, nil - } -} - -func getStringValue(obj map[string]interface{}, key string) (string, error) { - if untypedValue, ok := obj[key]; ok { - if value, ok := untypedValue.(string); ok { - return value, nil - } else { - err := fmt.Errorf("the field '%s' should be a string", key) - return "", err - } - } else { - err := fmt.Errorf("the field '%s' should be set", key) - return "", err - } -} diff --git a/pkg/tsdb/azuremonitor/azcredentials/credentials.go b/pkg/tsdb/azuremonitor/azcredentials/credentials.go deleted file mode 100644 index 49311e5c11a..00000000000 --- a/pkg/tsdb/azuremonitor/azcredentials/credentials.go +++ /dev/null @@ -1,30 +0,0 @@ -package azcredentials - -const ( - AzureAuthManagedIdentity = "msi" - AzureAuthClientSecret = "clientsecret" -) - -type AzureCredentials interface { - AzureAuthType() string -} - -type AzureManagedIdentityCredentials struct { - ClientId string -} - -type AzureClientSecretCredentials struct { - AzureCloud string - Authority string - TenantId string - ClientId string - ClientSecret string -} - -func (credentials *AzureManagedIdentityCredentials) AzureAuthType() string { - return AzureAuthManagedIdentity -} - -func (credentials *AzureClientSecretCredentials) AzureAuthType() string { - return AzureAuthClientSecret -} diff --git a/pkg/tsdb/azuremonitor/azhttpclient/middleware.go b/pkg/tsdb/azuremonitor/azhttpclient/middleware.go deleted file mode 100644 index 4bb1739decb..00000000000 --- a/pkg/tsdb/azuremonitor/azhttpclient/middleware.go +++ /dev/null @@ -1,41 +0,0 @@ -package azhttpclient - -import ( - "fmt" - "net/http" - - "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/aztokenprovider" -) - -const azureMiddlewareName = "AzureAuthentication" - -func AzureMiddleware(settings *azsettings.AzureSettings, credentials azcredentials.AzureCredentials, scopes []string) httpclient.Middleware { - return httpclient.NamedMiddlewareFunc(azureMiddlewareName, func(opts httpclient.Options, next http.RoundTripper) http.RoundTripper { - tokenProvider, err := aztokenprovider.NewAzureAccessTokenProvider(settings, credentials) - if err != nil { - return errorResponse(err) - } - - return ApplyAzureAuth(tokenProvider, scopes, next) - }) -} - -func ApplyAzureAuth(tokenProvider aztokenprovider.AzureTokenProvider, scopes []string, next http.RoundTripper) http.RoundTripper { - return httpclient.RoundTripperFunc(func(req *http.Request) (*http.Response, error) { - token, err := tokenProvider.GetAccessToken(req.Context(), scopes) - if err != nil { - return nil, fmt.Errorf("failed to retrieve Azure access token: %w", err) - } - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) - return next.RoundTrip(req) - }) -} - -func errorResponse(err error) http.RoundTripper { - return httpclient.RoundTripperFunc(func(req *http.Request) (*http.Response, error) { - return nil, fmt.Errorf("invalid Azure configuration: %s", err) - }) -} diff --git a/pkg/tsdb/azuremonitor/azhttpclient/options.go b/pkg/tsdb/azuremonitor/azhttpclient/options.go deleted file mode 100644 index 27838284fe3..00000000000 --- a/pkg/tsdb/azuremonitor/azhttpclient/options.go +++ /dev/null @@ -1,11 +0,0 @@ -package azhttpclient - -import ( - sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" -) - -func AddAzureAuthentication(opts *sdkhttpclient.Options, settings *azsettings.AzureSettings, credentials azcredentials.AzureCredentials, scopes []string) { - opts.Middlewares = append(opts.Middlewares, AzureMiddleware(settings, credentials, scopes)) -} diff --git a/pkg/tsdb/azuremonitor/azsettings/clouds.go b/pkg/tsdb/azuremonitor/azsettings/clouds.go deleted file mode 100644 index f1a798be7a4..00000000000 --- a/pkg/tsdb/azuremonitor/azsettings/clouds.go +++ /dev/null @@ -1,55 +0,0 @@ -package azsettings - -import "strings" - -const ( - AzurePublic = "AzureCloud" - AzureChina = "AzureChinaCloud" - AzureUSGovernment = "AzureUSGovernment" - AzureGermany = "AzureGermanCloud" -) - -func NormalizeAzureCloud(cloudName string) string { - switch strings.ToLower(cloudName) { - // Public - case "azurecloud": - fallthrough - case "azurepublic": - fallthrough - case "azurepubliccloud": - fallthrough - case "public": - return AzurePublic - - // China - case "azurechina": - fallthrough - case "azurechinacloud": - fallthrough - case "china": - return AzureChina - - // US Government - case "azureusgovernment": - fallthrough - case "azureusgovernmentcloud": - fallthrough - case "usgov": - fallthrough - case "usgovernment": - return AzureUSGovernment - - // Germany - case "azuregermancloud": - fallthrough - case "azuregermany": - fallthrough - case "german": - fallthrough - case "germany": - return AzureGermany - } - - // Pass the name unchanged if it's not known - return cloudName -} diff --git a/pkg/tsdb/azuremonitor/azsettings/settings.go b/pkg/tsdb/azuremonitor/azsettings/settings.go deleted file mode 100644 index a8d1b29c54e..00000000000 --- a/pkg/tsdb/azuremonitor/azsettings/settings.go +++ /dev/null @@ -1,7 +0,0 @@ -package azsettings - -type AzureSettings struct { - Cloud string - ManagedIdentityEnabled bool - ManagedIdentityClientId string -} diff --git a/pkg/tsdb/azuremonitor/aztokenprovider/token_cache.go b/pkg/tsdb/azuremonitor/aztokenprovider/token_cache.go deleted file mode 100644 index 3c375979e4d..00000000000 --- a/pkg/tsdb/azuremonitor/aztokenprovider/token_cache.go +++ /dev/null @@ -1,189 +0,0 @@ -package aztokenprovider - -import ( - "context" - "sort" - "strings" - "sync" - "sync/atomic" - "time" -) - -var ( - // timeNow makes it possible to test usage of time - timeNow = time.Now -) - -type AccessToken struct { - Token string - ExpiresOn time.Time -} - -type TokenRetriever interface { - GetCacheKey() string - Init() error - GetAccessToken(ctx context.Context, scopes []string) (*AccessToken, error) -} - -type ConcurrentTokenCache interface { - GetAccessToken(ctx context.Context, tokenRetriever TokenRetriever, scopes []string) (string, error) -} - -func NewConcurrentTokenCache() ConcurrentTokenCache { - return &tokenCacheImpl{} -} - -type tokenCacheImpl struct { - cache sync.Map // of *credentialCacheEntry -} -type credentialCacheEntry struct { - retriever TokenRetriever - - credInit uint32 - credMutex sync.Mutex - cache sync.Map // of *scopesCacheEntry -} - -type scopesCacheEntry struct { - retriever TokenRetriever - scopes []string - - cond *sync.Cond - refreshing bool - accessToken *AccessToken -} - -func (c *tokenCacheImpl) GetAccessToken(ctx context.Context, tokenRetriever TokenRetriever, scopes []string) (string, error) { - return c.getEntryFor(tokenRetriever).getAccessToken(ctx, scopes) -} - -func (c *tokenCacheImpl) getEntryFor(credential TokenRetriever) *credentialCacheEntry { - var entry interface{} - var ok bool - - key := credential.GetCacheKey() - - if entry, ok = c.cache.Load(key); !ok { - entry, _ = c.cache.LoadOrStore(key, &credentialCacheEntry{ - retriever: credential, - }) - } - - return entry.(*credentialCacheEntry) -} - -func (c *credentialCacheEntry) getAccessToken(ctx context.Context, scopes []string) (string, error) { - err := c.ensureInitialized() - if err != nil { - return "", err - } - - return c.getEntryFor(scopes).getAccessToken(ctx) -} - -func (c *credentialCacheEntry) ensureInitialized() error { - if atomic.LoadUint32(&c.credInit) == 0 { - c.credMutex.Lock() - defer c.credMutex.Unlock() - - if c.credInit == 0 { - // Initialize retriever - err := c.retriever.Init() - if err != nil { - return err - } - - atomic.StoreUint32(&c.credInit, 1) - } - } - - return nil -} - -func (c *credentialCacheEntry) getEntryFor(scopes []string) *scopesCacheEntry { - var entry interface{} - var ok bool - - key := getKeyForScopes(scopes) - - if entry, ok = c.cache.Load(key); !ok { - entry, _ = c.cache.LoadOrStore(key, &scopesCacheEntry{ - retriever: c.retriever, - scopes: scopes, - cond: sync.NewCond(&sync.Mutex{}), - }) - } - - return entry.(*scopesCacheEntry) -} - -func (c *scopesCacheEntry) getAccessToken(ctx context.Context) (string, error) { - var accessToken *AccessToken - var err error - shouldRefresh := false - - c.cond.L.Lock() - for { - if c.accessToken != nil && c.accessToken.ExpiresOn.After(timeNow().Add(2*time.Minute)) { - // Use the cached token since it's available and not expired yet - accessToken = c.accessToken - break - } - - if !c.refreshing { - // Start refreshing the token - c.refreshing = true - shouldRefresh = true - break - } - - // Wait for the token to be refreshed - c.cond.Wait() - } - c.cond.L.Unlock() - - if shouldRefresh { - accessToken, err = c.refreshAccessToken(ctx) - if err != nil { - return "", err - } - } - - return accessToken.Token, nil -} - -func (c *scopesCacheEntry) refreshAccessToken(ctx context.Context) (*AccessToken, error) { - var accessToken *AccessToken - - // Safeguarding from panic caused by retriever implementation - defer func() { - c.cond.L.Lock() - - c.refreshing = false - - if accessToken != nil { - c.accessToken = accessToken - } - - c.cond.Broadcast() - c.cond.L.Unlock() - }() - - token, err := c.retriever.GetAccessToken(ctx, c.scopes) - if err != nil { - return nil, err - } - accessToken = token - return accessToken, nil -} - -func getKeyForScopes(scopes []string) string { - if len(scopes) > 1 { - arr := make([]string, len(scopes)) - copy(arr, scopes) - sort.Strings(arr) - scopes = arr - } - - return strings.Join(scopes, " ") -} diff --git a/pkg/tsdb/azuremonitor/aztokenprovider/token_cache_test.go b/pkg/tsdb/azuremonitor/aztokenprovider/token_cache_test.go deleted file mode 100644 index 1d26d004c3f..00000000000 --- a/pkg/tsdb/azuremonitor/aztokenprovider/token_cache_test.go +++ /dev/null @@ -1,457 +0,0 @@ -package aztokenprovider - -import ( - "context" - "errors" - "fmt" - "sync" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -type fakeRetriever struct { - key string - initCalledTimes int - calledTimes int - initFunc func() error - getAccessTokenFunc func(ctx context.Context, scopes []string) (*AccessToken, error) -} - -func (c *fakeRetriever) GetCacheKey() string { - return c.key -} - -func (c *fakeRetriever) Reset() { - c.initCalledTimes = 0 - c.calledTimes = 0 -} - -func (c *fakeRetriever) Init() error { - c.initCalledTimes = c.initCalledTimes + 1 - if c.initFunc != nil { - return c.initFunc() - } - return nil -} - -func (c *fakeRetriever) GetAccessToken(ctx context.Context, scopes []string) (*AccessToken, error) { - c.calledTimes = c.calledTimes + 1 - if c.getAccessTokenFunc != nil { - return c.getAccessTokenFunc(ctx, scopes) - } - fakeAccessToken := &AccessToken{Token: fmt.Sprintf("%v-token-%v", c.key, c.calledTimes), ExpiresOn: timeNow().Add(time.Hour)} - return fakeAccessToken, nil -} - -func TestConcurrentTokenCache_GetAccessToken(t *testing.T) { - ctx := context.Background() - - scopes1 := []string{"Scope1"} - scopes2 := []string{"Scope2"} - - t.Run("should request access token from retriever", func(t *testing.T) { - cache := NewConcurrentTokenCache() - tokenRetriever := &fakeRetriever{key: "retriever"} - - token, err := cache.GetAccessToken(ctx, tokenRetriever, scopes1) - require.NoError(t, err) - assert.Equal(t, "retriever-token-1", token) - - assert.Equal(t, 1, tokenRetriever.calledTimes) - }) - - t.Run("should return cached token for same scopes", func(t *testing.T) { - var token1, token2 string - var err error - - cache := NewConcurrentTokenCache() - credential := &fakeRetriever{key: "credential-1"} - - token1, err = cache.GetAccessToken(ctx, credential, scopes1) - require.NoError(t, err) - assert.Equal(t, "credential-1-token-1", token1) - - token2, err = cache.GetAccessToken(ctx, credential, scopes2) - require.NoError(t, err) - assert.Equal(t, "credential-1-token-2", token2) - - token1, err = cache.GetAccessToken(ctx, credential, scopes1) - require.NoError(t, err) - assert.Equal(t, "credential-1-token-1", token1) - - token2, err = cache.GetAccessToken(ctx, credential, scopes2) - require.NoError(t, err) - assert.Equal(t, "credential-1-token-2", token2) - - assert.Equal(t, 2, credential.calledTimes) - }) - - t.Run("should return cached token for same credentials", func(t *testing.T) { - var token1, token2 string - var err error - - cache := NewConcurrentTokenCache() - credential1 := &fakeRetriever{key: "credential-1"} - credential2 := &fakeRetriever{key: "credential-2"} - - token1, err = cache.GetAccessToken(ctx, credential1, scopes1) - require.NoError(t, err) - assert.Equal(t, "credential-1-token-1", token1) - - token2, err = cache.GetAccessToken(ctx, credential2, scopes1) - require.NoError(t, err) - assert.Equal(t, "credential-2-token-1", token2) - - token1, err = cache.GetAccessToken(ctx, credential1, scopes1) - require.NoError(t, err) - assert.Equal(t, "credential-1-token-1", token1) - - token2, err = cache.GetAccessToken(ctx, credential2, scopes1) - require.NoError(t, err) - assert.Equal(t, "credential-2-token-1", token2) - - assert.Equal(t, 1, credential1.calledTimes) - assert.Equal(t, 1, credential2.calledTimes) - }) -} - -func TestCredentialCacheEntry_EnsureInitialized(t *testing.T) { - t.Run("when retriever init returns error", func(t *testing.T) { - tokenRetriever := &fakeRetriever{ - initFunc: func() error { - return errors.New("unable to initialize") - }, - } - - t.Run("should return error", func(t *testing.T) { - cacheEntry := &credentialCacheEntry{ - retriever: tokenRetriever, - } - - err := cacheEntry.ensureInitialized() - - assert.Error(t, err) - }) - - t.Run("should call init again each time and return error", func(t *testing.T) { - tokenRetriever.Reset() - - cacheEntry := &credentialCacheEntry{ - retriever: tokenRetriever, - } - - var err error - err = cacheEntry.ensureInitialized() - assert.Error(t, err) - - err = cacheEntry.ensureInitialized() - assert.Error(t, err) - - err = cacheEntry.ensureInitialized() - assert.Error(t, err) - - assert.Equal(t, 3, tokenRetriever.initCalledTimes) - }) - }) - - t.Run("when retriever init returns error only once", func(t *testing.T) { - var times = 0 - tokenRetriever := &fakeRetriever{ - initFunc: func() error { - times = times + 1 - if times == 1 { - return errors.New("unable to initialize") - } - return nil - }, - } - - t.Run("should call retriever init again only while it returns error", func(t *testing.T) { - cacheEntry := &credentialCacheEntry{ - retriever: tokenRetriever, - } - - var err error - err = cacheEntry.ensureInitialized() - assert.Error(t, err) - - err = cacheEntry.ensureInitialized() - assert.NoError(t, err) - - err = cacheEntry.ensureInitialized() - assert.NoError(t, err) - - assert.Equal(t, 2, tokenRetriever.initCalledTimes) - }) - }) - - t.Run("when retriever init panics", func(t *testing.T) { - tokenRetriever := &fakeRetriever{ - initFunc: func() error { - panic(errors.New("unable to initialize")) - }, - } - - t.Run("should call retriever init again each time", func(t *testing.T) { - tokenRetriever.Reset() - - cacheEntry := &credentialCacheEntry{ - retriever: tokenRetriever, - } - - func() { - defer func() { - assert.NotNil(t, recover(), "retriever expected to panic") - }() - _ = cacheEntry.ensureInitialized() - }() - - func() { - defer func() { - assert.NotNil(t, recover(), "retriever expected to panic") - }() - _ = cacheEntry.ensureInitialized() - }() - - func() { - defer func() { - assert.NotNil(t, recover(), "retriever expected to panic") - }() - _ = cacheEntry.ensureInitialized() - }() - - assert.Equal(t, 3, tokenRetriever.initCalledTimes) - }) - }) - - t.Run("when retriever init panics only once", func(t *testing.T) { - var times = 0 - tokenRetriever := &fakeRetriever{ - initFunc: func() error { - times = times + 1 - if times == 1 { - panic(errors.New("unable to initialize")) - } - return nil - }, - } - - t.Run("should call retriever init again only while it panics", func(t *testing.T) { - cacheEntry := &credentialCacheEntry{ - retriever: tokenRetriever, - } - - var err error - - func() { - defer func() { - assert.NotNil(t, recover(), "retriever expected to panic") - }() - _ = cacheEntry.ensureInitialized() - }() - - func() { - defer func() { - assert.Nil(t, recover(), "retriever not expected to panic") - }() - err = cacheEntry.ensureInitialized() - assert.NoError(t, err) - }() - - func() { - defer func() { - assert.Nil(t, recover(), "retriever not expected to panic") - }() - err = cacheEntry.ensureInitialized() - assert.NoError(t, err) - }() - - assert.Equal(t, 2, tokenRetriever.initCalledTimes) - }) - }) -} - -func TestScopesCacheEntry_GetAccessToken(t *testing.T) { - ctx := context.Background() - - scopes := []string{"Scope1"} - - t.Run("when retriever getAccessToken returns error", func(t *testing.T) { - tokenRetriever := &fakeRetriever{ - getAccessTokenFunc: func(ctx context.Context, scopes []string) (*AccessToken, error) { - invalidToken := &AccessToken{Token: "invalid_token", ExpiresOn: timeNow().Add(time.Hour)} - return invalidToken, errors.New("unable to get access token") - }, - } - - t.Run("should return error", func(t *testing.T) { - cacheEntry := &scopesCacheEntry{ - retriever: tokenRetriever, - scopes: scopes, - cond: sync.NewCond(&sync.Mutex{}), - } - - accessToken, err := cacheEntry.getAccessToken(ctx) - - assert.Error(t, err) - assert.Equal(t, "", accessToken) - }) - - t.Run("should call retriever again each time and return error", func(t *testing.T) { - tokenRetriever.Reset() - - cacheEntry := &scopesCacheEntry{ - retriever: tokenRetriever, - scopes: scopes, - cond: sync.NewCond(&sync.Mutex{}), - } - - var err error - _, err = cacheEntry.getAccessToken(ctx) - assert.Error(t, err) - - _, err = cacheEntry.getAccessToken(ctx) - assert.Error(t, err) - - _, err = cacheEntry.getAccessToken(ctx) - assert.Error(t, err) - - assert.Equal(t, 3, tokenRetriever.calledTimes) - }) - }) - - t.Run("when retriever getAccessToken returns error only once", func(t *testing.T) { - var times = 0 - retriever := &fakeRetriever{ - getAccessTokenFunc: func(ctx context.Context, scopes []string) (*AccessToken, error) { - times = times + 1 - if times == 1 { - invalidToken := &AccessToken{Token: "invalid_token", ExpiresOn: timeNow().Add(time.Hour)} - return invalidToken, errors.New("unable to get access token") - } - fakeAccessToken := &AccessToken{Token: fmt.Sprintf("token-%v", times), ExpiresOn: timeNow().Add(time.Hour)} - return fakeAccessToken, nil - }, - } - - t.Run("should call retriever again only while it returns error", func(t *testing.T) { - cacheEntry := &scopesCacheEntry{ - retriever: retriever, - scopes: scopes, - cond: sync.NewCond(&sync.Mutex{}), - } - - var accessToken string - var err error - - _, err = cacheEntry.getAccessToken(ctx) - assert.Error(t, err) - - accessToken, err = cacheEntry.getAccessToken(ctx) - assert.NoError(t, err) - assert.Equal(t, "token-2", accessToken) - - accessToken, err = cacheEntry.getAccessToken(ctx) - assert.NoError(t, err) - assert.Equal(t, "token-2", accessToken) - - assert.Equal(t, 2, retriever.calledTimes) - }) - }) - - t.Run("when retriever getAccessToken panics", func(t *testing.T) { - tokenRetriever := &fakeRetriever{ - getAccessTokenFunc: func(ctx context.Context, scopes []string) (*AccessToken, error) { - panic(errors.New("unable to get access token")) - }, - } - - t.Run("should call retriever again each time", func(t *testing.T) { - tokenRetriever.Reset() - - cacheEntry := &scopesCacheEntry{ - retriever: tokenRetriever, - scopes: scopes, - cond: sync.NewCond(&sync.Mutex{}), - } - - func() { - defer func() { - assert.NotNil(t, recover(), "retriever expected to panic") - }() - _, _ = cacheEntry.getAccessToken(ctx) - }() - - func() { - defer func() { - assert.NotNil(t, recover(), "retriever expected to panic") - }() - _, _ = cacheEntry.getAccessToken(ctx) - }() - - func() { - defer func() { - assert.NotNil(t, recover(), "retriever expected to panic") - }() - _, _ = cacheEntry.getAccessToken(ctx) - }() - - assert.Equal(t, 3, tokenRetriever.calledTimes) - }) - }) - - t.Run("when retriever getAccessToken panics only once", func(t *testing.T) { - var times = 0 - tokenRetriever := &fakeRetriever{ - getAccessTokenFunc: func(ctx context.Context, scopes []string) (*AccessToken, error) { - times = times + 1 - if times == 1 { - panic(errors.New("unable to get access token")) - } - fakeAccessToken := &AccessToken{Token: fmt.Sprintf("token-%v", times), ExpiresOn: timeNow().Add(time.Hour)} - return fakeAccessToken, nil - }, - } - - t.Run("should call retriever again only while it panics", func(t *testing.T) { - cacheEntry := &scopesCacheEntry{ - retriever: tokenRetriever, - scopes: scopes, - cond: sync.NewCond(&sync.Mutex{}), - } - - var accessToken string - var err error - - func() { - defer func() { - assert.NotNil(t, recover(), "retriever expected to panic") - }() - _, _ = cacheEntry.getAccessToken(ctx) - }() - - func() { - defer func() { - assert.Nil(t, recover(), "retriever not expected to panic") - }() - accessToken, err = cacheEntry.getAccessToken(ctx) - assert.NoError(t, err) - assert.Equal(t, "token-2", accessToken) - }() - - func() { - defer func() { - assert.Nil(t, recover(), "retriever not expected to panic") - }() - accessToken, err = cacheEntry.getAccessToken(ctx) - assert.NoError(t, err) - assert.Equal(t, "token-2", accessToken) - }() - - assert.Equal(t, 2, tokenRetriever.calledTimes) - }) - }) -} diff --git a/pkg/tsdb/azuremonitor/aztokenprovider/token_provider.go b/pkg/tsdb/azuremonitor/aztokenprovider/token_provider.go deleted file mode 100644 index 32074e6cb0a..00000000000 --- a/pkg/tsdb/azuremonitor/aztokenprovider/token_provider.go +++ /dev/null @@ -1,187 +0,0 @@ -package aztokenprovider - -import ( - "context" - "crypto/sha256" - "fmt" - - "github.com/Azure/azure-sdk-for-go/sdk/azcore" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" - "github.com/Azure/azure-sdk-for-go/sdk/azidentity" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" -) - -var ( - azureTokenCache = NewConcurrentTokenCache() -) - -type AzureTokenProvider interface { - GetAccessToken(ctx context.Context, scopes []string) (string, error) -} - -type tokenProviderImpl struct { - tokenRetriever TokenRetriever -} - -func NewAzureAccessTokenProvider(settings *azsettings.AzureSettings, credentials azcredentials.AzureCredentials) (AzureTokenProvider, error) { - if settings == nil { - err := fmt.Errorf("parameter 'settings' cannot be nil") - return nil, err - } - if credentials == nil { - err := fmt.Errorf("parameter 'credentials' cannot be nil") - return nil, err - } - - var tokenRetriever TokenRetriever - - switch c := credentials.(type) { - case *azcredentials.AzureManagedIdentityCredentials: - if !settings.ManagedIdentityEnabled { - err := fmt.Errorf("managed identity authentication is not enabled in Grafana config") - return nil, err - } else { - tokenRetriever = getManagedIdentityTokenRetriever(settings, c) - } - case *azcredentials.AzureClientSecretCredentials: - tokenRetriever = getClientSecretTokenRetriever(c) - default: - err := fmt.Errorf("credentials of type '%s' not supported by authentication provider", c.AzureAuthType()) - return nil, err - } - - tokenProvider := &tokenProviderImpl{ - tokenRetriever: tokenRetriever, - } - - return tokenProvider, nil -} - -func (provider *tokenProviderImpl) GetAccessToken(ctx context.Context, scopes []string) (string, error) { - if ctx == nil { - err := fmt.Errorf("parameter 'ctx' cannot be nil") - return "", err - } - if scopes == nil { - err := fmt.Errorf("parameter 'scopes' cannot be nil") - return "", err - } - - accessToken, err := azureTokenCache.GetAccessToken(ctx, provider.tokenRetriever, scopes) - if err != nil { - return "", err - } - return accessToken, nil -} - -func getManagedIdentityTokenRetriever(settings *azsettings.AzureSettings, credentials *azcredentials.AzureManagedIdentityCredentials) TokenRetriever { - var clientId string - if credentials.ClientId != "" { - clientId = credentials.ClientId - } else { - clientId = settings.ManagedIdentityClientId - } - return &managedIdentityTokenRetriever{ - clientId: clientId, - } -} - -func getClientSecretTokenRetriever(credentials *azcredentials.AzureClientSecretCredentials) TokenRetriever { - var authority string - if credentials.Authority != "" { - authority = credentials.Authority - } else { - authority = resolveAuthorityForCloud(credentials.AzureCloud) - } - return &clientSecretTokenRetriever{ - authority: authority, - tenantId: credentials.TenantId, - clientId: credentials.ClientId, - clientSecret: credentials.ClientSecret, - } -} - -func resolveAuthorityForCloud(cloudName string) string { - // Known Azure clouds - switch cloudName { - case azsettings.AzurePublic: - return azidentity.AzurePublicCloud - case azsettings.AzureChina: - return azidentity.AzureChina - case azsettings.AzureUSGovernment: - return azidentity.AzureGovernment - case azsettings.AzureGermany: - return azidentity.AzureGermany - default: - return "" - } -} - -type managedIdentityTokenRetriever struct { - clientId string - credential azcore.TokenCredential -} - -func (c *managedIdentityTokenRetriever) GetCacheKey() string { - clientId := c.clientId - if clientId == "" { - clientId = "system" - } - return fmt.Sprintf("azure|msi|%s", clientId) -} - -func (c *managedIdentityTokenRetriever) Init() error { - if credential, err := azidentity.NewManagedIdentityCredential(c.clientId, nil); err != nil { - return err - } else { - c.credential = credential - return nil - } -} - -func (c *managedIdentityTokenRetriever) GetAccessToken(ctx context.Context, scopes []string) (*AccessToken, error) { - accessToken, err := c.credential.GetToken(ctx, policy.TokenRequestOptions{Scopes: scopes}) - if err != nil { - return nil, err - } - - return &AccessToken{Token: accessToken.Token, ExpiresOn: accessToken.ExpiresOn}, nil -} - -type clientSecretTokenRetriever struct { - authority string - tenantId string - clientId string - clientSecret string - credential azcore.TokenCredential -} - -func (c *clientSecretTokenRetriever) GetCacheKey() string { - return fmt.Sprintf("azure|clientsecret|%s|%s|%s|%s", c.authority, c.tenantId, c.clientId, hashSecret(c.clientSecret)) -} - -func (c *clientSecretTokenRetriever) Init() error { - options := &azidentity.ClientSecretCredentialOptions{AuthorityHost: c.authority} - if credential, err := azidentity.NewClientSecretCredential(c.tenantId, c.clientId, c.clientSecret, options); err != nil { - return err - } else { - c.credential = credential - return nil - } -} - -func (c *clientSecretTokenRetriever) GetAccessToken(ctx context.Context, scopes []string) (*AccessToken, error) { - accessToken, err := c.credential.GetToken(ctx, policy.TokenRequestOptions{Scopes: scopes}) - if err != nil { - return nil, err - } - - return &AccessToken{Token: accessToken.Token, ExpiresOn: accessToken.ExpiresOn}, nil -} - -func hashSecret(secret string) string { - hash := sha256.New() - _, _ = hash.Write([]byte(secret)) - return fmt.Sprintf("%x", hash.Sum(nil)) -} diff --git a/pkg/tsdb/azuremonitor/aztokenprovider/token_provider_test.go b/pkg/tsdb/azuremonitor/aztokenprovider/token_provider_test.go deleted file mode 100644 index 790a3a6fcf9..00000000000 --- a/pkg/tsdb/azuremonitor/aztokenprovider/token_provider_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package aztokenprovider - -import ( - "context" - "testing" - - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -var getAccessTokenFunc func(credential TokenRetriever, scopes []string) - -type tokenCacheFake struct{} - -func (c *tokenCacheFake) GetAccessToken(_ context.Context, credential TokenRetriever, scopes []string) (string, error) { - getAccessTokenFunc(credential, scopes) - return "4cb83b87-0ffb-4abd-82f6-48a8c08afc53", nil -} - -func TestAzureTokenProvider_GetAccessToken(t *testing.T) { - ctx := context.Background() - - settings := &azsettings.AzureSettings{} - - scopes := []string{ - "https://management.azure.com/.default", - } - - original := azureTokenCache - azureTokenCache = &tokenCacheFake{} - t.Cleanup(func() { azureTokenCache = original }) - - t.Run("when managed identities enabled", func(t *testing.T) { - settings.ManagedIdentityEnabled = true - - t.Run("should resolve managed identity retriever if auth type is managed identity", func(t *testing.T) { - credentials := &azcredentials.AzureManagedIdentityCredentials{} - - provider, err := NewAzureAccessTokenProvider(settings, credentials) - require.NoError(t, err) - - getAccessTokenFunc = func(credential TokenRetriever, scopes []string) { - assert.IsType(t, &managedIdentityTokenRetriever{}, credential) - } - - _, err = provider.GetAccessToken(ctx, scopes) - require.NoError(t, err) - }) - - t.Run("should resolve client secret retriever if auth type is client secret", func(t *testing.T) { - credentials := &azcredentials.AzureClientSecretCredentials{} - - provider, err := NewAzureAccessTokenProvider(settings, credentials) - require.NoError(t, err) - - getAccessTokenFunc = func(credential TokenRetriever, scopes []string) { - assert.IsType(t, &clientSecretTokenRetriever{}, credential) - } - - _, err = provider.GetAccessToken(ctx, scopes) - require.NoError(t, err) - }) - }) - - t.Run("when managed identities disabled", func(t *testing.T) { - settings.ManagedIdentityEnabled = false - - t.Run("should return error if auth type is managed identity", func(t *testing.T) { - credentials := &azcredentials.AzureManagedIdentityCredentials{} - - _, err := NewAzureAccessTokenProvider(settings, credentials) - assert.Error(t, err, "managed identity authentication is not enabled in Grafana config") - }) - }) -} - -func TestAzureTokenProvider_getClientSecretCredential(t *testing.T) { - credentials := &azcredentials.AzureClientSecretCredentials{ - AzureCloud: azsettings.AzurePublic, - Authority: "", - TenantId: "7dcf1d1a-4ec0-41f2-ac29-c1538a698bc4", - ClientId: "1af7c188-e5b6-4f96-81b8-911761bdd459", - ClientSecret: "0416d95e-8af8-472c-aaa3-15c93c46080a", - } - - t.Run("should return clientSecretTokenRetriever with values", func(t *testing.T) { - result := getClientSecretTokenRetriever(credentials) - assert.IsType(t, &clientSecretTokenRetriever{}, result) - - credential := (result).(*clientSecretTokenRetriever) - - assert.Equal(t, "https://login.microsoftonline.com/", credential.authority) - assert.Equal(t, "7dcf1d1a-4ec0-41f2-ac29-c1538a698bc4", credential.tenantId) - assert.Equal(t, "1af7c188-e5b6-4f96-81b8-911761bdd459", credential.clientId) - assert.Equal(t, "0416d95e-8af8-472c-aaa3-15c93c46080a", credential.clientSecret) - }) - - t.Run("authority should selected based on cloud", func(t *testing.T) { - originalCloud := credentials.AzureCloud - defer func() { credentials.AzureCloud = originalCloud }() - - credentials.AzureCloud = azsettings.AzureChina - - result := getClientSecretTokenRetriever(credentials) - assert.IsType(t, &clientSecretTokenRetriever{}, result) - - credential := (result).(*clientSecretTokenRetriever) - - assert.Equal(t, "https://login.chinacloudapi.cn/", credential.authority) - }) - - t.Run("explicitly set authority should have priority over cloud", func(t *testing.T) { - originalCloud := credentials.AzureCloud - defer func() { credentials.AzureCloud = originalCloud }() - - credentials.AzureCloud = azsettings.AzureChina - credentials.Authority = "https://another.com/" - - result := getClientSecretTokenRetriever(credentials) - assert.IsType(t, &clientSecretTokenRetriever{}, result) - - credential := (result).(*clientSecretTokenRetriever) - - assert.Equal(t, "https://another.com/", credential.authority) - }) -} diff --git a/pkg/tsdb/azuremonitor/azuremonitor-resource-handler_test.go b/pkg/tsdb/azuremonitor/azuremonitor-resource-handler_test.go index 2158b31126e..61b71e480de 100644 --- a/pkg/tsdb/azuremonitor/azuremonitor-resource-handler_test.go +++ b/pkg/tsdb/azuremonitor/azuremonitor-resource-handler_test.go @@ -6,9 +6,11 @@ import ( "net/http/httptest" "testing" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" + "github.com/grafana/grafana-azure-sdk-go/azsettings" + "github.com/grafana/grafana/pkg/tsdb/azuremonitor/metrics" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/types" + "github.com/stretchr/testify/require" ) diff --git a/pkg/tsdb/azuremonitor/azuremonitor_test.go b/pkg/tsdb/azuremonitor/azuremonitor_test.go index e9af2b86b9e..0e5d1f99017 100644 --- a/pkg/tsdb/azuremonitor/azuremonitor_test.go +++ b/pkg/tsdb/azuremonitor/azuremonitor_test.go @@ -6,15 +6,17 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/grafana/grafana-azure-sdk-go/azcredentials" + "github.com/grafana/grafana-azure-sdk-go/azsettings" "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt" + "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/deprecated" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/types" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/tsdb/azuremonitor/credentials.go b/pkg/tsdb/azuremonitor/credentials.go index 6bf43efba5c..be155b764ee 100644 --- a/pkg/tsdb/azuremonitor/credentials.go +++ b/pkg/tsdb/azuremonitor/credentials.go @@ -3,10 +3,11 @@ package azuremonitor import ( "fmt" + "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/azcredentials" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" ) // Azure cloud names specific to Azure Monitor diff --git a/pkg/tsdb/azuremonitor/credentials_test.go b/pkg/tsdb/azuremonitor/credentials_test.go index 82926c0374a..35fb2ebfb9f 100644 --- a/pkg/tsdb/azuremonitor/credentials_test.go +++ b/pkg/tsdb/azuremonitor/credentials_test.go @@ -3,10 +3,11 @@ package azuremonitor import ( "testing" + "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/azcredentials" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/tsdb/azuremonitor/httpclient.go b/pkg/tsdb/azuremonitor/httpclient.go index 2c3655733b0..a8dc2ad377d 100644 --- a/pkg/tsdb/azuremonitor/httpclient.go +++ b/pkg/tsdb/azuremonitor/httpclient.go @@ -3,10 +3,11 @@ package azuremonitor import ( "net/http" + "github.com/grafana/grafana-azure-sdk-go/azhttpclient" sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" + "github.com/grafana/grafana/pkg/infra/httpclient" "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azhttpclient" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/deprecated" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/types" ) diff --git a/pkg/tsdb/azuremonitor/httpclient_test.go b/pkg/tsdb/azuremonitor/httpclient_test.go index f14015f843a..0867acd0144 100644 --- a/pkg/tsdb/azuremonitor/httpclient_test.go +++ b/pkg/tsdb/azuremonitor/httpclient_test.go @@ -5,10 +5,11 @@ import ( "net/http" "testing" + "github.com/grafana/grafana-azure-sdk-go/azcredentials" sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" + "github.com/grafana/grafana/pkg/infra/httpclient" "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/deprecated" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/types" "github.com/stretchr/testify/assert" diff --git a/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource.go b/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource.go index e7100d358a5..f99a837a6bc 100644 --- a/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource.go +++ b/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource.go @@ -11,13 +11,14 @@ import ( "path" "time" + "github.com/grafana/grafana-azure-sdk-go/azsettings" "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azlog" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/loganalytics" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/macros" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/types" diff --git a/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource_test.go b/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource_test.go index fcb54888e6d..ca397a7d80d 100644 --- a/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource_test.go +++ b/pkg/tsdb/azuremonitor/resourcegraph/azure-resource-graph-datasource_test.go @@ -10,10 +10,11 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + "github.com/grafana/grafana-azure-sdk-go/azsettings" "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana/pkg/components/simplejson" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/pkg/tsdb/azuremonitor/routes.go b/pkg/tsdb/azuremonitor/routes.go index ece4f5d91db..1a883826f5f 100644 --- a/pkg/tsdb/azuremonitor/routes.go +++ b/pkg/tsdb/azuremonitor/routes.go @@ -1,7 +1,8 @@ package azuremonitor import ( - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azsettings" + "github.com/grafana/grafana-azure-sdk-go/azsettings" + "github.com/grafana/grafana/pkg/tsdb/azuremonitor/deprecated" "github.com/grafana/grafana/pkg/tsdb/azuremonitor/types" ) diff --git a/pkg/tsdb/azuremonitor/types/types.go b/pkg/tsdb/azuremonitor/types/types.go index 4321516f375..f0d40823c7b 100644 --- a/pkg/tsdb/azuremonitor/types/types.go +++ b/pkg/tsdb/azuremonitor/types/types.go @@ -7,8 +7,8 @@ import ( "regexp" "time" + "github.com/grafana/grafana-azure-sdk-go/azcredentials" "github.com/grafana/grafana-plugin-sdk-go/backend" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials" ) const ( diff --git a/pkg/tsdb/prometheus/promclient/provider_azure.go b/pkg/tsdb/prometheus/promclient/provider_azure.go index 8d59bfec358..318867ef681 100644 --- a/pkg/tsdb/prometheus/promclient/provider_azure.go +++ b/pkg/tsdb/prometheus/promclient/provider_azure.go @@ -5,10 +5,11 @@ import ( "net/url" "path" + "github.com/grafana/grafana-azure-sdk-go/azcredentials" + "github.com/grafana/grafana-azure-sdk-go/azhttpclient" sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" + "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials" - "github.com/grafana/grafana/pkg/tsdb/azuremonitor/azhttpclient" "github.com/grafana/grafana/pkg/util/maputil" )