Skip to content

Commit 2616366

Browse files
authored
Prometheus: Reintroduce Azure audience override feature flag (grafana#90339)
* Re-add feature flag with deprecation note * Hide the field in frontend if ff disabled * Block scope overriding if ff is disabled in backend - Update promlib to forward logger to extendOptions - Add warning - Update tests * Default toggle to true for now * Update description * Update prom tests * Fix lint
1 parent 7839903 commit 2616366

File tree

13 files changed

+131
-37
lines changed

13 files changed

+131
-37
lines changed

packages/grafana-data/src/types/featureToggles.gen.ts

+1
Original file line numberDiff line numberDiff line change
@@ -199,4 +199,5 @@ export interface FeatureToggles {
199199
cloudWatchRoundUpEndTime?: boolean;
200200
bodyScrolling?: boolean;
201201
cloudwatchMetricInsightsCrossAccount?: boolean;
202+
prometheusAzureOverrideAudience?: boolean;
202203
}

pkg/promlib/heuristics_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/grafana/grafana-plugin-sdk-go/backend"
1515
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
1616
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
17+
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
1718
)
1819

1920
type heuristicsSuccessRoundTripper struct {
@@ -41,7 +42,7 @@ func newHeuristicsSDKProvider(hrt heuristicsSuccessRoundTripper) *sdkhttpclient.
4142
return sdkhttpclient.NewProvider(sdkhttpclient.ProviderOptions{Middlewares: []sdkhttpclient.Middleware{mid}})
4243
}
4344

