AzureMonitor: Remove support for different credentials for Azure Monitor Logs (#35121)

pull/35805/head
Andres Martinez Gotor 4 years ago committed by GitHub
parent abe35c8c01
commit b1a839825f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      public/app/plugins/datasource/grafana-azure-monitor-datasource/__mocks__/instanceSettings.ts
  2. 15
      public/app/plugins/datasource/grafana-azure-monitor-datasource/api/routes.ts
  3. 4
      public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/azure_log_analytics_datasource.test.ts
  4. 18
      public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/azure_log_analytics_datasource.ts
  5. 34
      public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AnalyticsConfig.test.tsx
  6. 96
      public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AnalyticsConfig.tsx
  7. 24
      public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AzureCredentialsForm.test.tsx
  8. 18
      public/app/plugins/datasource/grafana-azure-monitor-datasource/components/AzureCredentialsForm.tsx
  9. 6
      public/app/plugins/datasource/grafana-azure-monitor-datasource/components/ConfigEditor.tsx
  10. 7
      public/app/plugins/datasource/grafana-azure-monitor-datasource/components/InsightsConfig.tsx
  11. 330
      public/app/plugins/datasource/grafana-azure-monitor-datasource/components/__snapshots__/AnalyticsConfig.test.tsx.snap
  12. 36
      public/app/plugins/datasource/grafana-azure-monitor-datasource/components/__snapshots__/InsightsConfig.test.tsx.snap
  13. 117
      public/app/plugins/datasource/grafana-azure-monitor-datasource/credentials.ts
  14. 86
      public/app/plugins/datasource/grafana-azure-monitor-datasource/plugin.json
  15. 4
      public/app/plugins/datasource/grafana-azure-monitor-datasource/resourcePicker/resourcePickerData.ts
  16. 7
      public/app/plugins/datasource/grafana-azure-monitor-datasource/types/index.ts

@ -17,8 +17,5 @@ export const createMockInstanceSetttings = (): AzureDataSourceInstanceSettings =
tenantId: 'abc-123',
clientId: 'def-456',
subscriptionId: 'ghi-789',
// logs
azureLogAnalyticsSameAs: true,
},
});

