diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 82604409275..1f5d5f25b5e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -455,6 +455,7 @@ playwright.config.ts @grafana/plugins-platform-frontend # public folder +/public/app/api/ @grafana/grafana-frontend-platform /public/app/core/ @grafana/grafana-frontend-platform /public/app/core/components/TimePicker/ @grafana/grafana-frontend-platform /public/app/core/components/Layers/ @grafana/dataviz-squad diff --git a/public/app/api/utils.ts b/public/app/api/utils.ts new file mode 100644 index 00000000000..51ba395ad43 --- /dev/null +++ b/public/app/api/utils.ts @@ -0,0 +1,3 @@ +import { config } from '@grafana/runtime'; + +export const getAPINamespace = () => config.namespace; diff --git a/public/app/features/alerting/unified/components/contact-points/useContactPoints.ts b/public/app/features/alerting/unified/components/contact-points/useContactPoints.ts index a052f34013e..314a64aa852 100644 --- a/public/app/features/alerting/unified/components/contact-points/useContactPoints.ts +++ b/public/app/features/alerting/unified/components/contact-points/useContactPoints.ts @@ -12,17 +12,14 @@ import { ComGithubGrafanaGrafanaPkgApisAlertingNotificationsV0Alpha1Receiver } f import { BaseAlertmanagerArgs, Skippable } from 'app/features/alerting/unified/types/hooks'; import { cloudNotifierTypes } from 'app/features/alerting/unified/utils/cloud-alertmanager-notifier-types'; import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource'; -import { - getK8sNamespace, - isK8sEntityProvisioned, - shouldUseK8sApi, -} from 'app/features/alerting/unified/utils/k8s/utils'; +import { isK8sEntityProvisioned, shouldUseK8sApi } from 'app/features/alerting/unified/utils/k8s/utils'; import { GrafanaManagedContactPoint, GrafanaManagedReceiverConfig, Receiver, } from 'app/plugins/datasource/alertmanager/types'; +import { getAPINamespace } from '../../../../../api/utils'; import { alertmanagerApi } from '../../api/alertmanagerApi'; import { onCallApi } from '../../api/onCallApi'; import { useAsync } from '../../hooks/useAsync'; @@ -117,7 +114,7 @@ const useK8sContactPoints = (...[hookParams, queryOptions]: Parameters { - const namespace = getK8sNamespace(); + const namespace = getAPINamespace(); const useK8sApi = shouldUseK8sApi(GRAFANA_RULES_SOURCE_NAME); const grafanaResponse = useGetContactPointsListQuery(undefined, { @@ -239,7 +236,7 @@ const useGetGrafanaContactPoint = ( { name }: { name: string }, queryOptions?: Parameters[1] ) => { - const namespace = getK8sNamespace(); + const namespace = getAPINamespace(); const useK8sApi = shouldUseK8sApi(GRAFANA_RULES_SOURCE_NAME); const k8sResponse = useReadNamespacedReceiverQuery( @@ -314,7 +311,7 @@ export function useDeleteContactPoint({ alertmanager }: BaseAlertmanagerArgs) { const [deleteReceiver] = useDeleteNamespacedReceiverMutation(); const deleteFromK8sAPI = useAsync(async ({ name, resourceVersion }: DeleteContactPointArgs) => { - const namespace = getK8sNamespace(); + const namespace = getAPINamespace(); await deleteReceiver({ name, namespace, @@ -407,7 +404,7 @@ export const useCreateContactPoint = ({ alertmanager }: BaseAlertmanagerArgs) => ? await createOnCallIntegrations(contactPoint) : contactPoint; - const namespace = getK8sNamespace(); + const namespace = getAPINamespace(); const contactPointToUse = grafanaContactPointToK8sReceiver(contactPointWithMaybeOnCall); return createGrafanaContactPoint({ @@ -455,7 +452,7 @@ export const useUpdateContactPoint = ({ alertmanager }: BaseAlertmanagerArgs) => ? await createOnCallIntegrations(contactPoint) : contactPoint; - const namespace = getK8sNamespace(); + const namespace = getAPINamespace(); const contactPointToUse = grafanaContactPointToK8sReceiver(receiverWithPotentialOnCall, id, resourceVersion); return replaceGrafanaContactPoint({ diff --git a/public/app/features/alerting/unified/components/contact-points/useNotificationTemplates.ts b/public/app/features/alerting/unified/components/contact-points/useNotificationTemplates.ts index 160a28001a6..91739aeca61 100644 --- a/public/app/features/alerting/unified/components/contact-points/useNotificationTemplates.ts +++ b/public/app/features/alerting/unified/components/contact-points/useNotificationTemplates.ts @@ -1,6 +1,7 @@ import { useEffect } from 'react'; import { Validate } from 'react-hook-form'; +import { getAPINamespace } from '../../../../../api/utils'; import { AlertManagerCortexConfig } from '../../../../../plugins/datasource/alertmanager/types'; import { alertmanagerApi } from '../../api/alertmanagerApi'; import { templatesApi } from '../../api/templateApi'; @@ -16,7 +17,7 @@ import { updateNotificationTemplateAction, } from '../../reducers/alertmanager/notificationTemplates'; import { K8sAnnotations, PROVENANCE_NONE } from '../../utils/k8s/constants'; -import { getAnnotation, getK8sNamespace, shouldUseK8sApi } from '../../utils/k8s/utils'; +import { getAnnotation, shouldUseK8sApi } from '../../utils/k8s/utils'; import { ensureDefine } from '../../utils/templates'; import { TemplateFormValues } from '../receivers/TemplateForm'; @@ -46,7 +47,7 @@ export function useNotificationTemplates({ alertmanager }: BaseAlertmanagerArgs) const k8sApiSupported = shouldUseK8sApi(alertmanager); const k8sApiTemplatesRequestState = useListNamespacedTemplateGroupQuery( - { namespace: getK8sNamespace() }, + { namespace: getAPINamespace() }, { skip: !k8sApiSupported, selectFromResult: (state) => ({ @@ -131,7 +132,7 @@ export function useGetNotificationTemplate({ alertmanager, uid }: GetTemplatePar // What are pros and cons of each? useEffect(() => { if (k8sApiSupported) { - fetchTemplate({ namespace: getK8sNamespace(), name: uid }); + fetchTemplate({ namespace: getAPINamespace(), name: uid }); } else { fetchAmConfig(alertmanager); } @@ -164,7 +165,7 @@ export function useCreateNotificationTemplate({ alertmanager }: BaseAlertmanager const content = ensureDefine(templateValues.title, templateValues.content); return createNamespacedTemplateGroup({ - namespace: getK8sNamespace(), + namespace: getAPINamespace(), comGithubGrafanaGrafanaPkgApisAlertingNotificationsV0Alpha1TemplateGroup: { spec: { title: templateValues.title, content }, metadata: {}, @@ -195,7 +196,7 @@ export function useUpdateNotificationTemplate({ alertmanager }: BaseAlertmanager const content = ensureDefine(patch.title, patch.content); return replaceNamespacedTemplateGroup({ - namespace: getK8sNamespace(), + namespace: getAPINamespace(), name: template.uid, comGithubGrafanaGrafanaPkgApisAlertingNotificationsV0Alpha1TemplateGroup: { spec: { title: patch.title, content }, @@ -218,7 +219,7 @@ export function useDeleteNotificationTemplate({ alertmanager }: BaseAlertmanager const deleteUsingK8sApi = useAsync(({ uid }: { uid: string }) => { return deleteNamespacedTemplateGroup({ - namespace: getK8sNamespace(), + namespace: getAPINamespace(), name: uid, ioK8SApimachineryPkgApisMetaV1DeleteOptions: {}, }).unwrap(); diff --git a/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.tsx b/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.tsx index dd365218c47..fb873f967b3 100644 --- a/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.tsx +++ b/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.tsx @@ -10,13 +10,10 @@ import { import { BaseAlertmanagerArgs, Skippable } from 'app/features/alerting/unified/types/hooks'; import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource'; import { PROVENANCE_NONE } from 'app/features/alerting/unified/utils/k8s/constants'; -import { - getK8sNamespace, - isK8sEntityProvisioned, - shouldUseK8sApi, -} from 'app/features/alerting/unified/utils/k8s/utils'; +import { isK8sEntityProvisioned, shouldUseK8sApi } from 'app/features/alerting/unified/utils/k8s/utils'; import { MuteTimeInterval } from 'app/plugins/datasource/alertmanager/types'; +import { getAPINamespace } from '../../../../../api/utils'; import { useAsync } from '../../hooks/useAsync'; import { useProduceNewAlertmanagerConfiguration } from '../../hooks/useProduceNewAlertmanagerConfig'; import { @@ -114,7 +111,7 @@ export const useMuteTimings = ({ alertmanager, skip }: BaseAlertmanagerArgs & Sk return; } if (useK8sApi) { - const namespace = getK8sNamespace(); + const namespace = getAPINamespace(); getGrafanaTimeIntervals({ namespace }); } else { getAlertmanagerTimeIntervals(alertmanager); @@ -140,7 +137,7 @@ export const useCreateMuteTiming = ({ alertmanager }: BaseAlertmanagerArgs) => { const [updateConfiguration] = useProduceNewAlertmanagerConfiguration(); const addToK8sAPI = useAsync(({ interval }: CreateUpdateMuteTimingArgs) => { - const namespace = getK8sNamespace(); + const namespace = getAPINamespace(); return createGrafanaTimeInterval({ namespace, @@ -202,7 +199,7 @@ export const useGetMuteTiming = ({ alertmanager, name: nameToFind }: BaseAlertma useEffect(() => { if (useK8sApi) { - const namespace = getK8sNamespace(); + const namespace = getAPINamespace(); getGrafanaTimeInterval({ namespace, fieldSelector: `spec.name=${nameToFind}` }, true); } else { getAlertmanagerTimeInterval(alertmanager, true); @@ -228,7 +225,7 @@ export const useUpdateMuteTiming = ({ alertmanager }: BaseAlertmanagerArgs) => { const updateToK8sAPI = useAsync( async ({ interval, originalName }: CreateUpdateMuteTimingArgs & { originalName: string }) => { - const namespace = getK8sNamespace(); + const namespace = getAPINamespace(); return replaceGrafanaTimeInterval({ name: originalName, @@ -267,7 +264,7 @@ export const useDeleteMuteTiming = ({ alertmanager }: BaseAlertmanagerArgs) => { }); const deleteFromK8sAPI = useAsync(async ({ name }: DeleteMuteTimingArgs) => { - const namespace = getK8sNamespace(); + const namespace = getAPINamespace(); await deleteGrafanaTimeInterval({ name, namespace, diff --git a/public/app/features/alerting/unified/components/notification-policies/useNotificationPolicyRoute.ts b/public/app/features/alerting/unified/components/notification-policies/useNotificationPolicyRoute.ts index 4b1e2243c8e..f927fc49d70 100644 --- a/public/app/features/alerting/unified/components/notification-policies/useNotificationPolicyRoute.ts +++ b/public/app/features/alerting/unified/components/notification-policies/useNotificationPolicyRoute.ts @@ -4,6 +4,7 @@ import memoize from 'micro-memoize'; import { BaseAlertmanagerArgs, Skippable } from 'app/features/alerting/unified/types/hooks'; import { MatcherOperator, ROUTES_META_SYMBOL, Route } from 'app/plugins/datasource/alertmanager/types'; +import { getAPINamespace } from '../../../../../api/utils'; import { alertmanagerApi } from '../../api/alertmanagerApi'; import { useAsync } from '../../hooks/useAsync'; import { useProduceNewAlertmanagerConfiguration } from '../../hooks/useProduceNewAlertmanagerConfig'; @@ -21,7 +22,7 @@ import { import { FormAmRoute } from '../../types/amroutes'; import { addUniqueIdentifierToRoute } from '../../utils/amroutes'; import { PROVENANCE_NONE, ROOT_ROUTE_NAME } from '../../utils/k8s/constants'; -import { getK8sNamespace, isK8sEntityProvisioned, shouldUseK8sApi } from '../../utils/k8s/utils'; +import { isK8sEntityProvisioned, shouldUseK8sApi } from '../../utils/k8s/utils'; import { INHERITABLE_KEYS, InheritableProperties } from '../../utils/notification-policies'; import { InsertPosition, @@ -45,7 +46,7 @@ export const useNotificationPolicyRoute = ({ alertmanager }: BaseAlertmanagerArg const k8sApiSupported = shouldUseK8sApi(alertmanager); const k8sRouteQuery = useListNamespacedRoutingTreeQuery( - { namespace: getK8sNamespace() }, + { namespace: getAPINamespace() }, { skip: skip || !k8sApiSupported, selectFromResult: (result) => { @@ -92,7 +93,7 @@ export function useUpdateExistingNotificationPolicy({ alertmanager }: BaseAlertm const [listNamespacedRoutingTree] = useLazyListNamespacedRoutingTreeQuery(); const updateUsingK8sApi = useAsync(async (update: Partial) => { - const namespace = getK8sNamespace(); + const namespace = getAPINamespace(); const result = await listNamespacedRoutingTree({ namespace }); const [rootTree] = result.data ? k8sRoutesToRoutesMemoized(result.data.items) : []; @@ -128,7 +129,7 @@ export function useDeleteNotificationPolicy({ alertmanager }: BaseAlertmanagerAr const [updatedNamespacedRoute] = useReplaceNamespacedRoutingTreeMutation(); const deleteFromK8sApi = useAsync(async (id: string) => { - const namespace = getK8sNamespace(); + const namespace = getAPINamespace(); const result = await listNamespacedRoutingTree({ namespace }); const [rootTree] = result.data ? k8sRoutesToRoutesMemoized(result.data.items) : []; @@ -173,7 +174,7 @@ export function useAddNotificationPolicy({ alertmanager }: BaseAlertmanagerArgs) referenceRouteIdentifier: string; insertPosition: InsertPosition; }) => { - const namespace = getK8sNamespace(); + const namespace = getAPINamespace(); const result = await listNamespacedRoutingTree({ namespace }); const [rootTree] = result.data ? k8sRoutesToRoutesMemoized(result.data.items) : []; diff --git a/public/app/features/alerting/unified/home/Insights.tsx b/public/app/features/alerting/unified/home/Insights.tsx index f98cd51622e..9d85797751b 100644 --- a/public/app/features/alerting/unified/home/Insights.tsx +++ b/public/app/features/alerting/unified/home/Insights.tsx @@ -16,7 +16,7 @@ import { } from '@grafana/scenes'; import { Icon, Text, Tooltip } from '@grafana/ui'; -import { config } from '../../../../core/config'; +import { getAPINamespace } from '../../../../api/utils'; import { SectionFooter } from '../insights/SectionFooter'; import { SectionSubheader } from '../insights/SectionSubheader'; import { getActiveGrafanaAlertsScene } from '../insights/grafana/Active'; @@ -95,7 +95,7 @@ export const PANEL_STYLES = { minHeight: 300 }; const THIS_WEEK_TIME_RANGE = new SceneTimeRange({ from: 'now-1w', to: 'now' }); -const namespace = config.namespace; +const namespace = getAPINamespace(); export const INSTANCE_ID = namespace.includes('stacks-') ? namespace.replace('stacks-', '') : undefined; diff --git a/public/app/features/alerting/unified/utils/k8s/utils.ts b/public/app/features/alerting/unified/utils/k8s/utils.ts index 2857552ecc5..0aec7c1dd52 100644 --- a/public/app/features/alerting/unified/utils/k8s/utils.ts +++ b/public/app/features/alerting/unified/utils/k8s/utils.ts @@ -3,11 +3,6 @@ import { IoK8SApimachineryPkgApisMetaV1ObjectMeta } from 'app/features/alerting/ import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource'; import { K8sAnnotations, PROVENANCE_NONE } from 'app/features/alerting/unified/utils/k8s/constants'; -/** - * Get the correct namespace to use when using the K8S API. - */ -export const getK8sNamespace = () => config.namespace; - /** * Should we call the kubernetes-style API for managing alertmanager entities? * diff --git a/public/app/features/apiserver/client.ts b/public/app/features/apiserver/client.ts index ba647d4cf6c..90a5004b8b0 100644 --- a/public/app/features/apiserver/client.ts +++ b/public/app/features/apiserver/client.ts @@ -3,6 +3,8 @@ import { Observable, from, retry, catchError, filter, map, mergeMap } from 'rxjs import { config, getBackendSrv } from '@grafana/runtime'; import { contextSrv } from 'app/core/core'; +import { getAPINamespace } from '../../api/utils'; + import { ListOptions, ListOptionsFieldSelector, @@ -29,7 +31,7 @@ export class ScopedResourceClient implements readonly url: string; constructor(gvr: GroupVersionResource, namespaced = true) { - const ns = namespaced ? `namespaces/${config.namespace}/` : ''; + const ns = namespaced ? `namespaces/${getAPINamespace()}/` : ''; this.url = `/apis/${gvr.group}/${gvr.version}/${ns}${gvr.resource}`; } diff --git a/public/app/features/dashboard/services/SnapshotSrv.ts b/public/app/features/dashboard/services/SnapshotSrv.ts index 5467542ab2b..1ca4894de22 100644 --- a/public/app/features/dashboard/services/SnapshotSrv.ts +++ b/public/app/features/dashboard/services/SnapshotSrv.ts @@ -4,6 +4,8 @@ import { config, getBackendSrv, FetchResponse } from '@grafana/runtime'; import { contextSrv } from 'app/core/core'; import { DashboardDataDTO, DashboardDTO } from 'app/types'; +import { getAPINamespace } from '../../../api/utils'; + // Used in the snapshot list export interface Snapshot { key: string; @@ -91,7 +93,7 @@ class K8sAPI implements DashboardSnapshotSrv { readonly url: string; constructor() { - this.url = `/apis/${this.apiVersion}/namespaces/${config.namespace}/dashboardsnapshots`; + this.url = `/apis/${this.apiVersion}/namespaces/${getAPINamespace()}/dashboardsnapshots`; } async create(cmd: SnapshotCreateCommand) { diff --git a/public/app/features/query-library/api/query.ts b/public/app/features/query-library/api/query.ts index c2ce2bea47c..610c1556387 100644 --- a/public/app/features/query-library/api/query.ts +++ b/public/app/features/query-library/api/query.ts @@ -1,9 +1,10 @@ import { BaseQueryFn } from '@reduxjs/toolkit/query/react'; import { lastValueFrom } from 'rxjs'; -import { config } from '@grafana/runtime'; import { BackendSrvRequest, getBackendSrv, isFetchError } from '@grafana/runtime/src/services/backendSrv'; +import { getAPINamespace } from '../../../api/utils'; + /** * @alpha */ @@ -16,14 +17,12 @@ export enum QueryTemplateKinds { QueryTemplate = 'QueryTemplate', } -export const getK8sNamespace = () => config.namespace; - /** * Query Library is an experimental feature. API (including the URL path) will likely change. * * @alpha */ -export const BASE_URL = `/apis/${API_VERSION}/namespaces/${getK8sNamespace()}`; +export const BASE_URL = `/apis/${API_VERSION}/namespaces/${getAPINamespace()}`; interface QueryLibraryBackendRequest extends BackendSrvRequest { body?: BackendSrvRequest['data']; diff --git a/public/app/features/query-library/api/user.ts b/public/app/features/query-library/api/user.ts index 640b04aa1dd..6b8ba4c9437 100644 --- a/public/app/features/query-library/api/user.ts +++ b/public/app/features/query-library/api/user.ts @@ -1,6 +1,7 @@ import { getBackendSrv } from '@grafana/runtime'; -import { getK8sNamespace } from './query'; +import { getAPINamespace } from '../../../api/utils'; + import { UserDataQueryResponse } from './types'; /** @@ -11,7 +12,7 @@ export const API_VERSION = 'iam.grafana.app/v0alpha1'; /** * @alpha */ -const BASE_URL = `apis/${API_VERSION}/namespaces/${getK8sNamespace()}/display`; +const BASE_URL = `apis/${API_VERSION}/namespaces/${getAPINamespace()}/display`; export async function getUserInfo(url?: string): Promise { const userInfo = await getBackendSrv().get(`${BASE_URL}${url}`); diff --git a/public/app/features/scopes/internal/api.ts b/public/app/features/scopes/internal/api.ts index b1f1ceaf869..1b0dae4cce9 100644 --- a/public/app/features/scopes/internal/api.ts +++ b/public/app/features/scopes/internal/api.ts @@ -1,13 +1,15 @@ import { Scope, ScopeDashboardBinding, ScopeNode, ScopeSpec } from '@grafana/data'; -import { config, getBackendSrv } from '@grafana/runtime'; +import { getBackendSrv } from '@grafana/runtime'; import { ScopedResourceClient } from 'app/features/apiserver/client'; +import { getAPINamespace } from '../../../api/utils'; + import { NodeReason, NodesMap, SelectedScope, TreeScope } from './types'; import { getBasicScope, mergeScopes } from './utils'; const group = 'scope.grafana.app'; const version = 'v0alpha1'; -const namespace = config.namespace ?? 'default'; +const namespace = getAPINamespace(); const nodesEndpoint = `/apis/${group}/${version}/namespaces/${namespace}/find/scope_node_children`; const dashboardsEndpoint = `/apis/${group}/${version}/namespaces/${namespace}/find/scope_dashboard_bindings`; diff --git a/public/app/features/search/service/unified.ts b/public/app/features/search/service/unified.ts index 3ed44146c35..700cf566314 100644 --- a/public/app/features/search/service/unified.ts +++ b/public/app/features/search/service/unified.ts @@ -4,6 +4,8 @@ import { DataFrame, DataFrameView, getDisplayProcessor, SelectableValue, toDataF import { config, getBackendSrv } from '@grafana/runtime'; import { TermCount } from 'app/core/components/TagFilter/TagFilter'; +import { getAPINamespace } from '../../../api/utils'; + import { DashboardQueryResult, GrafanaSearcher, @@ -18,7 +20,7 @@ import { replaceCurrentFolderQuery } from './utils'; // and that it can not serve any search requests. We are temporarily using the old SQL Search API as a fallback when that happens. const loadingFrameName = 'Loading'; -const searchURI = `apis/dashboard.grafana.app/v0alpha1/namespaces/${config.namespace}/search`; +const searchURI = `apis/dashboard.grafana.app/v0alpha1/namespaces/${getAPINamespace()}/search`; export type SearchHit = { resource: string; // dashboards | folders