Submit
Path:
~
/
/
usr
/
share
/
grafana
/
public
/
app
/
features
/
alerting
/
unified
/
hooks
/
File Content:
useAbilities.ts
import { useMemo } from 'react'; import { contextSrv, contextSrv as ctx } from 'app/core/services/context_srv'; import { AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types'; import { AccessControlAction } from 'app/types'; import { CombinedRule, RulesSource } from 'app/types/unified-alerting'; import { alertmanagerApi } from '../api/alertmanagerApi'; import { useAlertmanager } from '../state/AlertmanagerContext'; import { getInstancesPermissions, getNotificationsPermissions, getRulesPermissions } from '../utils/access-control'; import { GRAFANA_RULES_SOURCE_NAME } from '../utils/datasource'; import { isFederatedRuleGroup, isGrafanaRulerRule } from '../utils/rules'; import { useIsRuleEditable } from './useIsRuleEditable'; /** * These hooks will determine if * 1. the action is supported in the current context (alertmanager, alert rule or general context) * 2. user is allowed to perform actions based on their set of permissions / assigned role */ // this enum lists all of the available actions we can perform within the context of an alertmanager export enum AlertmanagerAction { // configuration ViewExternalConfiguration = 'view-external-configuration', UpdateExternalConfiguration = 'update-external-configuration', // contact points CreateContactPoint = 'create-contact-point', ViewContactPoint = 'view-contact-point', UpdateContactPoint = 'edit-contact-points', DeleteContactPoint = 'delete-contact-point', ExportContactPoint = 'export-contact-point', // notification templates CreateNotificationTemplate = 'create-notification-template', ViewNotificationTemplate = 'view-notification-template', UpdateNotificationTemplate = 'edit-notification-template', DeleteNotificationTemplate = 'delete-notification-template', DecryptSecrets = 'decrypt-secrets', // notification policies CreateNotificationPolicy = 'create-notification-policy', ViewNotificationPolicyTree = 'view-notification-policy-tree', UpdateNotificationPolicyTree = 'update-notification-policy-tree', DeleteNotificationPolicy = 'delete-notification-policy', ExportNotificationPolicies = 'export-notification-policies', ViewAutogeneratedPolicyTree = 'view-autogenerated-policy-tree', // silences – these cannot be deleted only "expired" (updated) CreateSilence = 'create-silence', ViewSilence = 'view-silence', UpdateSilence = 'update-silence', // mute timings ViewMuteTiming = 'view-mute-timing', CreateMuteTiming = 'create-mute-timing', UpdateMuteTiming = 'update-mute-timing', DeleteMuteTiming = 'delete-mute-timing', ExportMuteTimings = 'export-mute-timings', } // this enum lists all of the available actions we can take on a single alert rule export enum AlertRuleAction { Duplicate = 'duplicate-alert-rule', View = 'view-alert-rule', Update = 'update-alert-rule', Delete = 'delete-alert-rule', Explore = 'explore-alert-rule', Silence = 'silence-alert-rule', ModifyExport = 'modify-export-rule', } // this enum lists all of the actions we can perform within alerting in general, not linked to a specific // alert source, rule or alertmanager export enum AlertingAction { // internal (Grafana managed) CreateAlertRule = 'create-alert-rule', ViewAlertRule = 'view-alert-rule', UpdateAlertRule = 'update-alert-rule', DeleteAlertRule = 'delete-alert-rule', ExportGrafanaManagedRules = 'export-grafana-managed-rules', // external (any compatible alerting data source) CreateExternalAlertRule = 'create-external-alert-rule', ViewExternalAlertRule = 'view-external-alert-rule', UpdateExternalAlertRule = 'update-external-alert-rule', DeleteExternalAlertRule = 'delete-external-alert-rule', } // these just makes it easier to read the code :) const AlwaysSupported = true; const NotSupported = false; export type Action = AlertmanagerAction | AlertingAction | AlertRuleAction; export type Ability = [actionSupported: boolean, actionAllowed: boolean]; export type Abilities<T extends Action> = Record<T, Ability>; /** * This one will check for alerting abilities that don't apply to any particular alert source or alert rule */ export const useAlertingAbilities = (): Abilities<AlertingAction> => { return { // internal (Grafana managed) [AlertingAction.CreateAlertRule]: toAbility(AlwaysSupported, AccessControlAction.AlertingRuleCreate), [AlertingAction.ViewAlertRule]: toAbility(AlwaysSupported, AccessControlAction.AlertingRuleRead), [AlertingAction.UpdateAlertRule]: toAbility(AlwaysSupported, AccessControlAction.AlertingRuleUpdate), [AlertingAction.DeleteAlertRule]: toAbility(AlwaysSupported, AccessControlAction.AlertingRuleDelete), [AlertingAction.ExportGrafanaManagedRules]: toAbility(AlwaysSupported, AccessControlAction.AlertingRuleRead), // external [AlertingAction.CreateExternalAlertRule]: toAbility(AlwaysSupported, AccessControlAction.AlertingRuleExternalWrite), [AlertingAction.ViewExternalAlertRule]: toAbility(AlwaysSupported, AccessControlAction.AlertingRuleExternalRead), [AlertingAction.UpdateExternalAlertRule]: toAbility(AlwaysSupported, AccessControlAction.AlertingRuleExternalWrite), [AlertingAction.DeleteExternalAlertRule]: toAbility(AlwaysSupported, AccessControlAction.AlertingRuleExternalWrite), }; }; export const useAlertingAbility = (action: AlertingAction): Ability => { const allAbilities = useAlertingAbilities(); return allAbilities[action]; }; /** * This hook will check if we support the action and have sufficient permissions for it on a single alert rule */ export function useAlertRuleAbility(rule: CombinedRule, action: AlertRuleAction): Ability { const abilities = useAllAlertRuleAbilities(rule); return useMemo(() => { return abilities[action]; }, [abilities, action]); } export function useAlertRuleAbilities(rule: CombinedRule, actions: AlertRuleAction[]): Ability[] { const abilities = useAllAlertRuleAbilities(rule); return useMemo(() => { return actions.map((action) => abilities[action]); }, [abilities, actions]); } export function useAllAlertRuleAbilities(rule: CombinedRule): Abilities<AlertRuleAction> { const rulesSource = rule.namespace.rulesSource; const rulesSourceName = typeof rulesSource === 'string' ? rulesSource : rulesSource.name; const isProvisioned = isGrafanaRulerRule(rule.rulerRule) && Boolean(rule.rulerRule.grafana_alert.provenance); const isFederated = isFederatedRuleGroup(rule.group); const isGrafanaManagedAlertRule = isGrafanaRulerRule(rule.rulerRule); // if a rule is either provisioned or a federated rule, we don't allow it to be removed or edited const immutableRule = isProvisioned || isFederated; const { isEditable, isRemovable, isRulerAvailable = false, loading, } = useIsRuleEditable(rulesSourceName, rule.rulerRule); const [_, exportAllowed] = useAlertingAbility(AlertingAction.ExportGrafanaManagedRules); // while we gather info, pretend it's not supported const MaybeSupported = loading ? NotSupported : isRulerAvailable; const MaybeSupportedUnlessImmutable = immutableRule ? NotSupported : MaybeSupported; const rulesPermissions = getRulesPermissions(rulesSourceName); const canSilence = useCanSilence(rulesSource); const abilities: Abilities<AlertRuleAction> = { [AlertRuleAction.Duplicate]: toAbility(MaybeSupported, rulesPermissions.create), [AlertRuleAction.View]: toAbility(AlwaysSupported, rulesPermissions.read), [AlertRuleAction.Update]: [MaybeSupportedUnlessImmutable, isEditable ?? false], [AlertRuleAction.Delete]: [MaybeSupportedUnlessImmutable, isRemovable ?? false], [AlertRuleAction.Explore]: toAbility(AlwaysSupported, AccessControlAction.DataSourcesExplore), [AlertRuleAction.Silence]: canSilence, [AlertRuleAction.ModifyExport]: [isGrafanaManagedAlertRule, exportAllowed], }; return abilities; } export function useAllAlertmanagerAbilities(): Abilities<AlertmanagerAction> { const { selectedAlertmanager, hasConfigurationAPI, isGrafanaAlertmanager: isGrafanaFlavoredAlertmanager, } = useAlertmanager(); // These are used for interacting with Alertmanager resources where we apply alert.notifications:<name> permissions. // There are different permissions based on wether the built-in alertmanager is selected (grafana) or an external one. const notificationsPermissions = getNotificationsPermissions(selectedAlertmanager!); const instancePermissions = getInstancesPermissions(selectedAlertmanager!); //we need to know user role to determine if they can view autogenerated policy tree const isAdmin = contextSrv.hasRole('Admin') || contextSrv.isGrafanaAdmin; // list out all of the abilities, and if the user has permissions to perform them const abilities: Abilities<AlertmanagerAction> = { // -- configuration -- [AlertmanagerAction.ViewExternalConfiguration]: toAbility( AlwaysSupported, AccessControlAction.AlertingNotificationsExternalRead ), [AlertmanagerAction.UpdateExternalConfiguration]: toAbility( hasConfigurationAPI, AccessControlAction.AlertingNotificationsExternalWrite ), // -- contact points -- [AlertmanagerAction.CreateContactPoint]: toAbility(hasConfigurationAPI, notificationsPermissions.create), [AlertmanagerAction.ViewContactPoint]: toAbility(AlwaysSupported, notificationsPermissions.read), [AlertmanagerAction.UpdateContactPoint]: toAbility(hasConfigurationAPI, notificationsPermissions.update), [AlertmanagerAction.DeleteContactPoint]: toAbility(hasConfigurationAPI, notificationsPermissions.delete), // only Grafana flavored alertmanager supports exporting [AlertmanagerAction.ExportContactPoint]: toAbility(isGrafanaFlavoredAlertmanager, notificationsPermissions.read), // -- notification templates -- [AlertmanagerAction.CreateNotificationTemplate]: toAbility(hasConfigurationAPI, notificationsPermissions.create), [AlertmanagerAction.ViewNotificationTemplate]: toAbility(AlwaysSupported, notificationsPermissions.read), [AlertmanagerAction.UpdateNotificationTemplate]: toAbility(hasConfigurationAPI, notificationsPermissions.update), [AlertmanagerAction.DeleteNotificationTemplate]: toAbility(hasConfigurationAPI, notificationsPermissions.delete), // -- notification policies -- [AlertmanagerAction.CreateNotificationPolicy]: toAbility(hasConfigurationAPI, notificationsPermissions.create), [AlertmanagerAction.ViewNotificationPolicyTree]: toAbility(AlwaysSupported, notificationsPermissions.read), [AlertmanagerAction.UpdateNotificationPolicyTree]: toAbility(hasConfigurationAPI, notificationsPermissions.update), [AlertmanagerAction.DeleteNotificationPolicy]: toAbility(hasConfigurationAPI, notificationsPermissions.delete), [AlertmanagerAction.ExportNotificationPolicies]: toAbility( isGrafanaFlavoredAlertmanager, notificationsPermissions.read ), [AlertmanagerAction.DecryptSecrets]: toAbility( isGrafanaFlavoredAlertmanager, notificationsPermissions.provisioning.readSecrets ), [AlertmanagerAction.ViewAutogeneratedPolicyTree]: [isGrafanaFlavoredAlertmanager, isAdmin], // -- silences -- // for now, all supported Alertmanager flavors have API endpoints for managing silences [AlertmanagerAction.CreateSilence]: toAbility(AlwaysSupported, instancePermissions.create), [AlertmanagerAction.ViewSilence]: toAbility(AlwaysSupported, instancePermissions.read), [AlertmanagerAction.UpdateSilence]: toAbility(AlwaysSupported, instancePermissions.update), // -- mute timtings -- [AlertmanagerAction.CreateMuteTiming]: toAbility(hasConfigurationAPI, notificationsPermissions.create), [AlertmanagerAction.ViewMuteTiming]: toAbility(AlwaysSupported, notificationsPermissions.read), [AlertmanagerAction.UpdateMuteTiming]: toAbility(hasConfigurationAPI, notificationsPermissions.update), [AlertmanagerAction.DeleteMuteTiming]: toAbility(hasConfigurationAPI, notificationsPermissions.delete), [AlertmanagerAction.ExportMuteTimings]: toAbility(isGrafanaFlavoredAlertmanager, notificationsPermissions.read), }; return abilities; } export function useAlertmanagerAbility(action: AlertmanagerAction): Ability { const abilities = useAllAlertmanagerAbilities(); return useMemo(() => { return abilities[action]; }, [abilities, action]); } export function useAlertmanagerAbilities(actions: AlertmanagerAction[]): Ability[] { const abilities = useAllAlertmanagerAbilities(); return useMemo(() => { return actions.map((action) => abilities[action]); }, [abilities, actions]); } /** * We don't want to show the silence button if either * 1. the user has no permissions to create silences * 2. the admin has configured to only send instances to external AMs */ function useCanSilence(rulesSource: RulesSource): [boolean, boolean] { const isGrafanaManagedRule = rulesSource === GRAFANA_RULES_SOURCE_NAME; const { useGetAlertmanagerChoiceStatusQuery } = alertmanagerApi; const { currentData: amConfigStatus, isLoading } = useGetAlertmanagerChoiceStatusQuery(undefined, { skip: !isGrafanaManagedRule, }); // we don't support silencing when the rule is not a Grafana managed rule // we simply don't know what Alertmanager the ruler is sending alerts to if (!isGrafanaManagedRule || isLoading) { return [false, false]; } const interactsOnlyWithExternalAMs = amConfigStatus?.alertmanagersChoice === AlertmanagerChoice.External; const interactsWithAll = amConfigStatus?.alertmanagersChoice === AlertmanagerChoice.All; const silenceSupported = !interactsOnlyWithExternalAMs || interactsWithAll; return toAbility(silenceSupported, AccessControlAction.AlertingInstanceCreate); } // just a convenient function const toAbility = (supported: boolean, action: AccessControlAction): Ability => [supported, ctx.hasPermission(action)];
Edit
Rename
Chmod
Delete
FILE
FOLDER
INFO
Name
Size
Permission
Action
__snapshots__
---
0755
alert-details
---
0755
useAbilities.test.tsx
6404 bytes
0644
useAbilities.ts
13933 bytes
0644
useAlertManagerSources.ts
293 bytes
0644
useAlertQueriesStatus.ts
681 bytes
0644
useAlertmanagerConfig.ts
732 bytes
0644
useCombinedRule.ts
10042 bytes
0644
useCombinedRuleNamespaces.test.ts
1785 bytes
0644
useCombinedRuleNamespaces.ts
15283 bytes
0644
useControlledFieldArray.ts
1841 bytes
0644
useExternalAMSelector.test.tsx
6805 bytes
0644
useExternalAmSelector.ts
4616 bytes
0644
useFilteredAmGroups.ts
1291 bytes
0644
useFilteredRules.test.ts
8782 bytes
0644
useFilteredRules.ts
12938 bytes
0644
useFolder.ts
847 bytes
0644
useGroupedAlerts.ts
3338 bytes
0644
useHasRuler.ts
1062 bytes
0644
useIsRuleEditable.test.tsx
5996 bytes
0644
useIsRuleEditable.ts
2778 bytes
0644
useManagedAlertStateHistory.ts
692 bytes
0644
useMuteTimingOptions.ts
897 bytes
0644
usePagination.test.tsx
2055 bytes
0644
usePagination.ts
1058 bytes
0644
usePanelCombinedRules.ts
2733 bytes
0644
usePluginBridge.ts
847 bytes
0644
useReturnTo.test.tsx
1946 bytes
0644
useReturnTo.ts
1546 bytes
0644
useRuleSourcesWithRuler.ts
812 bytes
0644
useSilenceNavData.test.tsx
1249 bytes
0644
useSilenceNavData.ts
797 bytes
0644
useStateHistoryModal.tsx
2855 bytes
0644
useURLSearchParams.ts
628 bytes
0644
useUnifiedAlertingSelector.ts
531 bytes
0644
useVizHeight.ts
877 bytes
0644
N4ST4R_ID | Naxtarrr