44-
func mockExtendClientOpts(ctx context.Context, settings backend.DataSourceInstanceSettings, clientOpts *sdkhttpclient.Options) error {
45+
func mockExtendClientOpts(ctx context.Context, settings backend.DataSourceInstanceSettings, clientOpts *sdkhttpclient.Options, log log.Logger) error {
4546
return nil
4647
}
4748

pkg/promlib/library.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ type instance struct {
3232
versionCache *cache.Cache
3333
}
3434

35-
type ExtendOptions func(ctx context.Context, settings backend.DataSourceInstanceSettings, clientOpts *sdkhttpclient.Options) error
35+
type ExtendOptions func(ctx context.Context, settings backend.DataSourceInstanceSettings, clientOpts *sdkhttpclient.Options, log log.Logger) error
3636

3737
func NewService(httpClientProvider *sdkhttpclient.Provider, plog log.Logger, extendOptions ExtendOptions) *Service {
3838
if httpClientProvider == nil {
@@ -53,7 +53,7 @@ func newInstanceSettings(httpClientProvider *sdkhttpclient.Provider, log log.Log
5353
}
5454

5555
if extendOptions != nil {
56-
err = extendOptions(ctx, settings, opts)
56+
err = extendOptions(ctx, settings, opts, log)
5757
if err != nil {
5858
return nil, fmt.Errorf("error extending transport options: %v", err)
5959
}

pkg/promlib/library_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/grafana/grafana-plugin-sdk-go/backend"
1212
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
13+
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
1314
"github.com/stretchr/testify/require"
1415
)
1516

@@ -60,7 +61,7 @@ func getMockPromTestSDKProvider(f *fakeHTTPClientProvider) *sdkhttpclient.Provid
6061
return sdkhttpclient.NewProvider(sdkhttpclient.ProviderOptions{Middlewares: []sdkhttpclient.Middleware{mid}})
6162
}
6263

63-
func mockExtendTransportOptions(ctx context.Context, settings backend.DataSourceInstanceSettings, clientOpts *sdkhttpclient.Options) error {
64+
func mockExtendTransportOptions(ctx context.Context, settings backend.DataSourceInstanceSettings, clientOpts *sdkhttpclient.Options, log log.Logger) error {
6465
return nil
6566
}
6667

@@ -103,7 +104,7 @@ func TestService(t *testing.T) {
103104
t.Run("extendOptions function provided", func(t *testing.T) {
104105
f := &fakeHTTPClientProvider{}
105106
httpProvider := getMockPromTestSDKProvider(f)
106-
service := NewService(httpProvider, backend.NewLoggerWith("logger", "test"), func(ctx context.Context, settings backend.DataSourceInstanceSettings, clientOpts *sdkhttpclient.Options) error {
107+
service := NewService(httpProvider, backend.NewLoggerWith("logger", "test"), func(ctx context.Context, settings backend.DataSourceInstanceSettings, clientOpts *sdkhttpclient.Options, log log.Logger) error {
107108
fmt.Println(ctx, settings, clientOpts)
108109
require.NotNil(t, ctx)
109110
require.NotNil(t, settings)

pkg/services/featuremgmt/registry.go

+7
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,13 @@ var (
13661366
Owner: awsDatasourcesSquad,
13671367
FrontendOnly: true,
13681368
},
1369+
{
1370+
Name: "prometheusAzureOverrideAudience",
1371+
Description: "Deprecated. Allow override default AAD audience for Azure Prometheus endpoint. Enabled by default. This feature should no longer be used and will be removed in the future.",
1372+
Stage: FeatureStageDeprecated,
1373+
Owner: grafanaPartnerPluginsSquad,
1374+
Expression: "true", // Enabled by default for now
1375+
},
13691376
}
13701377
)
13711378

pkg/services/featuremgmt/toggles_gen.csv

+1
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,4 @@ dashboardRestoreUI,experimental,@grafana/grafana-frontend-platform,false,false,f
180180
cloudWatchRoundUpEndTime,GA,@grafana/aws-datasources,false,false,false
181181
bodyScrolling,experimental,@grafana/grafana-frontend-platform,false,false,true
182182
cloudwatchMetricInsightsCrossAccount,experimental,@grafana/aws-datasources,false,false,true
183+
prometheusAzureOverrideAudience,deprecated,@grafana/partner-datasources,false,false,false

pkg/services/featuremgmt/toggles_gen.go

+4
Original file line numberDiff line numberDiff line change
@@ -730,4 +730,8 @@ const (
730730
// FlagCloudwatchMetricInsightsCrossAccount
731731
// Enables cross account observability for Cloudwatch Metric Insights
732732
FlagCloudwatchMetricInsightsCrossAccount = "cloudwatchMetricInsightsCrossAccount"
733+
734+
// FlagPrometheusAzureOverrideAudience
735+
// Deprecated. Allow override default AAD audience for Azure Prometheus endpoint. Enabled by default. This feature should no longer be used and will be removed in the future.
736+
FlagPrometheusAzureOverrideAudience = "prometheusAzureOverrideAudience"
733737
)

pkg/services/featuremgmt/toggles_gen.json

+17
Original file line numberDiff line numberDiff line change
@@ -2019,6 +2019,23 @@
20192019
"codeowner": "@grafana/observability-metrics"
20202020
}
20212021
},
2022+
{
2023+
"metadata": {
2024+
"name": "prometheusAzureOverrideAudience",
2025+
"resourceVersion": "1721046541163",
2026+
"creationTimestamp": "2022-05-30T15:43:32Z",
2027+
"deletionTimestamp": "2023-07-16T21:30:14Z",
2028+
"annotations": {
2029+
"grafana.app/updatedTimestamp": "2024-07-15 12:29:01.163772 +0000 UTC"
2030+
}
2031+
},
2032+
"spec": {
2033+
"description": "Deprecated. Allow override default AAD audience for Azure Prometheus endpoint. Enabled by default. This feature should no longer be used and will be removed in the future.",
2034+
"stage": "deprecated",
2035+
"codeowner": "@grafana/partner-datasources",
2036+
"expression": "true"
2037+
}
2038+
},
20222039
{
20232040
"metadata": {
20242041
"name": "prometheusCodeModeMetricNamesSearch",

pkg/tsdb/prometheus/azureauth/azure.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ import (
1010
"github.com/grafana/grafana-azure-sdk-go/v2/azsettings"
1111
"github.com/grafana/grafana-plugin-sdk-go/backend"
1212
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
13+
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
1314
"github.com/grafana/grafana-plugin-sdk-go/data/utils/maputil"
1415

1516
"github.com/grafana/grafana/pkg/promlib/utils"
1617
)
1718

18-
func ConfigureAzureAuthentication(settings backend.DataSourceInstanceSettings, azureSettings *azsettings.AzureSettings, clientOpts *sdkhttpclient.Options) error {
19+
func ConfigureAzureAuthentication(settings backend.DataSourceInstanceSettings, azureSettings *azsettings.AzureSettings, clientOpts *sdkhttpclient.Options, audienceOverride bool, log log.Logger) error {
1920
jsonData, err := utils.GetJsonData(settings)
2021
if err != nil {
2122
return fmt.Errorf("failed to get jsonData: %w", err)
@@ -29,7 +30,7 @@ func ConfigureAzureAuthentication(settings backend.DataSourceInstanceSettings, a
2930
if credentials != nil {
3031
var scopes []string
3132

32-
if scopes, err = getOverriddenScopes(jsonData); err != nil {
33+
if scopes, err = getOverriddenScopes(jsonData, audienceOverride, log); err != nil {
3334
return err
3435
}
3536

@@ -47,7 +48,7 @@ func ConfigureAzureAuthentication(settings backend.DataSourceInstanceSettings, a
4748
return nil
4849
}
4950

50-
func getOverriddenScopes(jsonData map[string]any) ([]string, error) {
51+
func getOverriddenScopes(jsonData map[string]any, audienceOverride bool, log log.Logger) ([]string, error) {
5152
resourceIdStr, err := maputil.GetStringOptional(jsonData, "azureEndpointResourceId")
5253
if err != nil {
5354
err = fmt.Errorf("overridden resource ID (audience) invalid")
@@ -56,6 +57,11 @@ func getOverriddenScopes(jsonData map[string]any) ([]string, error) {
5657
return nil, nil
5758
}
5859

60+
if !audienceOverride {
61+
log.Warn("Specifying an audience override requires the prometheusAzureOverrideAudience feature toggle to be enabled. This functionality is deprecated and will be removed in a future release.")
62+
return nil, nil
63+
}
64+
5965
resourceId, err := url.Parse(resourceIdStr)
6066
if err != nil || resourceId.Scheme == "" || resourceId.Host == "" {
6167
err = fmt.Errorf("overridden endpoint resource ID (audience) '%s' invalid", resourceIdStr)

pkg/tsdb/prometheus/azureauth/azure_test.go

+54-6
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,39 @@
11
package azureauth
22

33
import (
4+
"bytes"
5+
"context"
46
"testing"
57

68
"github.com/grafana/grafana-azure-sdk-go/v2/azcredentials"
79
"github.com/grafana/grafana-azure-sdk-go/v2/azsettings"
810
"github.com/grafana/grafana-plugin-sdk-go/backend"
911
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
12+
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
13+
"github.com/hashicorp/go-hclog"
1014
"github.com/stretchr/testify/assert"
1115
"github.com/stretchr/testify/require"
1216
)
1317

18+
type fakeLogger struct {
19+
hclog.Logger
20+
21+
level log.Level
22+
}
23+
24+
func (l fakeLogger) Level() log.Level {
25+
return l.level
26+
}
27+
func (l fakeLogger) FromContext(ctx context.Context) log.Logger {
28+
return fakeLogger{}
29+
}
30+
func (l fakeLogger) With(args ...interface{}) log.Logger {
31+
return fakeLogger{}
32+
}
33+
1434
func TestConfigureAzureAuthentication(t *testing.T) {
1535
azureSettings := &azsettings.AzureSettings{}
36+
testLogger := backend.Logger
1637

1738
t.Run("should set Azure middleware when JsonData contains valid credentials", func(t *testing.T) {
1839
settings := backend.DataSourceInstanceSettings{
@@ -26,7 +47,7 @@ func TestConfigureAzureAuthentication(t *testing.T) {
2647

2748
var opts = &sdkhttpclient.Options{CustomOptions: map[string]any{}}
2849

29-
err := ConfigureAzureAuthentication(settings, azureSettings, opts)
50+
err := ConfigureAzureAuthentication(settings, azureSettings, opts, false, testLogger)
3051
require.NoError(t, err)
3152

3253
require.NotNil(t, opts.Middlewares)
@@ -40,7 +61,7 @@ func TestConfigureAzureAuthentication(t *testing.T) {
4061

4162
var opts = &sdkhttpclient.Options{CustomOptions: map[string]any{}}
4263

43-
err := ConfigureAzureAuthentication(settings, azureSettings, opts)
64+
err := ConfigureAzureAuthentication(settings, azureSettings, opts, false, testLogger)
4465
require.NoError(t, err)
4566

4667
assert.NotContains(t, opts.CustomOptions, "_azureCredentials")
@@ -55,7 +76,7 @@ func TestConfigureAzureAuthentication(t *testing.T) {
5576
}
5677

5778
var opts = &sdkhttpclient.Options{CustomOptions: map[string]any{}}
58-
err := ConfigureAzureAuthentication(settings, azureSettings, opts)
79+
err := ConfigureAzureAuthentication(settings, azureSettings, opts, false, testLogger)
5980
assert.Error(t, err)
6081
})
6182

@@ -71,7 +92,7 @@ func TestConfigureAzureAuthentication(t *testing.T) {
7192
}
7293
var opts = &sdkhttpclient.Options{CustomOptions: map[string]any{}}
7394

74-
err := ConfigureAzureAuthentication(settings, azureSettings, opts)
95+
err := ConfigureAzureAuthentication(settings, azureSettings, opts, true, testLogger)
7596
require.NoError(t, err)
7697

7798
require.NotNil(t, opts.Middlewares)
@@ -87,7 +108,7 @@ func TestConfigureAzureAuthentication(t *testing.T) {
87108
}
88109
var opts = &sdkhttpclient.Options{CustomOptions: map[string]any{}}
89110

90-
err := ConfigureAzureAuthentication(settings, azureSettings, opts)
111+
err := ConfigureAzureAuthentication(settings, azureSettings, opts, true, testLogger)
91112
require.NoError(t, err)
92113

93114
if opts.Middlewares != nil {
@@ -108,9 +129,36 @@ func TestConfigureAzureAuthentication(t *testing.T) {
108129

109130
var opts = &sdkhttpclient.Options{CustomOptions: map[string]any{}}
110131

111-
err := ConfigureAzureAuthentication(settings, azureSettings, opts)
132+
err := ConfigureAzureAuthentication(settings, azureSettings, opts, true, testLogger)
112133
assert.Error(t, err)
113134
})
135+
t.Run("should warn if an audience is specified and the feature toggle is not enabled", func(t *testing.T) {
136+
settings := backend.DataSourceInstanceSettings{
137+
JSONData: []byte(`{
138+
"httpMethod": "POST",
139+
"azureCredentials": {
140+
"authType": "msi"
141+
},
142+
"azureEndpointResourceId": "https://api.example.com/abd5c4ce-ca73-41e9-9cb2-bed39aa2adb5"
143+
}`),
144+
}
145+
146+
var opts = &sdkhttpclient.Options{CustomOptions: map[string]any{}}
147+
var buf bytes.Buffer
148+
testLogger := hclog.New(&hclog.LoggerOptions{
149+
Name: "test",
150+
Output: &buf,
151+
})
152+
log := fakeLogger{
153+
Logger: testLogger,
154+
}
155+
156+
err := ConfigureAzureAuthentication(settings, azureSettings, opts, false, log)
157+
str := buf.String()
158+
t.Log(str)
159+
assert.NoError(t, err)
160+
assert.Contains(t, str, "Specifying an audience override requires the prometheusAzureOverrideAudience feature toggle to be enabled. This functionality is deprecated and will be removed in a future release.")
161+
})
114162
}
115163

116164
func TestGetPrometheusScopes(t *testing.T) {

pkg/tsdb/prometheus/prometheus.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/grafana/grafana-azure-sdk-go/v2/azsettings"
88
"github.com/grafana/grafana-plugin-sdk-go/backend"
99
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
10+
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
1011

1112
"github.com/grafana/grafana/pkg/promlib"
1213
"github.com/grafana/grafana/pkg/tsdb/prometheus/azureauth"
@@ -56,7 +57,7 @@ func (s *Service) ConvertObject(ctx context.Context, req *backend.ConversionRequ
5657
return s.lib.ConvertObject(ctx, req)
5758
}
5859

59-
func extendClientOpts(ctx context.Context, settings backend.DataSourceInstanceSettings, clientOpts *sdkhttpclient.Options) error {
60+
func extendClientOpts(ctx context.Context, settings backend.DataSourceInstanceSettings, clientOpts *sdkhttpclient.Options, plog log.Logger) error {
6061
// Set SigV4 service namespace
6162
if clientOpts.SigV4 != nil {
6263
clientOpts.SigV4.Service = "aps"
@@ -67,9 +68,11 @@ func extendClientOpts(ctx context.Context, settings backend.DataSourceInstanceSe
6768
return fmt.Errorf("failed to read Azure settings from Grafana: %v", err)
6869
}
6970

71+
audienceOverride := backend.GrafanaConfigFromContext(ctx).FeatureToggles().IsEnabled("prometheusAzureOverrideAudience")
72+
7073
// Set Azure authentication
7174
if azureSettings.AzureAuthEnabled {
72-
err = azureauth.ConfigureAzureAuthentication(settings, azureSettings, clientOpts)
75+
err = azureauth.ConfigureAzureAuthentication(settings, azureSettings, clientOpts, audienceOverride, plog)
7376
if err != nil {
7477
return fmt.Errorf("error configuring Azure auth: %v", err)
7578
}

pkg/tsdb/prometheus/prometheus_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestExtendClientOpts(t *testing.T) {
2828
}
2929
ctx := backend.WithGrafanaConfig(context.Background(), cfg)
3030
opts := &sdkhttpclient.Options{}
31-
err := extendClientOpts(ctx, settings, opts)
31+
err := extendClientOpts(ctx, settings, opts, backend.Logger)
3232
require.NoError(t, err)
3333
require.Equal(t, 1, len(opts.Middlewares))
3434
})
@@ -47,7 +47,7 @@ func TestExtendClientOpts(t *testing.T) {
4747
SecretKey: "secretkey",
4848
},
4949
}
50-
err := extendClientOpts(context.Background(), settings, opts)
50+
err := extendClientOpts(context.Background(), settings, opts, backend.Logger)
5151
require.NoError(t, err)
5252
require.Equal(t, "aps", opts.SigV4.Service)
5353
})

public/app/plugins/datasource/prometheus/configuration/AzureAuthSettings.tsx

+24-19
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { AzureCredentialsForm } from './AzureCredentialsForm';
1313
export const AzureAuthSettings = (props: HttpSettingsBaseProps) => {
1414
const { dataSourceConfig, onChange } = props;
1515

16+
const [overrideAudienceAllowed] = useState<boolean>(!!config.featureToggles.prometheusAzureOverrideAudience);
1617
const [overrideAudienceChecked, setOverrideAudienceChecked] = useState<boolean>(
1718
!!dataSourceConfig.jsonData.azureEndpointResourceId
1819
);
@@ -64,25 +65,29 @@ export const AzureAuthSettings = (props: HttpSettingsBaseProps) => {
6465
onCredentialsChange={onCredentialsChange}
6566
disabled={dataSourceConfig.readOnly}
6667
/>
67-
<h6>Azure configuration</h6>
68-
<div className="gf-form-group">
69-
<InlineFieldRow>
70-
<InlineField labelWidth={labelWidth} label="Override AAD audience" disabled={dataSourceConfig.readOnly}>
71-
<InlineSwitch value={overrideAudienceChecked} onChange={onOverrideAudienceChange} />
72-
</InlineField>
73-
</InlineFieldRow>
74-
{overrideAudienceChecked && (
75-
<InlineFieldRow>
76-
<InlineField labelWidth={labelWidth} label="Resource ID" disabled={dataSourceConfig.readOnly}>
77-
<Input
78-
className={cx(prometheusConfigOverhaulAuth ? 'width-20' : 'width-30')}
79-
value={dataSourceConfig.jsonData.azureEndpointResourceId || ''}
80-
onChange={onResourceIdChange}
81-
/>
82-
</InlineField>
83-
</InlineFieldRow>
84-
)}
85-
</div>
68+
{overrideAudienceAllowed && (
69+
<>
70+
<h6>Azure configuration</h6>
71+
<div className="gf-form-group">
72+
<InlineFieldRow>
73+
<InlineField labelWidth={labelWidth} label="Override AAD audience" disabled={dataSourceConfig.readOnly}>
74+
<InlineSwitch value={overrideAudienceChecked} onChange={onOverrideAudienceChange} />
75+
</InlineField>
76+
</InlineFieldRow>
77+
{overrideAudienceChecked && (
78+
<InlineFieldRow>
79+
<InlineField labelWidth={labelWidth} label="Resource ID" disabled={dataSourceConfig.readOnly}>
80+
<Input
81+
className={cx(prometheusConfigOverhaulAuth ? 'width-20' : 'width-30')}
82+
value={dataSourceConfig.jsonData.azureEndpointResourceId || ''}
83+
onChange={onResourceIdChange}
84+
/>
85+
</InlineField>
86+
</InlineFieldRow>
87+
)}
88+
</div>
89+
</>
90+
)}
8691
</>
8792
);
8893
};

0 commit comments

Comments
 (0)