Prometheus: Use frontend package in Prometheus DS with a feature toggle (#84397)

* add feature toggle usePrometheusFrontendPackage

* add feature toggle logic to Prometheus module

* use config editor with package and remove configOverhaul feature toggle

* update betterer because we will be removing other files as we replace with files from @grafana/prometheus

* fix exemplar ds picker selector

* add more description to ts-ignore

* remove go.work.sum change

* copy go.work.sum from main

* update go.work.sum after talking with ismail

* put back the promlib entry

---------

Co-authored-by: ismail simsek <ismailsimsek09@gmail.com>
This commit is contained in:
Brendan O'Handley 2024-03-22 19:47:53 -05:00 committed by GitHub
parent cdb64cb7eb
commit d084595211
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 2171 additions and 1956 deletions

View File

@ -5291,6 +5291,12 @@ exports[`better eslint`] = {
[0, 0, 0, "Styles should be written using objects.", "18"],
[0, 0, 0, "Styles should be written using objects.", "19"]
],
"public/app/plugins/datasource/prometheus/configuration/ConfigEditorPackage.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
[0, 0, 0, "Unexpected any. Specify a different type.", "3"]
],
"public/app/plugins/datasource/prometheus/configuration/ExemplarsSettings.tsx:5381": [
[0, 0, 0, "Styles should be written using objects.", "0"]
],

View File

@ -173,6 +173,7 @@ Experimental features might be changed or removed without prior notice.
| `nodeGraphDotLayout` | Changed the layout algorithm for the node graph |
| `kubernetesAggregator` | Enable grafana aggregator |
| `expressionParser` | Enable new expression parser |
| `usePrometheusFrontendPackage` | Use the @grafana/prometheus frontend package in core Prometheus. |
## Development feature toggles

View File

@ -11,7 +11,7 @@ const addDataSource = () => {
e2e.components.DataSource.Prometheus.configPage.exemplarsAddButton().click();
e2e.components.DataSource.Prometheus.configPage.internalLinkSwitch().check({ force: true });
e2e.components.DataSource.Prometheus.configPage.connectionSettings().type('http://prom-url:9090');
e2e.components.DataSourcePicker.inputV2().click().should('have.focus');
cy.get('[data-testid="data-testid Data source picker select container"]').click();
cy.contains('gdev-tempo').scrollIntoView().should('be.visible').click();
},

View File

@ -409,6 +409,7 @@ github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586 h1:/of8Z8taCPft
github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586/go.mod h1:PGk3RjYHpxMM8HFPhKKo+vve3DdlPUELZLSDEFehPuU=
github.com/grafana/grafana-plugin-sdk-go v0.212.0/go.mod h1:qsI4ktDf0lig74u8SLPJf9zRdVxWV/W4Wi+Ox6gifgs=
github.com/grafana/grafana-plugin-sdk-go v0.215.0/go.mod h1:nBsh3jRItKQUXDF2BQkiQCPxqrsSQeb+7hiFyJTO1RE=
github.com/grafana/grafana-plugin-sdk-go v0.216.0/go.mod h1:FdvSvOliqpVLnytM7e89zCFyYPDE6VOn9SIjVQRvVxM=
github.com/grafana/grafana/pkg/promlib v0.0.3/go.mod h1:3El4NlsfALz8QQCbEGHGFvJUG+538QLMuALRhZ3pcoo=
github.com/grafana/grafana/pkg/promlib v0.0.4/go.mod h1:621zjsCaFtP7mqqaiMJRN9h3SXrywAMaIPkeHvq3jsk=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
@ -836,4 +837,4 @@ rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4=
rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0 h1:ucqkfpjg9WzSUubAO62csmucvxl4/JeW3F4I4909XkM=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0 h1:ucqkfpjg9WzSUubAO62csmucvxl4/JeW3F4I4909XkM=

View File

@ -175,4 +175,5 @@ export interface FeatureToggles {
betterPageScrolling?: boolean;
scopeFilters?: boolean;
ssoSettingsSAML?: boolean;
usePrometheusFrontendPackage?: boolean;
}

View File

@ -1174,6 +1174,13 @@ var (
HideFromDocs: true,
HideFromAdminPage: true,
},
{
Name: "usePrometheusFrontendPackage",
Description: "Use the @grafana/prometheus frontend package in core Prometheus.",
Stage: FeatureStageExperimental,
FrontendOnly: true,
Owner: grafanaObservabilityMetricsSquad,
},
}
)

