AzureMonitor: Remove support for different credentials for Azure Monitor Logs (#35121)
This commit is contained in:
-3
@@ -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':
|
||||
|
||||
+2
-2
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
+6
-12
@@ -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.',
|
||||
|
||||
+8
-26
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
+28
-78
@@ -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,55 +91,29 @@ 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}
|
||||
<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={{
|
||||
...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}
|
||||
/>
|
||||
|
||||
{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>
|
||||
|
||||
<AzureCredentialsForm
|
||||
managedIdentityEnabled={false}
|
||||
credentials={logAnalyticsCredentials}
|
||||
onCredentialsChange={onCredentialsChange}
|
||||
getSubscriptions={getSubscriptions}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<div className="gf-form-group">
|
||||
|
||||
+24
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+48
-40
@@ -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,39 +204,42 @@ 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' ? (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel className="width-12">Client Secret</InlineFormLabel>
|
||||
<Input className="width-25" placeholder="configured" disabled={true} />
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<div className="max-width-30 gf-form-inline">
|
||||
<Button variant="secondary" type="button" onClick={onClientSecretReset}>
|
||||
reset
|
||||
</Button>
|
||||
{!disabled &&
|
||||
(typeof credentials.clientSecret === 'symbol' ? (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel className="width-12">Client Secret</InlineFormLabel>
|
||||
<Input className="width-25" placeholder="configured" disabled={true} />
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<div className="max-width-30 gf-form-inline">
|
||||
<Button variant="secondary" type="button" onClick={onClientSecretReset} disabled={disabled}>
|
||||
reset
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel className="width-12">Client Secret</InlineFormLabel>
|
||||
<div className="width-15">
|
||||
<Input
|
||||
className="width-30"
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value={credentials.clientSecret || ''}
|
||||
onChange={onClientSecretChange}
|
||||
/>
|
||||
) : (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<InlineFormLabel className="width-12">Client Secret</InlineFormLabel>
|
||||
<div className="width-15">
|
||||
<Input
|
||||
className="width-30"
|
||||
placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
|
||||
value={credentials.clientSecret || ''}
|
||||
onChange={onClientSecretChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{getSubscriptions && (
|
||||
@@ -251,25 +256,28 @@ export const AzureCredentialsForm: FunctionComponent<Props> = (props: Props) =>
|
||||
}
|
||||
options={subscriptions}
|
||||
onChange={onSubscriptionChange}
|
||||
isDisabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<div className="max-width-30 gf-form-inline">
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
type="button"
|
||||
onClick={onLoadSubscriptions}
|
||||
disabled={!hasRequiredFields}
|
||||
>
|
||||
Load Subscriptions
|
||||
</Button>
|
||||
{!disabled && (
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<div className="max-width-30 gf-form-inline">
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
type="button"
|
||||
onClick={onLoadSubscriptions}
|
||||
disabled={!hasRequiredFields}
|
||||
>
|
||||
Load Subscriptions
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
+3
-3
@@ -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({
|
||||
|
||||
+3
-4
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+396
-700
File diff suppressed because it is too large
Load Diff
+18
-18
@@ -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,84 +147,10 @@ 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) {
|
||||
return !!(options.jsonData.appInsightsAppId && options.secureJsonFields.appInsightsApiKey);
|
||||
}
|
||||
|
||||
@@ -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": [
|
||||
|
||||
+2
-2
@@ -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
|
||||
azureLogAnalyticsSameAs?: boolean;
|
||||
logAnalyticsTenantId?: string;
|
||||
logAnalyticsClientId?: string;
|
||||
logAnalyticsSubscriptionId?: string;
|
||||
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;
|
||||
|
||||
// App Insights
|
||||
appInsightsAppId?: string;
|
||||
@@ -95,7 +99,6 @@ export interface AzureDataSourceJsonData extends DataSourceJsonData {
|
||||
|
||||
export interface AzureDataSourceSecureJsonData {
|
||||
clientSecret?: string;
|
||||
logAnalyticsClientSecret?: string;
|
||||
appInsightsApiKey?: string;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user