Skip to content

Commit

Permalink
[FEATURE] Add composite monitor type opensearch-project#573
Browse files Browse the repository at this point in the history
Signed-off-by: Jovan Cvetkovic <[email protected]>
  • Loading branch information
jovancvetkovic3006 committed Jun 16, 2023
1 parent a8aa47a commit 83d6eb6
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ export default class CreateMonitor extends Component {
try {
const resp = await httpClient.post(
`../api/alerting/${
monitor.monitor_type === MONITOR_TYPE.COMPOSITE_LEVEL ? 'workflows' : 'monitors'
monitor.workflow_type && monitor.workflow_type === MONITOR_TYPE.COMPOSITE_LEVEL
? 'workflows'
: 'monitors'
}`,
{
body: JSON.stringify(monitor),
Expand Down Expand Up @@ -183,6 +185,9 @@ export default class CreateMonitor extends Component {
case MONITOR_TYPE.DOC_LEVEL:
triggerType = TRIGGER_TYPE.DOC_LEVEL;
break;
case MONITOR_TYPE.COMPOSITE_LEVEL:
triggerType = TRIGGER_TYPE.COMPOSITE_LEVEL;
break;
default:
triggerType = TRIGGER_TYPE.QUERY_LEVEL;
break;
Expand Down Expand Up @@ -249,8 +254,8 @@ export default class CreateMonitor extends Component {
monitor = { ...monitor, ...triggers };
}

console.log('Monitor', monitor);
console.log('Value', values);
if (monitor.monitor_type === MONITOR_TYPE.COMPOSITE_LEVEL) delete monitor.monitor_type;

if (edit) this.onUpdate(monitor, formikBag);
else this.onCreate(monitor, formikBag);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,16 @@ export function formikToMonitor(values) {
type: 'workflow',
enabled_time: enabled_time.getTime(),
enabled: !values.disabled,
workflow_type: 'composite',
monitor_type: MONITOR_TYPE.COMPOSITE_LEVEL,
workflow_type: MONITOR_TYPE.COMPOSITE_LEVEL,
schema_version: 0,
name: values.name,
schedule,
inputs: [formikToInputs(values)],
triggers: [],
ui_metadata: {
schedule: uiSchedule,
monitor_type: values.monitor_type,
...monitorUiMetadata(),
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const ExpressionQuery = ({
defaultText,
label,
name = 'expressionQueries',
triggerValues,
}) => {
const DEFAULT_DESCRIPTION = defaultText ? defaultText : 'Select';
const OPERATORS = ['AND', 'OR', 'NOT'];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const TRIGGER_TYPE = {
ALERT_TRIGGER: 'alerting_trigger',
QUERY_LEVEL: 'query_level_trigger',
DOC_LEVEL: 'document_level_trigger',
COMPOSITE_LEVEL: 'composite_level_trigger',
};

export const FORMIK_INITIAL_BUCKET_SELECTOR_VALUES = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ export function formikToTriggerUiMetadata(values, monitorUiMetadata) {
bucketLevelTriggersUiMetadata[trigger.name] = triggerMetadata;
});
return bucketLevelTriggersUiMetadata;

case MONITOR_TYPE.DOC_LEVEL:
const docLevelTriggersUiMetadata = {};
_.get(values, 'triggerDefinitions', []).forEach((trigger) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class DefineCompositeLevelTrigger extends Component {
name: triggerName,
},
]);

const triggerActions = _.get(triggerValues, 'triggerDefinitions[0].actions', []);
const monitorList = monitorValues?.associatedMonitors
? monitorValues.associatedMonitors?.map((monitor) => ({
label: monitor.label.replaceAll(' ', '_'),
Expand Down Expand Up @@ -135,6 +135,7 @@ class DefineCompositeLevelTrigger extends Component {
onChange={() => {}}
dataTestSubj={'composite_expression_query'}
defaultText={'Select associated monitor'}
triggerValues={triggerValues}
/>

<EuiSpacer size={'l'} />
Expand All @@ -156,6 +157,7 @@ class DefineCompositeLevelTrigger extends Component {
notifications={notifications}
notificationService={notificationService}
triggerValues={triggerValues}
triggerActions={triggerActions}
/>
</ContentPanel>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ import { getTriggerContext } from '../../utils/helper';
import { formikToMonitor } from '../../../CreateMonitor/containers/CreateMonitor/utils/formikToMonitor';
import _ from 'lodash';
import { formikToTrigger } from '../CreateTrigger/utils/formikToTrigger';
import { MONITOR_TYPE } from '../../../../utils/constants';
import { TRIGGER_TYPE } from '../CreateTrigger/utils/constants';
import { backendErrorNotification } from '../../../../utils/helpers';
import { checkForError } from '../ConfigureActions/ConfigureActions';

Expand All @@ -31,58 +29,31 @@ const NotificationConfigDialog = ({
triggerValues,
httpClient,
notifications,
actionIndex,
}) => {
const triggerIndex = 0;
const monitor = formikToMonitor(triggerValues);
delete monitor.monitor_type;
const context = getTriggerContext({}, monitor, triggerValues, 0);

const initialActionValues = _.cloneDeep(FORMIK_INITIAL_ACTION_VALUES);
let action = _.get(triggerValues, 'triggerDefinitions[0].actions[0]', {
let action = _.get(triggerValues, `triggerDefinitions[0].actions[${actionIndex}]`, {
...initialActionValues,
});

console.log('Initial actions', action);
const sendTestMessage = async (index) => {
const flattenedDestinations = [];
// TODO: For bucket-level triggers, sendTestMessage will only send a test message if there is
// at least one bucket of data from the monitor input query.
let testTrigger = _.cloneDeep(
formikToTrigger(triggerValues, monitor.ui_metadata)[triggerIndex]
);
let action;
let condition;

switch (monitor.monitor_type) {
case MONITOR_TYPE.BUCKET_LEVEL:
action = _.get(testTrigger, `${TRIGGER_TYPE.BUCKET_LEVEL}.actions[${index}]`);
condition = {
..._.get(testTrigger, `${TRIGGER_TYPE.BUCKET_LEVEL}.condition`),
buckets_path: { _count: '_count' },
script: {
source: 'params._count >= 0',
},
};
_.set(testTrigger, `${TRIGGER_TYPE.BUCKET_LEVEL}.actions`, [action]);
_.set(testTrigger, `${TRIGGER_TYPE.BUCKET_LEVEL}.condition`, condition);
break;
case MONITOR_TYPE.DOC_LEVEL:
action = _.get(testTrigger, `${TRIGGER_TYPE.DOC_LEVEL}.actions[${index}]`);
condition = {
..._.get(testTrigger, `${TRIGGER_TYPE.DOC_LEVEL}.condition`),
script: { lang: 'painless', source: 'return true' },
};
_.set(testTrigger, `${TRIGGER_TYPE.DOC_LEVEL}.actions`, [action]);
_.set(testTrigger, `${TRIGGER_TYPE.DOC_LEVEL}.condition`, condition);
break;
default:
action = _.get(testTrigger, `actions[${index}]`);
condition = {
..._.get(testTrigger, 'condition'),
script: { lang: 'painless', source: 'return true' },
};
_.set(testTrigger, 'actions', [action]);
_.set(testTrigger, 'condition', condition);
break;
}
const action = _.get(testTrigger, `chained_alert_trigger.actions[${index}]`);
const condition = {
..._.get(testTrigger, 'chained_alert_trigger.condition'),
script: { lang: 'painless', source: 'return true' },
};
_.set(testTrigger, 'actions', [action]);
_.set(testTrigger, 'condition', condition);

const testMonitor = { ...monitor, triggers: [{ ...testTrigger }] };

Expand All @@ -94,13 +65,8 @@ const NotificationConfigDialog = ({
let error = null;
if (response.ok) {
error = checkForError(response, error);
if (!_.isEmpty(action.destination_id)) {
const destinationName = _.get(
_.find(flattenedDestinations, { value: action.destination_id }),
'label'
);
notifications.toasts.addSuccess(`Test message sent to "${destinationName}."`);
}
if (!_.isEmpty(action.destination_id))
notifications.toasts.addSuccess(`Test message sent to "${action.name}."`);
}
if (error || !response.ok) {
const errorMessage = error == null ? response.resp : error;
Expand All @@ -127,7 +93,7 @@ const NotificationConfigDialog = ({

<Message
fieldPath={'triggerDefinitions[0]'}
index={0}
index={actionIndex}
values={triggerValues}
action={action}
context={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,25 @@ import { CHANNEL_TYPES } from '../../utils/constants';

const TriggerNotifications = ({
httpClient,
actions = [],
triggerActions = [],
plugins,
notifications,
notificationService,
triggerValues,
}) => {
const [channels, setChannels] = useState([]);
const [actions, setActions] = useState([]);
const [options, setOptions] = useState([]);

useEffect(() => {
let newChannels = [...actions];
if (_.isEmpty(newChannels))
newChannels = [
let newActions = [...triggerActions];
if (_.isEmpty(newActions))
newActions = [
{
name: '',
id: '',
},
];
setChannels(newChannels);
setActions(newActions);

getChannels().then((channels) => setOptions(channels));
}, []);
Expand Down Expand Up @@ -81,40 +81,40 @@ const TriggerNotifications = ({
};

const onAddNotification = () => {
const newChannels = [...channels];
newChannels.push({
const newActions = [...actions];
newActions.push({
label: '',
value: '',
});
setChannels(newChannels);
setActions(newActions);
};

const onRemoveNotification = (idx) => {
const newChannels = [...channels];
newChannels.splice(idx, 1);
setChannels(newChannels);
const newActions = [...actions];
newActions.splice(idx, 1);
setActions(newActions);
};

return (
<Fragment>
{titleTemplate('Notifications')}
<EuiSpacer size={'m'} />
{channels.length &&
channels.map((channel, idx) => (
{actions.length &&
actions.map((channel, actionIndex) => (
<EuiAccordion
title={`Notification ${idx + 1}`}
key={`notification-accordion-${idx}`}
id={`notification-accordion-${idx}`}
initialIsOpen={!idx}
buttonContent={<EuiText>{`Notification ${idx + 1}`}</EuiText>}
title={`Notification ${actionIndex + 1}`}
key={`notification-accordion-${actionIndex}`}
id={`notification-accordion-${actionIndex}`}
initialIsOpen={!actionIndex}
buttonContent={<EuiText>{`Notification ${actionIndex + 1}`}</EuiText>}
paddingSize={'s'}
extraAction={
channels.length > 1 && (
actions.length > 1 && (
<EuiButtonIcon
color={'danger'}
aria-label={'Delete notification'}
iconType={'trash'}
onClick={() => onRemoveNotification(idx)}
onClick={() => onRemoveNotification(actionIndex)}
size={'s'}
/>
)
Expand All @@ -123,11 +123,10 @@ const TriggerNotifications = ({
<TriggerNotificationsContent
channel={channel}
options={options}
idx={idx}
actionIndex={actionIndex}
notifications={notifications}
triggerValues={triggerValues}
httpClient={httpClient}
actions={actions}
/>
</EuiAccordion>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { FORMIK_INITIAL_ACTION_VALUES } from '../../utils/constants';
const TriggerNotificationsContent = ({
channel,
options,
idx,
actionIndex,
triggerValues,
httpClient,
notifications,
Expand All @@ -23,17 +23,17 @@ const TriggerNotificationsContent = ({

const onChange = (selectedOptions) => {
setSelected(selectedOptions);

const initialActionValues = _.cloneDeep(FORMIK_INITIAL_ACTION_VALUES);
_.set(triggerValues, 'triggerDefinitions[0].actions[0]', {
_.set(triggerValues, `triggerDefinitions[0].actions[${actionIndex}]`, {
...initialActionValues,
destination_id: selectedOptions[0]?.value,
name: selectedOptions[0]?.label,
subject_template: {
lang: 'mustache',
source: 'Monitor {{ctx.monitor.name}} triggered an alert {{ctx.trigger.name}}',
},
});

console.log('CHANNEL SELECTED', _.get(triggerValues, 'triggerDefinitions[0].actions[0]', {}));
};

const showConfig = (channels) => setIsModalVisible(true);
Expand All @@ -49,7 +49,7 @@ const TriggerNotificationsContent = ({
}}
>
<FormikComboBox
name={`channel_name_${idx}`}
name={`channel_name_${actionIndex}`}
formRow
fieldProps={{
isInvalid: !selected.length,
Expand Down Expand Up @@ -91,6 +91,7 @@ const TriggerNotificationsContent = ({
triggerValues={triggerValues}
httpClient={httpClient}
notifications={notifications}
actionIndex={actionIndex}
/>
)}
</Fragment>
Expand Down

0 comments on commit 83d6eb6

Please sign in to comment.