View File

@ -156,3 +156,4 @@ groupByVariable,experimental,@grafana/dashboards-squad,false,false,false
betterPageScrolling,GA,@grafana/grafana-frontend-platform,false,false,true
scopeFilters,experimental,@grafana/dashboards-squad,false,false,false
ssoSettingsSAML,experimental,@grafana/identity-access-team,false,false,false
usePrometheusFrontendPackage,experimental,@grafana/observability-metrics,false,false,true

1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
156 betterPageScrolling GA @grafana/grafana-frontend-platform false false true
157 scopeFilters experimental @grafana/dashboards-squad false false false
158 ssoSettingsSAML experimental @grafana/identity-access-team false false false
159 usePrometheusFrontendPackage experimental @grafana/observability-metrics false false true

View File

@ -634,4 +634,8 @@ const (
// FlagSsoSettingsSAML
// Use the new SSO Settings API to configure the SAML connector
FlagSsoSettingsSAML = "ssoSettingsSAML"
// FlagUsePrometheusFrontendPackage
// Use the @grafana/prometheus frontend package in core Prometheus.
FlagUsePrometheusFrontendPackage = "usePrometheusFrontendPackage"
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,152 @@
import { css } from '@emotion/css';
import React from 'react';
import { SIGV4ConnectionConfig } from '@grafana/aws-sdk';
import { DataSourcePluginOptionsEditorProps, DataSourceSettings, GrafanaTheme2 } from '@grafana/data';
import { AdvancedHttpSettings, ConfigSection, DataSourceDescription } from '@grafana/experimental';
import { AlertingSettingsOverhaul, PromOptions, PromSettings } from '@grafana/prometheus';
import { config } from '@grafana/runtime';
import { Alert, FieldValidationMessage, useTheme2 } from '@grafana/ui';
import { AzureAuthSettings } from './AzureAuthSettings';
import { hasCredentials, setDefaultCredentials, resetCredentials } from './AzureCredentialsConfig';
import { DataSourcehttpSettingsOverhaul } from './DataSourceHttpSettingsOverhaulPackage';
export const PROM_CONFIG_LABEL_WIDTH = 30;
export type Props = DataSourcePluginOptionsEditorProps<PromOptions>;
export const ConfigEditor = (props: Props) => {
const { options, onOptionsChange } = props;
const azureAuthSettings = {
azureAuthSupported: config.azureAuthEnabled,
getAzureAuthEnabled: (config: DataSourceSettings<any, any>): boolean => hasCredentials(config),
setAzureAuthEnabled: (config: DataSourceSettings<any, any>, enabled: boolean) =>
enabled ? setDefaultCredentials(config) : resetCredentials(config),
azureSettingsUI: AzureAuthSettings,
};
const theme = useTheme2();
const styles = overhaulStyles(theme);
return (
<>
{options.access === 'direct' && (
<Alert title="Error" severity="error">
Browser access mode in the Prometheus data source is no longer available. Switch to server access mode.
</Alert>
)}
<DataSourceDescription
dataSourceName="Prometheus"
docsLink="https://grafana.com/docs/grafana/latest/datasources/prometheus/configure-prometheus-data-source/"
/>
<hr className={`${styles.hrTopSpace} ${styles.hrBottomSpace}`} />
<DataSourcehttpSettingsOverhaul
options={options}
onOptionsChange={onOptionsChange}
azureAuthSettings={azureAuthSettings}
sigV4AuthToggleEnabled={config.sigV4AuthEnabled}
renderSigV4Editor={
<SIGV4ConnectionConfig inExperimentalAuthComponent={true} {...props}></SIGV4ConnectionConfig>
}
secureSocksDSProxyEnabled={config.secureSocksDSProxyEnabled}
/>
<hr />
<ConfigSection
className={styles.advancedSettings}
title="Advanced settings"
description="Additional settings are optional settings that can be configured for more control over your data source."
>
<AdvancedHttpSettings
className={styles.advancedHTTPSettingsMargin}
config={options}
onChange={onOptionsChange}
/>
<AlertingSettingsOverhaul<PromOptions> options={options} onOptionsChange={onOptionsChange} />
<PromSettings options={options} onOptionsChange={onOptionsChange} />
</ConfigSection>
</>
);
};
/**
* Use this to return a url in a tooltip in a field. Don't forget to make the field interactive to be able to click on the tooltip
* @param url
* @returns
*/
export function docsTip(url?: string) {
const docsUrl = 'https://grafana.com/docs/grafana/latest/datasources/prometheus/#configure-the-data-source';
return (
<a href={url ? url : docsUrl} target="_blank" rel="noopener noreferrer">
Visit docs for more details here.
</a>
);
}
export const validateInput = (
input: string,
pattern: string | RegExp,
errorMessage?: string
): boolean | JSX.Element => {
const defaultErrorMessage = 'Value is not valid';
if (input && !input.match(pattern)) {
return <FieldValidationMessage>{errorMessage ? errorMessage : defaultErrorMessage}</FieldValidationMessage>;
} else {
return true;
}
};
export function overhaulStyles(theme: GrafanaTheme2) {
return {
additionalSettings: css({
marginBottom: '25px',
}),
secondaryGrey: css({
color: `${theme.colors.secondary.text}`,
opacity: '65%',
}),
inlineError: css({
margin: '0px 0px 4px 245px',
}),
switchField: css({
alignItems: 'center',
}),
sectionHeaderPadding: css({
paddingTop: '32px',
}),
sectionBottomPadding: css({
paddingBottom: '28px',
}),
subsectionText: css({
fontSize: '12px',
}),
hrBottomSpace: css({
marginBottom: '56px',
}),
hrTopSpace: css({
marginTop: '50px',
}),
textUnderline: css({
textDecoration: 'underline',
}),
versionMargin: css({
marginBottom: '12px',
}),
advancedHTTPSettingsMargin: css({
margin: '24px 0 8px 0',
}),
advancedSettings: css({
paddingTop: '32px',
}),
alertingTop: css({
marginTop: '40px !important',
}),
overhaulPageHeading: css({
fontWeight: '400',
}),
container: css({
maxwidth: '578',
}),
};
}

View File

@ -0,0 +1,175 @@
import React, { ReactElement, useState } from 'react';
import { DataSourceSettings } from '@grafana/data';
import { Auth, ConnectionSettings, convertLegacyAuthProps, AuthMethod } from '@grafana/experimental';
import { PromOptions, docsTip, overhaulStyles } from '@grafana/prometheus';
import { SecureSocksProxySettings, useTheme2 } from '@grafana/ui';
// NEED TO EXPORT THIS FROM GRAFANA/UI FOR EXTERNAL DS
import { AzureAuthSettings } from '@grafana/ui/src/components/DataSourceSettings/types';
type Props = {
options: DataSourceSettings<PromOptions, {}>;
onOptionsChange: (options: DataSourceSettings<PromOptions, {}>) => void;
azureAuthSettings: AzureAuthSettings;
sigV4AuthToggleEnabled: boolean | undefined;
renderSigV4Editor: React.ReactNode;
secureSocksDSProxyEnabled: boolean;
};
// these are not available yet in grafana
export type CustomMethodId = `custom-${string}`;
export type CustomMethod = {
id: CustomMethodId;
label: string;
description: string;
component: ReactElement;
};
export const DataSourcehttpSettingsOverhaul = (props: Props) => {
const {
options,
onOptionsChange,
azureAuthSettings,
sigV4AuthToggleEnabled,
renderSigV4Editor,
secureSocksDSProxyEnabled,
} = props;
const newAuthProps = convertLegacyAuthProps({
config: options,
onChange: onOptionsChange,
});
const theme = useTheme2();
const styles = overhaulStyles(theme);
// for custom auth methods sigV4 and azure auth
let customMethods: CustomMethod[] = [];
const [sigV4Selected, setSigV4Selected] = useState<boolean>(options.jsonData.sigV4Auth || false);
const sigV4Id = 'custom-sigV4Id';
const sigV4Option: CustomMethod = {
id: sigV4Id,
label: 'SigV4 auth',
description: 'This is SigV4 auth description',
component: <>{renderSigV4Editor}</>,
};
if (sigV4AuthToggleEnabled) {
customMethods.push(sigV4Option);
}
const azureAuthEnabled: boolean =
(azureAuthSettings?.azureAuthSupported && azureAuthSettings.getAzureAuthEnabled(options)) || false;
const [azureAuthSelected, setAzureAuthSelected] = useState<boolean>(azureAuthEnabled);
const azureAuthId = 'custom-azureAuthId';
const azureAuthOption: CustomMethod = {
id: azureAuthId,
label: 'Azure auth',
description: 'This is Azure auth description',
component: (
<>
{azureAuthSettings.azureSettingsUI && (
<azureAuthSettings.azureSettingsUI dataSourceConfig={options} onChange={onOptionsChange} />
)}
</>
),
};
// allow the option to show in the dropdown
if (azureAuthSettings?.azureAuthSupported) {
customMethods.push(azureAuthOption);
}
function returnSelectedMethod() {
if (sigV4Selected) {
return sigV4Id;
}
if (azureAuthSelected) {
return azureAuthId;
}
return newAuthProps.selectedMethod;
}
// Do we need this switch anymore? Update the language.
let urlTooltip;
switch (options.access) {
case 'direct':
urlTooltip = (
<>
Your access method is <em>Browser</em>, this means the URL needs to be accessible from the browser.
{docsTip()}
</>
);
break;
case 'proxy':
urlTooltip = (
<>
Your access method is <em>Server</em>, this means the URL needs to be accessible from the grafana
backend/server.
{docsTip()}
</>
);
break;
default:
urlTooltip = <>Specify a complete HTTP URL (for example http://your_server:8080) {docsTip()}</>;
}
return (
<>
<ConnectionSettings
urlPlaceholder="http://localhost:9090"
config={options}
onChange={onOptionsChange}
urlLabel="Prometheus server URL"
urlTooltip={urlTooltip}
/>
<hr className={`${styles.hrTopSpace} ${styles.hrBottomSpace}`} />
<Auth
{...newAuthProps}
customMethods={customMethods}
onAuthMethodSelect={(method) => {
// sigV4Id
if (sigV4AuthToggleEnabled) {
setSigV4Selected(method === sigV4Id);
}
// Azure
if (azureAuthSettings?.azureAuthSupported) {
setAzureAuthSelected(method === azureAuthId);
azureAuthSettings.setAzureAuthEnabled(options, method === azureAuthId);
}
onOptionsChange({
...options,
basicAuth: method === AuthMethod.BasicAuth,
withCredentials: method === AuthMethod.CrossSiteCredentials,
jsonData: {
...options.jsonData,
sigV4Auth: method === sigV4Id,
oauthPassThru: method === AuthMethod.OAuthForward,
},
});
}}
// If your method is selected pass its id to `selectedMethod`,
// otherwise pass the id from converted legacy data
selectedMethod={returnSelectedMethod()}
/>
<div className={styles.sectionBottomPadding} />
{secureSocksDSProxyEnabled && (
<>
<SecureSocksProxySettings options={options} onOptionsChange={onOptionsChange} />
<div className={styles.sectionBottomPadding} />
</>
)}
</>
);
};

View File

@ -1,11 +1,27 @@
import { DataSourcePlugin } from '@grafana/data';
import {
PrometheusDatasource as PrometheusDatasourcePackage,
PromQueryEditorByApp as PromQueryEditorByAppPackage,
PromCheatSheet as PromCheatSheetPackage,
} from '@grafana/prometheus';
import { config } from '@grafana/runtime';
import PromCheatSheet from './components/PromCheatSheet';
import PromQueryEditorByApp from './components/PromQueryEditorByApp';
import { ConfigEditor } from './configuration/ConfigEditor';
import { ConfigEditor as ConfigEditorPackage } from './configuration/ConfigEditorPackage';
import { PrometheusDatasource } from './datasource';
export const plugin = new DataSourcePlugin(PrometheusDatasource)
.setQueryEditor(PromQueryEditorByApp)
.setConfigEditor(ConfigEditor)
.setQueryEditorHelp(PromCheatSheet);
const usePackage = config.featureToggles.usePrometheusFrontendPackage;
const PrometheusDataSourceUsed = usePackage ? PrometheusDatasource : PrometheusDatasourcePackage;
const PromQueryEditorByAppUsed = usePackage ? PromQueryEditorByApp : PromQueryEditorByAppPackage;
const ConfigEditorUsed = usePackage ? ConfigEditor : ConfigEditorPackage;
const PromCheatSheetUsed = usePackage ? PromCheatSheet : PromCheatSheetPackage;
// @ts-ignore These type errors will be removed when we fully migrate to the @grafana/prometheus package
export const plugin = new DataSourcePlugin(PrometheusDataSourceUsed)
// @ts-ignore These type errors will be removed when we fully migrate to the @grafana/prometheus package
.setQueryEditor(PromQueryEditorByAppUsed)
.setConfigEditor(ConfigEditorUsed)
.setQueryEditorHelp(PromCheatSheetUsed);