Skip to content

Commit

Permalink
Merge pull request openshift#6057 from afreen23/add-ocs-alert-actions
Browse files Browse the repository at this point in the history
Add an alert action extension
  • Loading branch information
openshift-merge-robot authored Jul 21, 2020
2 parents 90a44c0 + b1be29f commit a38673e
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 11 deletions.
1 change: 1 addition & 0 deletions frontend/packages/console-plugin-sdk/src/typings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export * from './horizontal-nav';
export * from './providers';
export * from './pvc';
export * from './storage-class-params';
export * from './notification-alerts';
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Extension } from './base';
import { Alert } from '@console/internal/components/monitoring/types';

namespace ExtensionProperties {
export interface AlertAction {
/* Alert name as defined by `alert.rule.name` property */
alert: string;
/* Action text */
text: string;
/* Action href link */
path: (alert: Alert) => string;
}
}

export interface AlertAction extends Extension<ExtensionProperties.AlertAction> {
type: 'AlertAction';
}

export function isAlertAction(e: Extension): e is AlertAction {
return e.type === 'AlertAction';
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import * as React from 'react';
import * as _ from 'lodash';
import { Link } from 'react-router-dom';
import { alertActions } from '@console/internal/components/notification-drawer';
import { isAlertAction, useExtensions, AlertAction } from '@console/plugin-sdk';
import { getAlertActions } from '@console/internal/components/notification-drawer';
import { Timestamp } from '@console/internal/components/utils/timestamp';
import { Alert } from '@console/internal/components/monitoring/types';
import { alertURL } from '@console/internal/components/monitoring/utils';
Expand Down Expand Up @@ -42,15 +44,16 @@ export const StatusItem: React.FC<StatusItemProps> = ({ Icon, timestamp, message
};

const AlertItem: React.FC<AlertItemProps> = ({ alert }) => {
const action = alertActions.get(alert.rule.name);
const actionsExtensions = useExtensions<AlertAction>(isAlertAction);
const action = getAlertActions(actionsExtensions).get(alert.rule.name);
return (
<StatusItem
Icon={getSeverityIcon(getAlertSeverity(alert))}
timestamp={getAlertTime(alert)}
message={getAlertDescription(alert) || getAlertMessage(alert)}
>
{action ? (
<Link to={action.path}>{action.text}</Link>
<Link to={_.isFunction(action.path) ? action.path(alert) : action.path}>{action.text}</Link>
) : (
<Link to={alertURL(alert, alert.rule.id)}>View details</Link>
)}
Expand Down
33 changes: 31 additions & 2 deletions frontend/packages/local-storage-operator-plugin/src/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import * as _ from 'lodash';
import {
AlertAction,
ModelDefinition,
ModelFeatureFlag,
Plugin,
RoutePage,
HorizontalNavTab,
} from '@console/plugin-sdk';
import { referenceForModel } from '@console/internal/module/k8s';
import * as models from './models';
import { ClusterServiceVersionModel } from '@console/operator-lifecycle-manager';
import { NodeModel } from '@console/internal/models';
import { getAlertActionPath } from './utils/alert-actions-path';
import * as models from './models';

type ConsumedExtensions = HorizontalNavTab | ModelFeatureFlag | ModelDefinition | RoutePage;
type ConsumedExtensions =
| AlertAction
| HorizontalNavTab
| ModelFeatureFlag
| ModelDefinition
| RoutePage;

const LSO_FLAG = 'LSO';
const LSO_DEVICE_DISCOVERY = 'LSO_DEVICE_DISCOVERY';
Expand Down Expand Up @@ -70,6 +77,28 @@ const plugin: Plugin<ConsumedExtensions> = [
required: [LSO_DEVICE_DISCOVERY],
},
},
{
type: 'AlertAction',
properties: {
alert: 'CephOSDDiskNotResponding',
text: 'Troubleshoot',
path: getAlertActionPath,
},
flags: {
required: [LSO_DEVICE_DISCOVERY],
},
},
{
type: 'AlertAction',
properties: {
alert: 'CephOSDDiskUnavailable',
text: 'Troubleshoot',
path: getAlertActionPath,
},
flags: {
required: [LSO_DEVICE_DISCOVERY],
},
},
];

export default plugin;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Alert } from '@console/internal/components/monitoring/types';

export const getAlertActionPath = (alertData: Alert) =>
`/k8s/cluster/nodes/${alertData.labels.host}/disks/node-disk-name=${alertData.labels.device}`;
28 changes: 22 additions & 6 deletions frontend/public/components/notification-drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
EmptyStateVariant,
Title,
} from '@patternfly/react-core';
import { isAlertAction, useExtensions, AlertAction } from '@console/plugin-sdk';
import { usePrevious } from '@console/shared/src/hooks/previous';

import { coFetchJSON } from '../co-fetch';
Expand Down Expand Up @@ -72,22 +73,33 @@ const AlertEmptyState: React.FC<AlertEmptyProps> = ({ drawerToggle }) => (
</EmptyState>
);

export const alertActions = new Map().set('AlertmanagerReceiversNotConfigured', {
text: 'Configure',
path: '/monitoring/alertmanagerconfig',
});
export const getAlertActions = (actionsExtensions: AlertAction[]) => {
const alertActions = new Map().set('AlertmanagerReceiversNotConfigured', {
text: 'Configure',
path: '/monitoring/alertmanagerconfig',
});
actionsExtensions.forEach(({ properties }) =>
alertActions.set(properties.alert, {
text: properties.text,
path: properties.path,
}),
);
return alertActions;
};

const getAlertNotificationEntries = (
isLoaded: boolean,
alertData: Alert[],
toggleNotificationDrawer: () => void,
alertActionExtensions: AlertAction[],
isCritical: boolean,
): React.ReactNode[] =>
isLoaded && !_.isEmpty(alertData)
? alertData
.filter((a) => (isCritical ? criticalCompare(a) : otherAlertCompare(a)))
.map((alert, i) => {
const action = alertActions.get(alert.rule.name);
const action = getAlertActions(alertActionExtensions).get(alert.rule.name);
const alertActionPath = _.isFunction(action?.path) ? action.path(alert) : action?.path;
return (
<NotificationEntry
key={`${i}_${alert.activeAt}`}
Expand All @@ -98,7 +110,7 @@ const getAlertNotificationEntries = (
toggleNotificationDrawer={toggleNotificationDrawer}
targetPath={alertURL(alert, alert.rule.id)}
actionText={action?.text}
actionPath={action?.path}
actionPath={alertActionPath}
/>
);
})
Expand Down Expand Up @@ -206,6 +218,8 @@ export const ConnectedNotificationDrawer_: React.FC<ConnectedNotificationDrawerP
const [clusterVersionData, clusterVersionLoaded] = useK8sWatchResource<ClusterVersionKind>(
cvResource,
);
const alertActionExtensions = useExtensions<AlertAction>(isAlertAction);

const updateData: ClusterUpdate[] = getSortedUpdates(clusterVersionData);
const { data, loaded, loadError } = alerts || {};

Expand All @@ -226,12 +240,14 @@ export const ConnectedNotificationDrawer_: React.FC<ConnectedNotificationDrawerP
true,
data,
toggleNotificationDrawer,
alertActionExtensions,
true,
);
const otherAlertList: React.ReactNode[] = getAlertNotificationEntries(
loaded,
data,
toggleNotificationDrawer,
alertActionExtensions,
false,
);
const [isAlertExpanded, toggleAlertExpanded] = React.useState<boolean>(
Expand Down

0 comments on commit a38673e

Please sign in to comment.