mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Azure Monitor: Add support for Metric Names variables (#52322)
* Azure Monitor: Add support for Metric Names variables * Azure Monitor: Add support for Workspaces variables (#52323)
This commit is contained in:
parent
d6d49d8ba3
commit
2538fca53a
@ -321,5 +321,25 @@ describe('AzureMonitorUrlBuilder', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when metric definition does not contain a metric namespace', () => {
|
||||||
|
it('should build the getMetricNames url in the longer format', () => {
|
||||||
|
const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl(
|
||||||
|
'',
|
||||||
|
'2017-05-01-preview',
|
||||||
|
{
|
||||||
|
subscription: 'sub1',
|
||||||
|
resourceGroup: 'rg',
|
||||||
|
metricDefinition: 'microsoft.compute/virtualmachines',
|
||||||
|
resourceName: 'rn1',
|
||||||
|
},
|
||||||
|
templateSrv
|
||||||
|
);
|
||||||
|
expect(url).toBe(
|
||||||
|
'/subscriptions/sub1/resourceGroups/rg/providers/microsoft.compute/virtualmachines/rn1/' +
|
||||||
|
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -82,9 +82,10 @@ export default class UrlBuilder {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
let url = `${baseUrl}${resourceUri}/providers/microsoft.insights/metricdefinitions?api-version=${apiVersion}`;
|
||||||
`${baseUrl}${resourceUri}/providers/microsoft.insights/metricdefinitions?api-version=${apiVersion}` +
|
if (metricNamespace) {
|
||||||
`&metricnamespace=${encodeURIComponent(metricNamespace)}`
|
url += `&metricnamespace=${encodeURIComponent(metricNamespace)}`;
|
||||||
);
|
}
|
||||||
|
return url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ const defaultProps = {
|
|||||||
getSubscriptions: jest.fn().mockResolvedValue([{ text: 'Primary Subscription', value: 'sub' }]),
|
getSubscriptions: jest.fn().mockResolvedValue([{ text: 'Primary Subscription', value: 'sub' }]),
|
||||||
getResourceGroups: jest.fn().mockResolvedValue([{ text: 'rg', value: 'rg' }]),
|
getResourceGroups: jest.fn().mockResolvedValue([{ text: 'rg', value: 'rg' }]),
|
||||||
getMetricNamespaces: jest.fn().mockResolvedValue([{ text: 'foo/bar', value: 'foo/bar' }]),
|
getMetricNamespaces: jest.fn().mockResolvedValue([{ text: 'foo/bar', value: 'foo/bar' }]),
|
||||||
|
getResourceNames: jest.fn().mockResolvedValue([{ text: 'foobar', value: 'foobar' }]),
|
||||||
getVariablesRaw: jest.fn().mockReturnValue([
|
getVariablesRaw: jest.fn().mockReturnValue([
|
||||||
{ label: 'query0', name: 'sub0' },
|
{ label: 'query0', name: 'sub0' },
|
||||||
{ label: 'query1', name: 'rg', query: { queryType: AzureQueryType.ResourceGroupsQuery } },
|
{ label: 'query1', name: 'rg', query: { queryType: AzureQueryType.ResourceGroupsQuery } },
|
||||||
@ -143,8 +144,24 @@ describe('VariableEditor:', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('predefined queries:', () => {
|
describe('predefined queries:', () => {
|
||||||
it('should show the new query types if feature gate is enabled', async () => {
|
const selectAndRerender = async (
|
||||||
|
label: string,
|
||||||
|
text: string,
|
||||||
|
onChange: jest.Mock,
|
||||||
|
rerender: (ui: React.ReactElement) => void
|
||||||
|
) => {
|
||||||
|
openMenu(screen.getByLabelText(label));
|
||||||
|
screen.getByText(text).click();
|
||||||
|
// Simulate onChange behavior
|
||||||
|
const newQuery = onChange.mock.calls.at(-1)[0];
|
||||||
|
rerender(<VariableEditor {...defaultProps} query={newQuery} onChange={onChange} />);
|
||||||
|
await waitFor(() => expect(screen.getByText(text)).toBeInTheDocument());
|
||||||
|
};
|
||||||
|
beforeEach(() => {
|
||||||
grafanaRuntime.config.featureToggles.azTemplateVars = true;
|
grafanaRuntime.config.featureToggles.azTemplateVars = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show the new query types if feature gate is enabled', async () => {
|
||||||
render(<VariableEditor {...defaultProps} />);
|
render(<VariableEditor {...defaultProps} />);
|
||||||
openMenu(screen.getByLabelText('select query type'));
|
openMenu(screen.getByLabelText('select query type'));
|
||||||
await waitFor(() => expect(screen.getByText('Subscriptions')).toBeInTheDocument());
|
await waitFor(() => expect(screen.getByText('Subscriptions')).toBeInTheDocument());
|
||||||
@ -158,36 +175,21 @@ describe('VariableEditor:', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should run the query if requesting subscriptions', async () => {
|
it('should run the query if requesting subscriptions', async () => {
|
||||||
grafanaRuntime.config.featureToggles.azTemplateVars = true;
|
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
const { rerender } = render(<VariableEditor {...defaultProps} onChange={onChange} />);
|
const { rerender } = render(<VariableEditor {...defaultProps} onChange={onChange} />);
|
||||||
openMenu(screen.getByLabelText('select query type'));
|
await selectAndRerender('select query type', 'Subscriptions', onChange, rerender);
|
||||||
screen.getByText('Subscriptions').click();
|
|
||||||
// Simulate onChange behavior
|
|
||||||
const newQuery = onChange.mock.calls.at(-1)[0];
|
|
||||||
rerender(<VariableEditor {...defaultProps} query={newQuery} onChange={onChange} />);
|
|
||||||
await waitFor(() => expect(screen.getByText('Subscriptions')).toBeInTheDocument());
|
|
||||||
expect(onChange).toHaveBeenCalledWith(
|
expect(onChange).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({ queryType: AzureQueryType.SubscriptionsQuery, refId: 'A' })
|
expect.objectContaining({ queryType: AzureQueryType.SubscriptionsQuery, refId: 'A' })
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should run the query if requesting resource groups', async () => {
|
it('should run the query if requesting resource groups', async () => {
|
||||||
grafanaRuntime.config.featureToggles.azTemplateVars = true;
|
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
const { rerender } = render(<VariableEditor {...defaultProps} onChange={onChange} />);
|
const { rerender } = render(<VariableEditor {...defaultProps} onChange={onChange} />);
|
||||||
// wait for initial load
|
// wait for initial load
|
||||||
await waitFor(() => expect(screen.getByText('Logs')).toBeInTheDocument());
|
await waitFor(() => expect(screen.getByText('Logs')).toBeInTheDocument());
|
||||||
// Select RGs variable
|
await selectAndRerender('select query type', 'Resource Groups', onChange, rerender);
|
||||||
openMenu(screen.getByLabelText('select query type'));
|
await selectAndRerender('select subscription', 'Primary Subscription', onChange, rerender);
|
||||||
screen.getByText('Resource Groups').click();
|
|
||||||
// Simulate onChange behavior
|
|
||||||
const newQuery = onChange.mock.calls.at(-1)[0];
|
|
||||||
rerender(<VariableEditor {...defaultProps} query={newQuery} onChange={onChange} />);
|
|
||||||
await waitFor(() => expect(screen.getByText('Select subscription')).toBeInTheDocument());
|
|
||||||
// Select a subscription
|
|
||||||
openMenu(screen.getByLabelText('select subscription'));
|
|
||||||
screen.getByText('Primary Subscription').click();
|
|
||||||
expect(onChange).toHaveBeenCalledWith(
|
expect(onChange).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
queryType: AzureQueryType.ResourceGroupsQuery,
|
queryType: AzureQueryType.ResourceGroupsQuery,
|
||||||
@ -199,17 +201,10 @@ describe('VariableEditor:', () => {
|
|||||||
|
|
||||||
it('should show template variables as options ', async () => {
|
it('should show template variables as options ', async () => {
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
grafanaRuntime.config.featureToggles.azTemplateVars = true;
|
|
||||||
const { rerender } = render(<VariableEditor {...defaultProps} onChange={onChange} />);
|
const { rerender } = render(<VariableEditor {...defaultProps} onChange={onChange} />);
|
||||||
// wait for initial load
|
// wait for initial load
|
||||||
await waitFor(() => expect(screen.getByText('Logs')).toBeInTheDocument());
|
await waitFor(() => expect(screen.getByText('Logs')).toBeInTheDocument());
|
||||||
// Select RGs variable
|
await selectAndRerender('select query type', 'Resource Groups', onChange, rerender);
|
||||||
openMenu(screen.getByLabelText('select query type'));
|
|
||||||
screen.getByText('Resource Groups').click();
|
|
||||||
// Simulate onChange behavior
|
|
||||||
const newQuery = onChange.mock.calls.at(-1)[0];
|
|
||||||
rerender(<VariableEditor {...defaultProps} query={newQuery} onChange={onChange} />);
|
|
||||||
await waitFor(() => expect(screen.getByText('Select subscription')).toBeInTheDocument());
|
|
||||||
// Select a subscription
|
// Select a subscription
|
||||||
openMenu(screen.getByLabelText('select subscription'));
|
openMenu(screen.getByLabelText('select subscription'));
|
||||||
await waitFor(() => expect(screen.getByText('Primary Subscription')).toBeInTheDocument());
|
await waitFor(() => expect(screen.getByText('Primary Subscription')).toBeInTheDocument());
|
||||||
@ -223,21 +218,12 @@ describe('VariableEditor:', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should run the query if requesting namespaces', async () => {
|
it('should run the query if requesting namespaces', async () => {
|
||||||
grafanaRuntime.config.featureToggles.azTemplateVars = true;
|
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
const { rerender } = render(<VariableEditor {...defaultProps} onChange={onChange} />);
|
const { rerender } = render(<VariableEditor {...defaultProps} onChange={onChange} />);
|
||||||
// wait for initial load
|
// wait for initial load
|
||||||
await waitFor(() => expect(screen.getByText('Logs')).toBeInTheDocument());
|
await waitFor(() => expect(screen.getByText('Logs')).toBeInTheDocument());
|
||||||
// Select RGs variable
|
await selectAndRerender('select query type', 'Namespaces', onChange, rerender);
|
||||||
openMenu(screen.getByLabelText('select query type'));
|
await selectAndRerender('select subscription', 'Primary Subscription', onChange, rerender);
|
||||||
screen.getByText('Namespaces').click();
|
|
||||||
// Simulate onChange behavior
|
|
||||||
const newQuery = onChange.mock.calls.at(-1)[0];
|
|
||||||
rerender(<VariableEditor {...defaultProps} query={newQuery} onChange={onChange} />);
|
|
||||||
await waitFor(() => expect(screen.getByText('Select subscription')).toBeInTheDocument());
|
|
||||||
// Select a subscription
|
|
||||||
openMenu(screen.getByLabelText('select subscription'));
|
|
||||||
screen.getByText('Primary Subscription').click();
|
|
||||||
expect(onChange).toHaveBeenCalledWith(
|
expect(onChange).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
queryType: AzureQueryType.NamespacesQuery,
|
queryType: AzureQueryType.NamespacesQuery,
|
||||||
@ -248,21 +234,12 @@ describe('VariableEditor:', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should run the query if requesting resource names', async () => {
|
it('should run the query if requesting resource names', async () => {
|
||||||
grafanaRuntime.config.featureToggles.azTemplateVars = true;
|
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
const { rerender } = render(<VariableEditor {...defaultProps} onChange={onChange} />);
|
const { rerender } = render(<VariableEditor {...defaultProps} onChange={onChange} />);
|
||||||
// wait for initial load
|
// wait for initial load
|
||||||
await waitFor(() => expect(screen.getByText('Logs')).toBeInTheDocument());
|
await waitFor(() => expect(screen.getByText('Logs')).toBeInTheDocument());
|
||||||
// Select RGs variable
|
await selectAndRerender('select query type', 'Resource Names', onChange, rerender);
|
||||||
openMenu(screen.getByLabelText('select query type'));
|
await selectAndRerender('select subscription', 'Primary Subscription', onChange, rerender);
|
||||||
screen.getByText('Resource Names').click();
|
|
||||||
// Simulate onChange behavior
|
|
||||||
const newQuery = onChange.mock.calls.at(-1)[0];
|
|
||||||
rerender(<VariableEditor {...defaultProps} query={newQuery} onChange={onChange} />);
|
|
||||||
await waitFor(() => expect(screen.getByText('Select subscription')).toBeInTheDocument());
|
|
||||||
// Select a subscription
|
|
||||||
openMenu(screen.getByLabelText('select subscription'));
|
|
||||||
screen.getByText('Primary Subscription').click();
|
|
||||||
expect(onChange).toHaveBeenCalledWith(
|
expect(onChange).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
queryType: AzureQueryType.ResourceNamesQuery,
|
queryType: AzureQueryType.ResourceNamesQuery,
|
||||||
@ -271,5 +248,43 @@ describe('VariableEditor:', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should run the query if requesting metric names', async () => {
|
||||||
|
const onChange = jest.fn();
|
||||||
|
const { rerender } = render(<VariableEditor {...defaultProps} onChange={onChange} />);
|
||||||
|
// wait for initial load
|
||||||
|
await waitFor(() => expect(screen.getByText('Logs')).toBeInTheDocument());
|
||||||
|
await selectAndRerender('select query type', 'Metric Names', onChange, rerender);
|
||||||
|
await selectAndRerender('select subscription', 'Primary Subscription', onChange, rerender);
|
||||||
|
await selectAndRerender('select resource group', 'rg', onChange, rerender);
|
||||||
|
await selectAndRerender('select namespace', 'foo/bar', onChange, rerender);
|
||||||
|
await selectAndRerender('select resource', 'foobar', onChange, rerender);
|
||||||
|
expect(onChange).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
queryType: AzureQueryType.MetricNamesQuery,
|
||||||
|
subscription: 'sub',
|
||||||
|
resourceGroup: 'rg',
|
||||||
|
namespace: 'foo/bar',
|
||||||
|
resource: 'foobar',
|
||||||
|
refId: 'A',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should run the query if requesting workspaces', async () => {
|
||||||
|
const onChange = jest.fn();
|
||||||
|
const { rerender } = render(<VariableEditor {...defaultProps} onChange={onChange} />);
|
||||||
|
// wait for initial load
|
||||||
|
await waitFor(() => expect(screen.getByText('Logs')).toBeInTheDocument());
|
||||||
|
await selectAndRerender('select query type', 'Workspaces', onChange, rerender);
|
||||||
|
await selectAndRerender('select subscription', 'Primary Subscription', onChange, rerender);
|
||||||
|
expect(onChange).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
queryType: AzureQueryType.WorkspacesQuery,
|
||||||
|
subscription: 'sub',
|
||||||
|
refId: 'A',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -34,6 +34,8 @@ const VariableEditor = (props: Props) => {
|
|||||||
AZURE_QUERY_VARIABLE_TYPE_OPTIONS.push({ label: 'Resource Groups', value: AzureQueryType.ResourceGroupsQuery });
|
AZURE_QUERY_VARIABLE_TYPE_OPTIONS.push({ label: 'Resource Groups', value: AzureQueryType.ResourceGroupsQuery });
|
||||||
AZURE_QUERY_VARIABLE_TYPE_OPTIONS.push({ label: 'Namespaces', value: AzureQueryType.NamespacesQuery });
|
AZURE_QUERY_VARIABLE_TYPE_OPTIONS.push({ label: 'Namespaces', value: AzureQueryType.NamespacesQuery });
|
||||||
AZURE_QUERY_VARIABLE_TYPE_OPTIONS.push({ label: 'Resource Names', value: AzureQueryType.ResourceNamesQuery });
|
AZURE_QUERY_VARIABLE_TYPE_OPTIONS.push({ label: 'Resource Names', value: AzureQueryType.ResourceNamesQuery });
|
||||||
|
AZURE_QUERY_VARIABLE_TYPE_OPTIONS.push({ label: 'Metric Names', value: AzureQueryType.MetricNamesQuery });
|
||||||
|
AZURE_QUERY_VARIABLE_TYPE_OPTIONS.push({ label: 'Workspaces', value: AzureQueryType.WorkspacesQuery });
|
||||||
}
|
}
|
||||||
const [variableOptionGroup, setVariableOptionGroup] = useState<{ label: string; options: AzureMonitorOption[] }>({
|
const [variableOptionGroup, setVariableOptionGroup] = useState<{ label: string; options: AzureMonitorOption[] }>({
|
||||||
label: 'Template Variables',
|
label: 'Template Variables',
|
||||||
@ -42,9 +44,13 @@ const VariableEditor = (props: Props) => {
|
|||||||
const [requireSubscription, setRequireSubscription] = useState(false);
|
const [requireSubscription, setRequireSubscription] = useState(false);
|
||||||
const [hasResourceGroup, setHasResourceGroup] = useState(false);
|
const [hasResourceGroup, setHasResourceGroup] = useState(false);
|
||||||
const [hasNamespace, setHasNamespace] = useState(false);
|
const [hasNamespace, setHasNamespace] = useState(false);
|
||||||
|
const [requireResourceGroup, setRequireResourceGroup] = useState(false);
|
||||||
|
const [requireNamespace, setRequireNamespace] = useState(false);
|
||||||
|
const [requireResource, setRequireResource] = useState(false);
|
||||||
const [subscriptions, setSubscriptions] = useState<SelectableValue[]>([]);
|
const [subscriptions, setSubscriptions] = useState<SelectableValue[]>([]);
|
||||||
const [resourceGroups, setResourceGroups] = useState<SelectableValue[]>([]);
|
const [resourceGroups, setResourceGroups] = useState<SelectableValue[]>([]);
|
||||||
const [namespaces, setNamespaces] = useState<SelectableValue[]>([]);
|
const [namespaces, setNamespaces] = useState<SelectableValue[]>([]);
|
||||||
|
const [resources, setResources] = useState<SelectableValue[]>([]);
|
||||||
const [errorMessage, setError] = useLastError();
|
const [errorMessage, setError] = useLastError();
|
||||||
const queryType = typeof query === 'string' ? '' : query.queryType;
|
const queryType = typeof query === 'string' ? '' : query.queryType;
|
||||||
|
|
||||||
@ -58,8 +64,12 @@ const VariableEditor = (props: Props) => {
|
|||||||
setRequireSubscription(false);
|
setRequireSubscription(false);
|
||||||
setHasResourceGroup(false);
|
setHasResourceGroup(false);
|
||||||
setHasNamespace(false);
|
setHasNamespace(false);
|
||||||
|
setRequireResourceGroup(false);
|
||||||
|
setRequireNamespace(false);
|
||||||
|
setRequireResource(false);
|
||||||
switch (queryType) {
|
switch (queryType) {
|
||||||
case AzureQueryType.ResourceGroupsQuery:
|
case AzureQueryType.ResourceGroupsQuery:
|
||||||
|
case AzureQueryType.WorkspacesQuery:
|
||||||
setRequireSubscription(true);
|
setRequireSubscription(true);
|
||||||
break;
|
break;
|
||||||
case AzureQueryType.NamespacesQuery:
|
case AzureQueryType.NamespacesQuery:
|
||||||
@ -71,6 +81,12 @@ const VariableEditor = (props: Props) => {
|
|||||||
setHasResourceGroup(true);
|
setHasResourceGroup(true);
|
||||||
setHasNamespace(true);
|
setHasNamespace(true);
|
||||||
break;
|
break;
|
||||||
|
case AzureQueryType.MetricNamesQuery:
|
||||||
|
setRequireSubscription(true);
|
||||||
|
setRequireResourceGroup(true);
|
||||||
|
setRequireNamespace(true);
|
||||||
|
setRequireResource(true);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}, [queryType]);
|
}, [queryType]);
|
||||||
|
|
||||||
@ -111,6 +127,15 @@ const VariableEditor = (props: Props) => {
|
|||||||
}
|
}
|
||||||
}, [datasource, subscription, resourceGroup]);
|
}, [datasource, subscription, resourceGroup]);
|
||||||
|
|
||||||
|
const namespace = (typeof query === 'object' && query.namespace) || '';
|
||||||
|
useEffect(() => {
|
||||||
|
if (subscription) {
|
||||||
|
datasource.getResourceNames(subscription, resourceGroup, namespace).then((rgs) => {
|
||||||
|
setResources(rgs.map((s) => ({ label: s.text, value: s.value })));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [datasource, subscription, resourceGroup, namespace]);
|
||||||
|
|
||||||
if (typeof query === 'string') {
|
if (typeof query === 'string') {
|
||||||
// still migrating the query
|
// still migrating the query
|
||||||
return null;
|
return null;
|
||||||
@ -148,6 +173,13 @@ const VariableEditor = (props: Props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onChangeResource = (selectableValue: SelectableValue) => {
|
||||||
|
onChange({
|
||||||
|
...query,
|
||||||
|
resource: selectableValue.value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const onLogsQueryChange = (queryChange: AzureMonitorQuery) => {
|
const onLogsQueryChange = (queryChange: AzureMonitorQuery) => {
|
||||||
onChange(queryChange);
|
onChange(queryChange);
|
||||||
};
|
};
|
||||||
@ -198,27 +230,46 @@ const VariableEditor = (props: Props) => {
|
|||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
)}
|
)}
|
||||||
{hasResourceGroup && (
|
{(requireResourceGroup || hasResourceGroup) && (
|
||||||
<InlineField label="Select Resource Group" labelWidth={20}>
|
<InlineField label="Select resource group" labelWidth={20}>
|
||||||
<Select
|
<Select
|
||||||
aria-label="select resource group"
|
aria-label="select resource group"
|
||||||
onChange={onChangeResourceGroup}
|
onChange={onChangeResourceGroup}
|
||||||
options={resourceGroups.concat(variableOptionGroup, removeOption)}
|
options={
|
||||||
|
requireResourceGroup
|
||||||
|
? resourceGroups.concat(variableOptionGroup)
|
||||||
|
: resourceGroups.concat(variableOptionGroup, removeOption)
|
||||||
|
}
|
||||||
width={25}
|
width={25}
|
||||||
value={query.resourceGroup}
|
value={query.resourceGroup}
|
||||||
placeholder="Optional"
|
placeholder={requireResourceGroup ? '' : 'Optional'}
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
)}
|
)}
|
||||||
{hasNamespace && (
|
{(requireNamespace || hasNamespace) && (
|
||||||
<InlineField label="Select Namespace" labelWidth={20}>
|
<InlineField label="Select namespace" labelWidth={20}>
|
||||||
<Select
|
<Select
|
||||||
aria-label="select namespace"
|
aria-label="select namespace"
|
||||||
onChange={onChangeNamespace}
|
onChange={onChangeNamespace}
|
||||||
options={namespaces.concat(variableOptionGroup, removeOption)}
|
options={
|
||||||
|
requireNamespace
|
||||||
|
? namespaces.concat(variableOptionGroup)
|
||||||
|
: namespaces.concat(variableOptionGroup, removeOption)
|
||||||
|
}
|
||||||
width={25}
|
width={25}
|
||||||
value={query.namespace}
|
value={query.namespace}
|
||||||
placeholder="Optional"
|
placeholder={requireNamespace ? '' : 'Optional'}
|
||||||
|
/>
|
||||||
|
</InlineField>
|
||||||
|
)}
|
||||||
|
{requireResource && (
|
||||||
|
<InlineField label="Select resource" labelWidth={20}>
|
||||||
|
<Select
|
||||||
|
aria-label="select resource"
|
||||||
|
onChange={onChangeResource}
|
||||||
|
options={resources.concat(variableOptionGroup)}
|
||||||
|
width={25}
|
||||||
|
value={query.resource}
|
||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
)}
|
)}
|
||||||
|
@ -170,6 +170,15 @@ export default class Datasource extends DataSourceWithBackend<AzureMonitorQuery,
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMetricNames(subscriptionId: string, resourceGroup: string, metricDefinition: string, resourceName: string) {
|
||||||
|
return this.azureMonitorDatasource.getMetricNames({
|
||||||
|
subscription: subscriptionId,
|
||||||
|
resourceGroup,
|
||||||
|
metricDefinition,
|
||||||
|
resourceName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/*Azure Log Analytics */
|
/*Azure Log Analytics */
|
||||||
getAzureLogAnalyticsWorkspaces(subscriptionId: string) {
|
getAzureLogAnalyticsWorkspaces(subscriptionId: string) {
|
||||||
return this.azureLogAnalyticsDatasource.getWorkspaces(subscriptionId);
|
return this.azureLogAnalyticsDatasource.getWorkspaces(subscriptionId);
|
||||||
|
@ -10,6 +10,8 @@ export enum AzureQueryType {
|
|||||||
ResourceGroupsQuery = 'Azure Resource Groups',
|
ResourceGroupsQuery = 'Azure Resource Groups',
|
||||||
NamespacesQuery = 'Azure Namespaces',
|
NamespacesQuery = 'Azure Namespaces',
|
||||||
ResourceNamesQuery = 'Azure Resource Names',
|
ResourceNamesQuery = 'Azure Resource Names',
|
||||||
|
MetricNamesQuery = 'Azure Metric Names',
|
||||||
|
WorkspacesQuery = 'Azure Workspaces',
|
||||||
/** Deprecated */
|
/** Deprecated */
|
||||||
GrafanaTemplateVariableFn = 'Grafana Template Variable Function',
|
GrafanaTemplateVariableFn = 'Grafana Template Variable Function',
|
||||||
}
|
}
|
||||||
@ -34,6 +36,7 @@ export interface AzureMonitorQuery extends DataQuery {
|
|||||||
/** Template variables params */
|
/** Template variables params */
|
||||||
resourceGroup?: string;
|
resourceGroup?: string;
|
||||||
namespace?: string;
|
namespace?: string;
|
||||||
|
resource?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -239,7 +239,7 @@ export interface LegacyAzureGetMetricNamespacesQuery {
|
|||||||
|
|
||||||
export interface AzureGetMetricNamesQuery {
|
export interface AzureGetMetricNamesQuery {
|
||||||
resourceUri: string;
|
resourceUri: string;
|
||||||
metricNamespace: string;
|
metricNamespace?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LegacyAzureGetMetricNamesQuery {
|
export interface LegacyAzureGetMetricNamesQuery {
|
||||||
@ -247,7 +247,7 @@ export interface LegacyAzureGetMetricNamesQuery {
|
|||||||
resourceGroup: string;
|
resourceGroup: string;
|
||||||
metricDefinition: string;
|
metricDefinition: string;
|
||||||
resourceName: string;
|
resourceName: string;
|
||||||
metricNamespace: string;
|
metricNamespace?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AzureGetMetricMetadataQuery {
|
export interface AzureGetMetricMetadataQuery {
|
||||||
|
@ -605,5 +605,54 @@ describe('VariableSupport', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can fetch metric names', (done) => {
|
||||||
|
const expectedResults = ['test'];
|
||||||
|
const variableSupport = new VariableSupport(
|
||||||
|
createMockDatasource({
|
||||||
|
getMetricNames: jest.fn().mockResolvedValueOnce(expectedResults),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const mockRequest = {
|
||||||
|
targets: [
|
||||||
|
{
|
||||||
|
refId: 'A',
|
||||||
|
queryType: AzureQueryType.MetricNamesQuery,
|
||||||
|
subscription: 'sub',
|
||||||
|
resourceGroup: 'rg',
|
||||||
|
namespace: 'ns',
|
||||||
|
resource: 'rn',
|
||||||
|
} as AzureMonitorQuery,
|
||||||
|
],
|
||||||
|
} as DataQueryRequest<AzureMonitorQuery>;
|
||||||
|
const observables = variableSupport.query(mockRequest);
|
||||||
|
observables.subscribe((result: DataQueryResponseData) => {
|
||||||
|
expect(result.data[0].source).toEqual(expectedResults);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can fetch workspaces', (done) => {
|
||||||
|
const expectedResults = ['test'];
|
||||||
|
const variableSupport = new VariableSupport(
|
||||||
|
createMockDatasource({
|
||||||
|
getAzureLogAnalyticsWorkspaces: jest.fn().mockResolvedValueOnce(expectedResults),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const mockRequest = {
|
||||||
|
targets: [
|
||||||
|
{
|
||||||
|
refId: 'A',
|
||||||
|
queryType: AzureQueryType.WorkspacesQuery,
|
||||||
|
subscription: 'sub',
|
||||||
|
} as AzureMonitorQuery,
|
||||||
|
],
|
||||||
|
} as DataQueryRequest<AzureMonitorQuery>;
|
||||||
|
const observables = variableSupport.query(mockRequest);
|
||||||
|
observables.subscribe((result: DataQueryResponseData) => {
|
||||||
|
expect(result.data[0].source).toEqual(expectedResults);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -61,6 +61,25 @@ export class VariableSupport extends CustomVariableSupport<DataSource, AzureMoni
|
|||||||
data: rgs?.length ? [toDataFrame(rgs)] : [],
|
data: rgs?.length ? [toDataFrame(rgs)] : [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
case AzureQueryType.MetricNamesQuery:
|
||||||
|
if (queryObj.subscription && queryObj.resourceGroup && queryObj.namespace && queryObj.resource) {
|
||||||
|
const rgs = await this.datasource.getMetricNames(
|
||||||
|
queryObj.subscription,
|
||||||
|
queryObj.resourceGroup,
|
||||||
|
queryObj.namespace,
|
||||||
|
queryObj.resource
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
data: rgs?.length ? [toDataFrame(rgs)] : [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case AzureQueryType.WorkspacesQuery:
|
||||||
|
if (queryObj.subscription) {
|
||||||
|
const rgs = await this.datasource.getAzureLogAnalyticsWorkspaces(queryObj.subscription);
|
||||||
|
return {
|
||||||
|
data: rgs?.length ? [toDataFrame(rgs)] : [],
|
||||||
|
};
|
||||||
|
}
|
||||||
case AzureQueryType.GrafanaTemplateVariableFn:
|
case AzureQueryType.GrafanaTemplateVariableFn:
|
||||||
if (queryObj.grafanaTemplateVariableFn) {
|
if (queryObj.grafanaTemplateVariableFn) {
|
||||||
const templateVariablesResults = await this.callGrafanaTemplateVariableFn(
|
const templateVariablesResults = await this.callGrafanaTemplateVariableFn(
|
||||||
|
Loading…
Reference in New Issue
Block a user