Prometheus: Fix Azure authentication support (#44407)

Re-adding back Azure authentication support to Prometheus datasource 
after the datasource query logic was rewritten from plugin.json routes to 
Go backend.

Ref #35857
This commit is contained in:
Sergey Kostrukov 2022-02-03 08:06:31 -08:00 committed by GitHub
parent 6d931226d8
commit 85ea1a5d64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 127 additions and 12 deletions

View File

@ -4,8 +4,8 @@ import (
"strings"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/tsdb/prometheus/middleware"
"github.com/grafana/grafana/pkg/util/maputil"
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana/pkg/infra/httpclient"
@ -16,30 +16,28 @@ import (
type Provider struct {
settings backend.DataSourceInstanceSettings
jsonData JsonData
jsonData map[string]interface{}
httpMethod string
clientProvider httpclient.Provider
log log.Logger
}
func NewProvider(
settings backend.DataSourceInstanceSettings,
jsonData JsonData,
jsonData map[string]interface{},
clientProvider httpclient.Provider,
log log.Logger,
) *Provider {
httpMethod, _ := maputil.GetStringOptional(jsonData, "httpMethod")
return &Provider{
settings: settings,
jsonData: jsonData,
httpMethod: httpMethod,
clientProvider: clientProvider,
log: log,
}
}
type JsonData struct {
Method string `json:"httpMethod"`
TimeInterval string `json:"timeInterval"`
}
func (p *Provider) GetClient(headers map[string]string) (apiv1.API, error) {
opts, err := p.settings.HTTPClientOptions()
if err != nil {
@ -54,6 +52,12 @@ func (p *Provider) GetClient(headers map[string]string) (apiv1.API, error) {
opts.SigV4.Service = "aps"
}
// Azure authentication
err = p.configureAzureAuthentication(opts)
if err != nil {
return nil, err
}
roundTripper, err := p.clientProvider.GetTransport(opts)
if err != nil {
return nil, err
@ -77,7 +81,7 @@ func (p *Provider) middlewares() []sdkhttpclient.Middleware {
middleware.CustomQueryParameters(p.log),
sdkhttpclient.CustomHeadersMiddleware(),
}
if strings.ToLower(p.jsonData.Method) == "get" {
if strings.ToLower(p.httpMethod) == "get" {
middlewares = append(middlewares, middleware.ForceHttpGet(p.log))
}

View File

@ -0,0 +1,32 @@
package promclient
import (
"fmt"
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials"
"github.com/grafana/grafana/pkg/util/maputil"
)
func (p *Provider) configureAzureAuthentication(opts sdkhttpclient.Options) error {
credentials, err := azcredentials.FromDatasourceData(p.jsonData, p.settings.DecryptedSecureJSONData)
if err != nil {
err = fmt.Errorf("invalid Azure credentials: %s", err)
return err
}
if credentials != nil {
opts.CustomOptions["_azureCredentials"] = credentials
resourceId, err := maputil.GetStringOptional(p.jsonData, "azureEndpointResourceId")
if err != nil {
return err
}
if resourceId != "" {
opts.CustomOptions["azureEndpointResourceId"] = resourceId
}
}
return nil
}

View File

@ -135,7 +135,7 @@ func setup(jsonData ...string) *testContext {
rawData = []byte(jsonData[0])
}
var jd promclient.JsonData
var jd map[string]interface{}
_ = json.Unmarshal(rawData, &jd)
settings := backend.DataSourceInstanceSettings{URL: "test-url", JSONData: rawData}

View File

@ -16,6 +16,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
"github.com/grafana/grafana/pkg/util/maputil"
apiv1 "github.com/prometheus/client_golang/api/prometheus/v1"
)
@ -42,7 +43,7 @@ func ProvideService(httpClientProvider httpclient.Provider, tracer tracing.Trace
func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
var jsonData promclient.JsonData
var jsonData map[string]interface{}
err := json.Unmarshal(settings.JSONData, &jsonData)
if err != nil {
return nil, fmt.Errorf("error reading settings: %w", err)
@ -54,10 +55,15 @@ func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.Inst
return nil, err
}
timeInterval, err := maputil.GetStringOptional(jsonData, "timeInterval")
if err != nil {
return nil, err
}
mdl := DatasourceInfo{
ID: settings.ID,
URL: settings.URL,
TimeInterval: jsonData.TimeInterval,
TimeInterval: timeInterval,
getClient: pc.GetClient,
}

View File

@ -0,0 +1,73 @@
package maputil
import "fmt"
func GetMap(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 {
err := fmt.Errorf("the field '%s' should be set", key)
return nil, err
}
}
func GetBool(obj map[string]interface{}, key string) (bool, error) {
if untypedValue, ok := obj[key]; ok {
if value, ok := untypedValue.(bool); ok {
return value, nil
} else {
err := fmt.Errorf("the field '%s' should be a bool", key)
return false, err
}
} else {
err := fmt.Errorf("the field '%s' should be set", key)
return false, err
}
}
func GetBoolOptional(obj map[string]interface{}, key string) (bool, error) {
if untypedValue, ok := obj[key]; ok {
if value, ok := untypedValue.(bool); ok {
return value, nil
} else {
err := fmt.Errorf("the field '%s' should be a bool", key)
return false, err
}
} else {
// Value optional, not error
return false, nil
}
}
func GetString(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
}
}
func GetStringOptional(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 {
// Value optional, not error
return "", nil
}
}