@ -13,21 +13,6 @@ export function getManagementApiRoute(azureCloud: string): string {
}
}
export function getLogAnalyticsManagementApiRoute(azureCloud: string): string {
switch (azureCloud) {
case 'azuremonitor':
return 'workspacesloganalytics';
case 'chinaazuremonitor':
return 'chinaworkspacesloganalytics';
case 'govazuremonitor':
return 'govworkspacesloganalytics';
case 'germanyazuremonitor':
return 'germanyworkspacesloganalytics';
default:
throw new Error('The cloud not supported.');
}
}
export function getLogAnalyticsApiRoute(azureCloud: string): string {
switch (azureCloud) {
case 'azuremonitor':

@ -33,7 +33,7 @@ describe('AzureLogAnalyticsDatasource', () => {
beforeEach(() => {
ctx.instanceSettings = {
jsonData: { logAnalyticsSubscriptionId: 'xxx', azureLogAnalyticsSameAs: false },
jsonData: { subscriptionId: 'xxx' },
url: 'http://azureloganalyticsapi',
};
@ -93,7 +93,7 @@ describe('AzureLogAnalyticsDatasource', () => {
it('should use the loganalyticsazure plugin route', async () => {
await ctx.ds.metricFindQuery('workspace("aworkspace").AzureActivity | distinct Category');
expect(workspacesUrl).toContain('workspacesloganalytics');
expect(workspacesUrl).toContain('azuremonitor');
expect(azureLogAnalyticsUrl).toContain('loganalyticsazure');
});
});

@ -18,8 +18,8 @@ import {
import { getBackendSrv, getTemplateSrv, DataSourceWithBackend, FetchResponse } from '@grafana/runtime';
import { Observable, from } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
import { getAuthType, getAzureCloud, isLogAnalyticsSameAs } from '../credentials';
import { getLogAnalyticsApiRoute, getLogAnalyticsManagementApiRoute } from '../api/routes';
import { getAuthType, getAzureCloud } from '../credentials';
import { getLogAnalyticsApiRoute, getManagementApiRoute } from '../api/routes';
import { AzureLogAnalyticsMetadata } from '../types/logAnalyticsMetadata';
import { isGUIDish } from '../components/ResourcePicker/utils';
@ -51,17 +51,11 @@ export default class AzureLogAnalyticsDatasource extends DataSourceWithBackend<
const logAnalyticsRoute = getLogAnalyticsApiRoute(cloud);
this.baseUrl = `/${logAnalyticsRoute}`;
const managementRoute = getLogAnalyticsManagementApiRoute(cloud);
const managementRoute = getManagementApiRoute(cloud);
this.azureMonitorUrl = `/${managementRoute}/subscriptions`;
this.url = instanceSettings.url || '';
const sameAsMonitor = isLogAnalyticsSameAs(instanceSettings);
this.defaultSubscriptionId = sameAsMonitor
? instanceSettings.jsonData.subscriptionId
: instanceSettings.jsonData.logAnalyticsSubscriptionId;
this.defaultSubscriptionId = this.instanceSettings.jsonData.subscriptionId || '';
this.defaultOrFirstWorkspace = this.instanceSettings.jsonData.logAnalyticsDefaultWorkspace || '';
}
@ -485,14 +479,14 @@ export default class AzureLogAnalyticsDatasource extends DataSourceWithBackend<
const authType = getAuthType(this.instanceSettings);
if (authType === 'clientsecret') {
if (!this.isValidConfigField(this.instanceSettings.jsonData.logAnalyticsTenantId)) {
if (!this.isValidConfigField(this.instanceSettings.jsonData.tenantId)) {
return {
status: 'error',
message: 'The Tenant Id field is required.',
};
}
if (!this.isValidConfigField(this.instanceSettings.jsonData.logAnalyticsClientId)) {
if (!this.isValidConfigField(this.instanceSettings.jsonData.clientId)) {
return {
status: 'error',
message: 'The Client Id field is required.',

@ -22,18 +22,11 @@ const setup = (propsFunc?: (props: Props) => Props) => {
basicAuthPassword: '',
withCredentials: false,
isDefault: false,
secureJsonFields: {
logAnalyticsClientSecret: false,
},
secureJsonFields: {},
jsonData: {
cloudName: '',
subscriptionId: '',
azureLogAnalyticsSameAs: false,
logAnalyticsDefaultWorkspace: '',
logAnalyticsTenantId: '',
},
secureJsonData: {
logAnalyticsClientSecret: '',
},
version: 1,
readOnly: false,
@ -80,10 +73,10 @@ describe('Render', () => {
...props.options.jsonData,
azureLogAnalyticsSameAs: false,
logAnalyticsDefaultWorkspace: '',
logAnalyticsTenantId: 'e7f3f661-a933-4b3f-8176-51c4f982ec48',
logAnalyticsClientId: '44693801-6ee6-49de-9b2d-9106972f9572',
logAnalyticsSubscriptionId: 'e3fe4fde-ad5e-4d60-9974-e2f3562ffdf2',
logAnalyticsClientSecret: 'cddcc020-2c94-460a-a3d0-df3147ffa792',
tenantId: 'e7f3f661-a933-4b3f-8176-51c4f982ec48',
clientId: '44693801-6ee6-49de-9b2d-9106972f9572',
subscriptionId: 'e3fe4fde-ad5e-4d60-9974-e2f3562ffdf2',
clientSecret: 'cddcc020-2c94-460a-a3d0-df3147ffa792',
},
},
}));
@ -91,18 +84,8 @@ describe('Render', () => {
});
it('should not render the Switch to use different creds for log analytics by default', () => {
setup((props) => ({
...props,
options: {
...props.options,
jsonData: {
...props.options.jsonData,
azureLogAnalyticsSameAs: undefined,
},
},
}));
expect(screen.queryByLabelText('Same details as Azure Monitor API')).not.toBeInTheDocument();
expect(screen.queryByText('is deprecated', { exact: false })).not.toBeInTheDocument();
setup();
expect(screen.queryByText('is no longer supported', { exact: false })).not.toBeInTheDocument();
});
// Remove this test with deprecated code
@ -117,7 +100,6 @@ describe('Render', () => {
},
},
}));
expect(screen.queryByLabelText('Same details as Azure Monitor API')).toBeInTheDocument();
expect(screen.queryByText('is deprecated', { exact: false })).toBeInTheDocument();
expect(screen.queryByText('is no longer supported', { exact: false })).toBeInTheDocument();
});
});

@ -2,15 +2,9 @@ import React, { FunctionComponent, useEffect, useMemo, useReducer, useState } fr
import { SelectableValue } from '@grafana/data';
import { AzureCredentialsForm } from './AzureCredentialsForm';
import { InlineFormLabel, LegacyForms, Button, Alert } from '@grafana/ui';
const { Select, Switch } = LegacyForms;
import { AzureDataSourceSettings, AzureCredentials } from '../types';
import {
getCredentials,
getLogAnalyticsCredentials,
isCredentialsComplete,
updateLogAnalyticsCredentials,
updateLogAnalyticsSameAs,
} from '../credentials';
const { Select } = LegacyForms;
import { AzureDataSourceSettings } from '../types';
import { getCredentials, isCredentialsComplete } from '../credentials';
export interface Props {
options: AzureDataSourceSettings;
@ -22,22 +16,16 @@ export interface Props {
export const AnalyticsConfig: FunctionComponent<Props> = (props: Props) => {
const { updateOptions, getSubscriptions, getWorkspaces } = props;
const primaryCredentials = useMemo(() => getCredentials(props.options), [props.options]);
const logAnalyticsCredentials = useMemo(() => getLogAnalyticsCredentials(props.options), [props.options]);
const subscriptionId = logAnalyticsCredentials
? logAnalyticsCredentials.defaultSubscriptionId
: primaryCredentials.defaultSubscriptionId;
const subscriptionId = primaryCredentials.defaultSubscriptionId;
// Only show a section for setting LogAnalytics credentials if they were set from before
// And the authType is supported
const [credentialsUsed, _] = useState(!!logAnalyticsCredentials);
const credentialsEnabled = credentialsUsed && primaryCredentials.authType === 'clientsecret';
// Only show a section for setting LogAnalytics credentials if
// they were set from before with different values and the
// authType is supported
const logCredentialsEnabled =
primaryCredentials.authType === 'clientsecret' && props.options.jsonData.azureLogAnalyticsSameAs === false;
const hasRequiredFields =
subscriptionId &&
(logAnalyticsCredentials
? isCredentialsComplete(logAnalyticsCredentials)
: isCredentialsComplete(primaryCredentials));
const hasRequiredFields = subscriptionId && isCredentialsComplete(primaryCredentials);
const defaultWorkspace = props.options.jsonData.logAnalyticsDefaultWorkspace;
@ -91,18 +79,6 @@ export const AnalyticsConfig: FunctionComponent<Props> = (props: Props) => {
}
};
const [sameAsSwitched, setSameAsSwitched] = useState(false);
const onCredentialsChange = (updatedCredentials: AzureCredentials) => {
updateOptions((options) => updateLogAnalyticsCredentials(options, updatedCredentials));
};
const onLogAnalyticsSameAsChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
const sameAs = event.currentTarget.checked;
updateOptions((options) => updateLogAnalyticsSameAs(options, sameAs));
setSameAsSwitched(true);
};
const onDefaultWorkspaceChange = (selected: SelectableValue<string>) => {
updateOptions((options) => {
return {
@ -115,57 +91,31 @@ export const AnalyticsConfig: FunctionComponent<Props> = (props: Props) => {
});
};
const tooltipAttribute = {
...(!logAnalyticsCredentials && {
tooltip: 'Workspaces are pulled from default subscription selected above.',
}),
};
const showSameAsHelpMsg =
credentialsEnabled &&
sameAsSwitched &&
primaryCredentials.authType === 'clientsecret' &&
!primaryCredentials.clientSecret;
return (
<>
<h3 className="page-heading">Azure Monitor Logs</h3>
{credentialsEnabled && (
{logCredentialsEnabled && (
<>
<Switch
label="Same details as Azure Monitor API"
checked={!logAnalyticsCredentials}
onChange={onLogAnalyticsSameAsChange}
{...tooltipAttribute}
/>
{showSameAsHelpMsg && (
<div className="grafana-info-box m-t-2">
<div className="alert-body">
<p>Re-enter your Azure Monitor Client Secret to use this setting.</p>
</div>
</div>
)}
{logAnalyticsCredentials && (
<>
<Alert severity="info" title="Deprecated">
Using different credentials for Azure Monitor Logs is deprecated and will be removed in a future
version.
<br />
Create a different Data Source if you need to use different credentials.
<Alert severity="error" title="Deprecated">
Using different credentials for Azure Monitor Logs is no longer supported. Authentication information above
will be used instead. Please create a new data source with the credentials below.
</Alert>
<AzureCredentialsForm
managedIdentityEnabled={false}
credentials={logAnalyticsCredentials}
onCredentialsChange={onCredentialsChange}
credentials={{
...primaryCredentials,
authType: 'clientsecret',
// Use deprecated Log Analytics credentials read-only
// to help with a possible migration
tenantId: props.options.jsonData.logAnalyticsTenantId,
clientId: props.options.jsonData.logAnalyticsClientId,
}}
getSubscriptions={getSubscriptions}
disabled={true}
/>
</>
)}
</>
)}
<div className="gf-form-group">
<div className="gf-form-inline">
<div className="gf-form">

@ -1,6 +1,8 @@
import React from 'react';
import { shallow } from 'enzyme';
import AzureCredentialsForm, { Props } from './AzureCredentialsForm';
import { LegacyForms, Button } from '@grafana/ui';
const { Input } = LegacyForms;
const setup = (propsFunc?: (props: Props) => Props) => {
let props: Props = {
@ -63,4 +65,26 @@ describe('Render', () => {
}));
expect(wrapper).toMatchSnapshot();
});
describe('when disabled', () => {
it('should disable inputs', () => {
const wrapper = setup((props) => ({
...props,
disabled: true,
}));
const inputs = wrapper.find(Input);
expect(inputs.length).toBeGreaterThan(1);
inputs.forEach((input) => {
expect(input.prop('disabled')).toBe(true);
});
});
it('should remove buttons', () => {
const wrapper = setup((props) => ({
...props,
disabled: true,
}));
expect(wrapper.find(Button).exists()).toBe(false);
});
});
});

@ -9,8 +9,9 @@ export interface Props {
managedIdentityEnabled: boolean;
credentials: AzureCredentials;
azureCloudOptions?: SelectableValue[];
onCredentialsChange: (updatedCredentials: AzureCredentials) => void;
onCredentialsChange?: (updatedCredentials: AzureCredentials) => void;
getSubscriptions?: () => Promise<SelectableValue[]>;
disabled?: boolean;
}
const authTypeOptions: Array<SelectableValue<AzureAuthType>> = [
@ -25,7 +26,7 @@ const authTypeOptions: Array<SelectableValue<AzureAuthType>> = [
];
export const AzureCredentialsForm: FunctionComponent<Props> = (props: Props) => {
const { credentials, azureCloudOptions, onCredentialsChange, getSubscriptions } = props;
const { credentials, azureCloudOptions, onCredentialsChange, getSubscriptions, disabled } = props;
const hasRequiredFields = isCredentialsComplete(credentials);
const [subscriptions, setSubscriptions] = useState<Array<SelectableValue<string>>>([]);
@ -189,6 +190,7 @@ export const AzureCredentialsForm: FunctionComponent<Props> = (props: Props) =>
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value={credentials.tenantId || ''}
onChange={onTenantIdChange}
disabled={disabled}
/>
</div>
</div>
@ -202,11 +204,13 @@ export const AzureCredentialsForm: FunctionComponent<Props> = (props: Props) =>
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value={credentials.clientId || ''}
onChange={onClientIdChange}
disabled={disabled}
/>
</div>
</div>
</div>
{typeof credentials.clientSecret === 'symbol' ? (
{!disabled &&
(typeof credentials.clientSecret === 'symbol' ? (
<div className="gf-form-inline">
<div className="gf-form">
<InlineFormLabel className="width-12">Client Secret</InlineFormLabel>
@ -214,7 +218,7 @@ export const AzureCredentialsForm: FunctionComponent<Props> = (props: Props) =>
</div>
<div className="gf-form">
<div className="max-width-30 gf-form-inline">
<Button variant="secondary" type="button" onClick={onClientSecretReset}>
<Button variant="secondary" type="button" onClick={onClientSecretReset} disabled={disabled}>
reset
</Button>
</div>
@ -230,11 +234,12 @@ export const AzureCredentialsForm: FunctionComponent<Props> = (props: Props) =>
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value={credentials.clientSecret || ''}
onChange={onClientSecretChange}
disabled={disabled}
/>
</div>
</div>
</div>
)}
))}
</>
)}
{getSubscriptions && (
@ -251,10 +256,12 @@ export const AzureCredentialsForm: FunctionComponent<Props> = (props: Props) =>
}
options={subscriptions}
onChange={onSubscriptionChange}
isDisabled={disabled}
/>
</div>
</div>
</div>
{!disabled && (
<div className="gf-form-inline">
<div className="gf-form">
<div className="max-width-30 gf-form-inline">
@ -270,6 +277,7 @@ export const AzureCredentialsForm: FunctionComponent<Props> = (props: Props) =>
</div>
</div>
</div>
)}
</>
)}
</div>

@ -14,7 +14,7 @@ import { InsightsConfig } from './InsightsConfig';
import ResponseParser from '../azure_monitor/response_parser';
import { AzureDataSourceJsonData, AzureDataSourceSecureJsonData, AzureDataSourceSettings } from '../types';
import { getAzureCloud, isAppInsightsConfigured } from '../credentials';
import { getLogAnalyticsManagementApiRoute, getManagementApiRoute } from '../api/routes';
import { getManagementApiRoute } from '../api/routes';
export type Props = DataSourcePluginOptionsEditorProps<AzureDataSourceJsonData, AzureDataSourceSecureJsonData>;
@ -77,7 +77,7 @@ export class ConfigEditor extends PureComponent<Props, State> {
await this.saveOptions();
const cloud = getAzureCloud(this.props.options);
const route = getLogAnalyticsManagementApiRoute(cloud);
const route = getManagementApiRoute(cloud);
const url = `/${route}/subscriptions?api-version=2019-03-01`;
const result = await getBackendSrv().datasourceRequest({
@ -92,7 +92,7 @@ export class ConfigEditor extends PureComponent<Props, State> {
await this.saveOptions();
const cloud = getAzureCloud(this.props.options);
const route = getLogAnalyticsManagementApiRoute(cloud);
const route = getManagementApiRoute(cloud);
const url = `/${route}/subscriptions/${subscriptionId}/providers/Microsoft.OperationalInsights/workspaces?api-version=2017-04-26-preview`;
const result = await getBackendSrv().datasourceRequest({

@ -23,6 +23,9 @@ export class InsightsConfig extends PureComponent<Props> {
return (
<>
<h3 className="page-heading">Azure Application Insights</h3>
<Alert severity="info" title="Application Insights credentials are deprecated">
Configure using Azure AD App Registration above and update existing queries to use Metrics or Logs.
</Alert>
<div className="gf-form-group">
{options.secureJsonFields.appInsightsApiKey ? (
<div className="gf-form-inline">
@ -66,10 +69,6 @@ export class InsightsConfig extends PureComponent<Props> {
</div>
</div>
</div>
<Alert severity="info" title="Application Insights credentials are deprecated">
Configure using Azure AD App Registration above and update existing queries to use Metrics or Logs.
</Alert>
</>
);
}

@ -65,7 +65,7 @@ exports[`Render should disable log analytics credentials form 1`] = `
autocapitalize="none"
autocomplete="off"
autocorrect="off"
id="react-select-4-input"
id="react-select-3-input"
spellcheck="false"
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
tabindex="0"
@ -128,36 +128,11 @@ exports[`Render should enable azure log analytics load workspaces button 1`] = `
Azure Monitor Logs
</h3>
<div
class="gf-form-switch-container-react"
>
<label
class="gf-form gf-form-switch-container "
for="2"
>
<div
class="gf-form-label pointer"
>
Same details as Azure Monitor API
</div>
<div
class="gf-form-switch "
>
<input
id="2"
type="checkbox"
/>
<span
class="gf-form-switch__slider"
/>
</div>
</label>
</div>
<div
aria-label="Alert info"
aria-label="Alert error"
class="css-7gef9a"
>
<div
class="css-ed9azx"
class="css-a4coia"
>
<div
class="css-1vzus6i-Icon"
@ -174,9 +149,7 @@ exports[`Render should enable azure log analytics load workspaces button 1`] = `
<div
class="css-1b0c7i6"
>
Using different credentials for Azure Monitor Logs is deprecated and will be removed in a future version.
<br />
Create a different Data Source if you need to use different credentials.
Using different credentials for Azure Monitor Logs is no longer supported. Authentication information above will be used instead. Please create a new data source with the credentials below.
</div>
</div>
</div>
@ -202,8 +175,9 @@ exports[`Render should enable azure log analytics load workspaces button 1`] = `
>
<input
class="gf-form-input width-30"
disabled=""
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value="e7f3f661-a933-4b3f-8176-51c4f982ec48"
value=""
/>
</div>
</div>
@ -228,32 +202,7 @@ exports[`Render should enable azure log analytics load workspaces button 1`] = `
>
<input
class="gf-form-input width-30"
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value="44693801-6ee6-49de-9b2d-9106972f9572"
/>
</div>
</div>
</div>
</div>
<div
class="gf-form-inline"
>
<div
class="gf-form"
>
<label
class="width-12 gf-form-label width-10"
>
Client Secret
</label>
<div
class="width-15"
>
<div
style="flex-grow: 1;"
>
<input
class="gf-form-input width-30"
disabled=""
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value=""
/>
@ -277,7 +226,7 @@ exports[`Render should enable azure log analytics load workspaces button 1`] = `
>
<div>
<div
class="gf-form-input gf-form-input--form-dropdown css-1daubv-SelectContainer"
class="gf-form-input gf-form-input--form-dropdown gf-form-select-box--is-disabled css-1daubv-SelectContainer"
>
<span
aria-atomic="false"
@ -286,7 +235,7 @@ exports[`Render should enable azure log analytics load workspaces button 1`] = `
class="css-1f43avz-a11yText-A11yText"
/>
<div
class="gf-form-select-box__control css-1g8ily9-Control"
class="gf-form-select-box__control gf-form-select-box__control--is-disabled css-1g8ily9-Control"
>
<div
class="gf-form-select-box__value-container css-pilx6v-ValueContainer"
@ -308,7 +257,8 @@ exports[`Render should enable azure log analytics load workspaces button 1`] = `
autocapitalize="none"
autocomplete="off"
autocorrect="off"
id="react-select-5-input"
disabled=""
id="react-select-4-input"
spellcheck="false"
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
tabindex="0"
@ -334,29 +284,6 @@ exports[`Render should enable azure log analytics load workspaces button 1`] = `
</div>
</div>
</div>
<div
class="gf-form-inline"
>
<div
class="gf-form"
>
<div
class="max-width-30 gf-form-inline"
>
<button
class="css-191ipe8-button"
disabled=""
type="button"
>
<span
class="css-1mhnkuh"
>
Load Subscriptions
</span>
</button>
</div>
</div>
</div>
</div>
<div
class="gf-form-group"
@ -415,7 +342,7 @@ exports[`Render should enable azure log analytics load workspaces button 1`] = `
autocapitalize="none"
autocomplete="off"
autocorrect="off"
id="react-select-6-input"
id="react-select-5-input"
spellcheck="false"
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
tabindex="0"
@ -477,237 +404,6 @@ exports[`Render should render component 1`] = `
>
Azure Monitor Logs
</h3>
<div
class="gf-form-switch-container-react"
>
<label
class="gf-form gf-form-switch-container "
for="1"
>
<div
class="gf-form-label pointer"
>
Same details as Azure Monitor API
</div>
<div
class="gf-form-switch "
>
<input
id="1"
type="checkbox"
/>
<span
class="gf-form-switch__slider"
/>
</div>
</label>
</div>
<div
aria-label="Alert info"
class="css-7gef9a"
>
<div
class="css-ed9azx"
>
<div
class="css-1vzus6i-Icon"
/>
</div>
<div
class="css-zmuccj"
>
<div
class="css-hui7p1"
>
Deprecated
</div>
<div
class="css-1b0c7i6"
>
Using different credentials for Azure Monitor Logs is deprecated and will be removed in a future version.
<br />
Create a different Data Source if you need to use different credentials.
</div>
</div>
</div>
<div
class="gf-form-group"
>
<div
class="gf-form-inline"
>
<div
class="gf-form"
>
<label
class="width-12 gf-form-label width-10"
>
Directory (tenant) ID
</label>
<div
class="width-15"
>
<div
style="flex-grow: 1;"
>
<input
class="gf-form-input width-30"
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value=""
/>
</div>
</div>
</div>
</div>
<div
class="gf-form-inline"
>
<div
class="gf-form"
>
<label
class="width-12 gf-form-label width-10"
>
Application (client) ID
</label>
<div
class="width-15"
>
<div
style="flex-grow: 1;"
>
<input
class="gf-form-input width-30"
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value=""
/>
</div>
</div>
</div>
</div>
<div
class="gf-form-inline"
>
<div
class="gf-form"
>
<label
class="width-12 gf-form-label width-10"
>
Client Secret
</label>
<div
class="width-15"
>
<div
style="flex-grow: 1;"
>
<input
class="gf-form-input width-30"
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
value=""
/>
</div>
</div>
</div>
</div>
<div
class="gf-form-inline"
>
<div
class="gf-form"
>
<label
class="width-12 gf-form-label width-10"
>
Default Subscription
</label>
<div
class="width-25"
>
<div>
<div
class="gf-form-input gf-form-input--form-dropdown css-1daubv-SelectContainer"
>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div
class="gf-form-select-box__control css-1g8ily9-Control"
>
<div
class="gf-form-select-box__value-container css-pilx6v-ValueContainer"
>
<div
class="gf-form-select-box__placeholder css-ovmm9z-Placeholder"
>
Choose
</div>
<div
class="css-17yls17-Input"
>
<div
class="gf-form-select-box__input"
style="display: inline-block;"
>
<input
aria-autocomplete="list"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
id="react-select-2-input"
spellcheck="false"
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/>
<div
style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre; font-family: -webkit-small-control; letter-spacing: normal; text-transform: none;"
/>
</div>
</div>
</div>
<div
class="gf-form-select-box__indicators css-1pmvkci-IndicatorsContainer"
>
<div
class="css-1vzus6i-Icon"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="gf-form-inline"
>
<div
class="gf-form"
>
<div
class="max-width-30 gf-form-inline"
>
<button
class="css-191ipe8-button"
disabled=""
type="button"
>
<span
class="css-1mhnkuh"
>
Load Subscriptions
</span>
</button>
</div>
</div>
</div>
</div>
<div
class="gf-form-group"
>
@ -765,7 +461,7 @@ exports[`Render should render component 1`] = `
autocapitalize="none"
autocomplete="off"
autocorrect="off"
id="react-select-3-input"
id="react-select-2-input"
spellcheck="false"
style="box-sizing: content-box; width: 2px; border: 0px; opacity: 1; outline: 0; padding: 0px;"
tabindex="0"

@ -7,6 +7,12 @@ exports[`Render should disable insights api key input 1`] = `
>
Azure Application Insights
</h3>
<Alert
severity="info"
title="Application Insights credentials are deprecated"
>
Configure using Azure AD App Registration above and update existing queries to use Metrics or Logs.
</Alert>
<div
className="gf-form-group"
>
@ -65,12 +71,6 @@ exports[`Render should disable insights api key input 1`] = `
</div>
</div>
</div>
<Alert
severity="info"
title="Application Insights credentials are deprecated"
>
Configure using Azure AD App Registration above and update existing queries to use Metrics or Logs.
</Alert>
</Fragment>
`;
@ -81,6 +81,12 @@ exports[`Render should enable insights api key input 1`] = `
>
Azure Application Insights
</h3>
<Alert
severity="info"
title="Application Insights credentials are deprecated"
>
Configure using Azure AD App Registration above and update existing queries to use Metrics or Logs.
</Alert>
<div
className="gf-form-group"
>
@ -128,12 +134,6 @@ exports[`Render should enable insights api key input 1`] = `
</div>
</div>
</div>
<Alert
severity="info"
title="Application Insights credentials are deprecated"
>
Configure using Azure AD App Registration above and update existing queries to use Metrics or Logs.
</Alert>
</Fragment>
`;
@ -144,6 +144,12 @@ exports[`Render should render component 1`] = `
>
Azure Application Insights
</h3>
<Alert
severity="info"
title="Application Insights credentials are deprecated"
>
Configure using Azure AD App Registration above and update existing queries to use Metrics or Logs.
</Alert>
<div
className="gf-form-group"
>
@ -191,11 +197,5 @@ exports[`Render should render component 1`] = `
</div>
</div>
</div>
<Alert
severity="info"
title="Application Insights credentials are deprecated"
>
Configure using Azure AD App Registration above and update existing queries to use Metrics or Logs.
</Alert>
</Fragment>
`;

@ -64,20 +64,6 @@ function getSecret(options: AzureDataSourceSettings): undefined | string | Conce
}
}
function getLogAnalyticsSecret(options: AzureDataSourceSettings): undefined | string | ConcealedSecret {
if (options.secureJsonFields.logAnalyticsClientSecret) {
// The secret is concealed on server
return concealed;
} else {
const secret = options.secureJsonData?.logAnalyticsClientSecret;
return typeof secret === 'string' && secret.length > 0 ? secret : undefined;
}
}
export function isLogAnalyticsSameAs(options: AzureDataSourceSettings | AzureDataSourceInstanceSettings): boolean {
return typeof options.jsonData.azureLogAnalyticsSameAs !== 'boolean' || options.jsonData.azureLogAnalyticsSameAs;
}
export function isCredentialsComplete(credentials: AzureCredentials): boolean {
switch (credentials.authType) {
case 'msi':
@ -116,29 +102,6 @@ export function getCredentials(options: AzureDataSourceSettings): AzureCredentia
}
}
export function getLogAnalyticsCredentials(options: AzureDataSourceSettings): AzureCredentials | undefined {
const authType = getAuthType(options);
if (authType !== 'clientsecret') {
// Only app registration (client secret) authentication supports different credentials for Log Analytics
// for backward compatibility
return undefined;
}
if (isLogAnalyticsSameAs(options)) {
return undefined;
}
return {
authType: 'clientsecret',
azureCloud: options.jsonData.cloudName || getDefaultAzureCloud(),
tenantId: options.jsonData.logAnalyticsTenantId,
clientId: options.jsonData.logAnalyticsClientId,
clientSecret: getLogAnalyticsSecret(options),
defaultSubscriptionId: options.jsonData.logAnalyticsSubscriptionId,
};
}
export function updateCredentials(
options: AzureDataSourceSettings,
credentials: AzureCredentials
@ -158,12 +121,6 @@ export function updateCredentials(
},
};
if (!isLogAnalyticsSameAs(options)) {
options = updateLogAnalyticsSameAs(options, true);
} else {
options = updateLogAnalyticsCredentials(options, credentials);
}
return options;
case 'clientsecret':
@ -190,82 +147,8 @@ export function updateCredentials(
},
};
if (isLogAnalyticsSameAs(options)) {
options = updateLogAnalyticsCredentials(options, credentials);
}
return options;
}
}
export function updateLogAnalyticsCredentials(
options: AzureDataSourceSettings,
credentials: AzureCredentials
): AzureDataSourceSettings {
// Log Analytics credentials only used if primary credentials are App Registration (client secret)
if (credentials.authType === 'clientsecret') {
options = {
...options,
jsonData: {
...options.jsonData,
logAnalyticsTenantId: credentials.tenantId,
logAnalyticsClientId: credentials.clientId,
},
secureJsonData: {
...options.secureJsonData,
logAnalyticsClientSecret:
typeof credentials.clientSecret === 'string' && credentials.clientSecret.length > 0
? credentials.clientSecret
: undefined,
},
secureJsonFields: {
...options.secureJsonFields,
logAnalyticsClientSecret: typeof credentials.clientSecret === 'symbol',
},
};
}
// Default subscription
options = {
...options,
jsonData: {
...options.jsonData,
logAnalyticsSubscriptionId: credentials.defaultSubscriptionId,
},
};
return options;
}
export function updateLogAnalyticsSameAs(options: AzureDataSourceSettings, sameAs: boolean): AzureDataSourceSettings {
if (sameAs !== isLogAnalyticsSameAs(options)) {
// Update the 'Same As' switch
options = {
...options,
jsonData: {
...options.jsonData,
azureLogAnalyticsSameAs: sameAs,
},
};
if (sameAs) {
// Get the primary credentials
let credentials = getCredentials(options);
// Check whether the primary client secret is concealed
if (credentials.authType === 'clientsecret' && typeof credentials.clientSecret === 'symbol') {
// Log Analytics credentials need to be synchronized but the client secret is concealed,
// so we have to reset the primary client secret to ensure that user enters a new secret
credentials.clientSecret = undefined;
options = updateCredentials(options, credentials);
}
// Synchronize the Log Analytics credentials with primary credentials
options = updateLogAnalyticsCredentials(options, credentials);
}
}
return options;
}
export function isAppInsightsConfigured(options: AzureDataSourceSettings) {

@ -115,74 +115,6 @@
{ "name": "x-ms-app", "content": "Grafana" }
]
},
{
"path": "workspacesloganalytics",
"method": "*",
"url": "https://management.azure.com",
"authType": "azure",
"tokenAuth": {
"scopes": ["https://management.azure.com/.default"],
"params": {
"azure_auth_type": "{{.JsonData.azureAuthType | orEmpty}}",
"azure_cloud": "AzureCloud",
"tenant_id": "{{.JsonData.logAnalyticsTenantId | orEmpty}}",
"client_id": "{{.JsonData.logAnalyticsClientId | orEmpty}}",
"client_secret": "{{.SecureJsonData.logAnalyticsClientSecret | orEmpty}}"
}
},
"headers": [{ "name": "x-ms-app", "content": "Grafana" }]
},
{
"path": "chinaworkspacesloganalytics",
"method": "*",
"url": "https://management.chinacloudapi.cn",
"authType": "azure",
"tokenAuth": {
"scopes": ["https://management.chinacloudapi.cn/.default"],
"params": {
"azure_auth_type": "{{.JsonData.azureAuthType | orEmpty}}",
"azure_cloud": "AzureChinaCloud",
"tenant_id": "{{.JsonData.logAnalyticsTenantId | orEmpty}}",
"client_id": "{{.JsonData.logAnalyticsClientId | orEmpty}}",
"client_secret": "{{.SecureJsonData.logAnalyticsClientSecret | orEmpty}}"
}
},
"headers": [{ "name": "x-ms-app", "content": "Grafana" }]
},
{
"path": "govworkspacesloganalytics",
"method": "*",
"url": "https://management.usgovcloudapi.net",
"authType": "azure",
"tokenAuth": {
"scopes": ["https://management.usgovcloudapi.net/.default"],
"params": {
"azure_auth_type": "{{.JsonData.azureAuthType | orEmpty}}",
"azure_cloud": "AzureUSGovernment",
"tenant_id": "{{.JsonData.logAnalyticsTenantId | orEmpty}}",
"client_id": "{{.JsonData.logAnalyticsClientId | orEmpty}}",
"client_secret": "{{.SecureJsonData.logAnalyticsClientSecret | orEmpty}}"
}
},
"headers": [{ "name": "x-ms-app", "content": "Grafana" }]
},
{
"path": "germanyworkspacesloganalytics",
"method": "*",
"url": "https://management.microsoftazure.de",
"authType": "azure",
"tokenAuth": {
"scopes": ["https://management.microsoftazure.de/.default"],
"params": {
"azure_auth_type": "{{.JsonData.azureAuthType | orEmpty}}",
"azure_cloud": "AzureUSGovernment",
"tenant_id": "{{.JsonData.logAnalyticsTenantId | orEmpty}}",
"client_id": "{{.JsonData.logAnalyticsClientId | orEmpty}}",
"client_secret": "{{.SecureJsonData.logAnalyticsClientSecret | orEmpty}}"
}
},
"headers": [{ "name": "x-ms-app", "content": "Grafana" }]
},
{
"path": "loganalyticsazure",
"method": "GET",
@ -193,9 +125,9 @@
"params": {
"azure_auth_type": "{{.JsonData.azureAuthType | orEmpty}}",
"azure_cloud": "AzureCloud",
"tenant_id": "{{.JsonData.logAnalyticsTenantId | orEmpty}}",
"client_id": "{{.JsonData.logAnalyticsClientId | orEmpty}}",
"client_secret": "{{.SecureJsonData.logAnalyticsClientSecret | orEmpty}}"
"tenant_id": "{{.JsonData.tenantId | orEmpty}}",
"client_id": "{{.JsonData.clientId | orEmpty}}",
"client_secret": "{{.SecureJsonData.clientSecret | orEmpty}}"
}
},
"headers": [
@ -213,9 +145,9 @@
"params": {
"azure_auth_type": "{{.JsonData.azureAuthType | orEmpty}}",
"azure_cloud": "AzureChinaCloud",
"tenant_id": "{{.JsonData.logAnalyticsTenantId | orEmpty}}",
"client_id": "{{.JsonData.logAnalyticsClientId | orEmpty}}",
"client_secret": "{{.SecureJsonData.logAnalyticsClientSecret | orEmpty}}"
"tenant_id": "{{.JsonData.tenantId | orEmpty}}",
"client_id": "{{.JsonData.clientId | orEmpty}}",
"client_secret": "{{.SecureJsonData.clientSecret | orEmpty}}"
}
},
"headers": [
@ -233,9 +165,9 @@
"params": {
"azure_auth_type": "{{.JsonData.azureAuthType | orEmpty}}",
"azure_cloud": "AzureUSGovernment",
"tenant_id": "{{.JsonData.logAnalyticsTenantId | orEmpty}}",
"client_id": "{{.JsonData.logAnalyticsClientId | orEmpty}}",
"client_secret": "{{.SecureJsonData.logAnalyticsClientSecret | orEmpty}}"
"tenant_id": "{{.JsonData.tenantId | orEmpty}}",
"client_id": "{{.JsonData.clientId | orEmpty}}",
"client_secret": "{{.SecureJsonData.clientSecret | orEmpty}}"
}
},
"headers": [

@ -1,5 +1,5 @@
import { FetchResponse, getBackendSrv } from '@grafana/runtime';
import { getLogAnalyticsManagementApiRoute } from '../api/routes';
import { getManagementApiRoute } from '../api/routes';
import {
locationDisplayNames,
logsSupportedLocationsKusto,
@ -148,7 +148,7 @@ export default class ResourcePickerData {
try {
return await getBackendSrv()
.fetch<AzureGraphResponse<T>>({
url: this.proxyUrl + '/' + getLogAnalyticsManagementApiRoute(this.cloud) + RESOURCE_GRAPH_URL,
url: this.proxyUrl + '/' + getManagementApiRoute(this.cloud) + RESOURCE_GRAPH_URL,
method: 'POST',
data: {
query: query,

@ -83,11 +83,15 @@ export interface AzureDataSourceJsonData extends DataSourceJsonData {
subscriptionId?: string;
// logs
logAnalyticsDefaultWorkspace?: string;
/** @deprecated Azure Logs credentials */
azureLogAnalyticsSameAs?: boolean;
/** @deprecated Azure Logs credentials */
logAnalyticsTenantId?: string;
/** @deprecated Azure Logs credentials */
logAnalyticsClientId?: string;
/** @deprecated Azure Logs credentials */
logAnalyticsSubscriptionId?: string;
logAnalyticsDefaultWorkspace?: string;
// App Insights
appInsightsAppId?: string;
@ -95,7 +99,6 @@ export interface AzureDataSourceJsonData extends DataSourceJsonData {
export interface AzureDataSourceSecureJsonData {
clientSecret?: string;
logAnalyticsClientSecret?: string;
appInsightsApiKey?: string;
}

Loading…
Cancel
Save