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 18, 2023
1 parent 567db1d commit f6b39fe
Show file tree
Hide file tree
Showing 18 changed files with 151 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import React, { Fragment } from 'react';
import { EuiSpacer, EuiText } from '@elastic/eui';
import MonitorsList from './components/MonitorsList';

const AssociateMonitors = ({ monitors, options, history }) => {
const AssociateMonitors = ({ monitors, options, history, values }) => {
const onUpdate = () => {};

return (
Expand All @@ -21,7 +21,7 @@ const AssociateMonitors = ({ monitors, options, history }) => {

<EuiSpacer size="m" />

<MonitorsList monitors={monitors} options={options} history={history} />
<MonitorsList monitors={monitors} options={options} history={history} values={values} />
</Fragment>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ import {
FormikFormRow,
} from '../../../../../components/FormControls';

const MonitorsList = ({ monitors = [], options = [] }) => {
const MonitorsList = ({ monitors = [], options = [], values }) => {
const [selectedOptions, setSelectedOptions] = useState({});
const [monitorOptions, setMonitorOptions] = useState([]);

const [monitorFields, setMonitorFields] = useState<number[]>(
_.reduce(
monitors.length ? monitors : [0, 1],
Expand All @@ -41,9 +42,11 @@ const MonitorsList = ({ monitors = [], options = [] }) => {
}));
setMonitorOptions(newOptions);

let newSelected = monitors.length ? monitors : [];
setSelectedOptions(Object.assign({}, newSelected));
}, []);
// let newSelected = monitors.length ? monitors : [];
// setSelectedOptions(Object.assign({}, newSelected));

// _.set(values, 'associatedMonitors', Object.values(newSelected));
}, [monitors, options, values]);

const onChange = (options, monitorIdx, form) => {
let newSelected = {
Expand Down Expand Up @@ -72,7 +75,6 @@ const MonitorsList = ({ monitors = [], options = [] }) => {
const onBlur = (monitorIdx, form) => {
form.setFieldTouched('associatedMonitors', true);
form.setFieldTouched(`associatedMonitor_${monitorIdx}`, true);

form.setFieldValue('associatedMonitors', Object.values(selectedOptions));
form.setFieldError('associatedMonitors', validate());
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ export default class CreateMonitor extends Component {
<EuiSpacer />

<WorkflowDetails
values={values}
history={history}
isAd={values.searchType === SEARCH_TYPE.AD}
isComposite={values.monitor_type === MONITOR_TYPE.COMPOSITE_LEVEL}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import { FORMIK_INITIAL_DOCUMENT_LEVEL_QUERY_VALUES, FORMIK_INITIAL_VALUES } fro
import { SEARCH_TYPE, INPUTS_DETECTOR_ID, MONITOR_TYPE } from '../../../../../utils/constants';
import { OPERATORS_MAP } from '../../../components/MonitorExpressions/expressions/utils/constants';
import {
COMPOSITE_INPUT_FIELD,
DOC_LEVEL_INPUT_FIELD,
QUERY_STRING_QUERY_OPERATORS,
} from '../../../components/DocumentLevelMonitorQueries/utils/constants';
import { formikToCompositeInput, formikToCompositeUiMetadata } from './formikToMonitor';

// Convert Monitor JSON to Formik values used in UI forms
export default function monitorToFormik(monitor) {
Expand Down Expand Up @@ -38,6 +40,8 @@ export default function monitorToFormik(monitor) {
};
case MONITOR_TYPE.DOC_LEVEL:
return docLevelInputToFormik(monitor);
case MONITOR_TYPE.COMPOSITE_LEVEL:
return { inputs: _.get(monitor, 'inputs[0].composite_input.sequence.delegates', []) };
default:
return {
index: indicesToFormik(inputs[0].search.indices),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import Schedule from '../../components/Schedule';
import AssociateMonitors from '../../components/AssociateMonitors/AssociateMonitors';
import { EuiSpacer } from '@elastic/eui';

const WorkflowDetails = ({ isAd, isComposite, httpClient, history }) => {
const WorkflowDetails = ({ isAd, isComposite, httpClient, history, values }) => {
const [selectedMonitors, setSelectedMonitors] = useState([]);
const [monitorOptions, setMonitorOptions] = useState([]);

const getMonitors = async () => {
const response = await httpClient.get('../api/alerting/monitors', {
query: {
from: 0,
size: 5000,
size: 1000,
search: '',
sortField: 'name',
sortDirection: 'desc',
Expand All @@ -37,8 +37,15 @@ const WorkflowDetails = ({ isAd, isComposite, httpClient, history }) => {
useEffect(() => {
getMonitors().then((monitors) => {
setMonitorOptions(monitors);

// const getMonitorById = (id) => monitors.find((mon) => mon.monitor_id === id);
// const newSelectedMonitors = values.inputs.map((monitor) => ({
// value: monitor.monitor_id,
// label: getMonitorById(monitor.monitor_id)?.monitor_name,
// }));
// setSelectedMonitors(newSelectedMonitors);
});
}, []);
}, [values]);

return (
<ContentPanel
Expand All @@ -59,6 +66,7 @@ const WorkflowDetails = ({ isAd, isComposite, httpClient, history }) => {
monitors={selectedMonitors}
options={monitorOptions}
history={history}
values={values}
/>
</Fragment>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const ExpressionQuery = ({
const [usedExpressions, setUsedExpressions] = useState([]);

useEffect(() => {
debugger;
let expressions = [];
if (value?.length) {
let values = [...value];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +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',
COMPOSITE_LEVEL: 'chained_alert_trigger',
};

export const FORMIK_INITIAL_BUCKET_SELECTOR_VALUES = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export function triggerDefinitionToFormik(trigger, monitor) {
return bucketLevelTriggerToFormik(trigger, monitor);
case MONITOR_TYPE.DOC_LEVEL:
return documentLevelTriggerToFormik(trigger, monitor);
case MONITOR_TYPE.COMPOSITE_LEVEL:
return compositeTriggerToFormik(trigger, monitor);
default:
return queryLevelTriggerToFormik(trigger, monitor);
}
Expand Down Expand Up @@ -216,6 +218,30 @@ export function documentLevelTriggerToFormik(trigger, monitor) {
};
}

export function compositeTriggerToFormik(trigger, monitor) {
const {
id,
name,
severity,
condition: { script },
actions,
minTimeBetweenExecutions,
rollingWindowSize,
} = trigger[TRIGGER_TYPE.COMPOSITE_LEVEL];
const triggerUiMetadata = _.get(monitor, `ui_metadata.triggers[${name}]`);
return {
..._.cloneDeep(FORMIK_INITIAL_TRIGGER_VALUES),
id,
name,
severity,
script,
actions: getExecutionPolicyActions(actions),
minTimeBetweenExecutions,
rollingWindowSize,
triggerConditions: triggerUiMetadata,
};
}

export function getExecutionPolicyActions(actions) {
const executionPolicyPath = 'action_execution_policy.action_execution_scope';
return _.cloneDeep(actions).map((action) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ class DefineCompositeLevelTrigger extends Component {
monitor_id: monitor.value,
}))
: [];

return (
<ContentPanel
title={'Alert trigger'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,39 @@ const NotificationConfigDialog = ({
...initialActionValues,
});

console.log('Initial actions', action);
const sendTestMessage = async (index) => {
let testTrigger = _.cloneDeep(
formikToTrigger(triggerValues, monitor.ui_metadata)[triggerIndex]
);
const mon = _.cloneDeep(monitor);
const tv = _.cloneDeep(triggerValues);
let testTrigger = _.cloneDeep(formikToTrigger(tv, mon.ui_metadata)[triggerIndex]);

testTrigger = {
...testTrigger,
name: _.get(tv, 'triggerDefinitions[0].name', ''),
severity: _.get(tv, 'triggerDefinitions[0].severity', ''),
};
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 }] };
let triggers = _.cloneDeep(testTrigger);

delete triggers.chained_alert_trigger;
delete triggers.min_time_between_executions;
delete triggers.rolling_window_size;

_.set(triggers, 'actions', [action]);
_.set(triggers, 'condition', condition);

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

// clean up actions and triggers
delete testMonitor.enabled_time;
delete testMonitor.last_update_time;
delete testMonitor.schema_version;
delete testMonitor.ui_metadata.composite_input;
delete testMonitor.ui_metadata.monitor_type;

try {
const response = await httpClient.post('../api/alerting/monitors/_execute', {
Expand All @@ -78,7 +96,6 @@ const NotificationConfigDialog = ({
}
};

console.log('ACTION', action);
return (
<EuiModal onClose={() => closeModal()}>
<EuiModalHeader>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const TriggerNotifications = ({
setActions(newActions);

getChannels().then((channels) => setOptions(channels));
}, []);
}, [triggerValues]);

const getChannels = async () => {
const hasNotificationPlugin = plugins.indexOf(OS_NOTIFICATION_PLUGIN) !== -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { FormikComboBox } from '../../../../components/FormControls';
import NotificationConfigDialog from './NotificationConfigDialog';
import _ from 'lodash';
import { FORMIK_INITIAL_ACTION_VALUES } from '../../utils/constants';
import { NOTIFY_OPTIONS_VALUES } from '../../components/Action/actions/Message';

const TriggerNotificationsContent = ({
channel,
Expand All @@ -33,6 +34,9 @@ const TriggerNotificationsContent = ({
lang: 'mustache',
source: 'Monitor {{ctx.monitor.name}} triggered an alert {{ctx.trigger.name}}',
},
action_execution_policy: {
action_execution_scope: NOTIFY_OPTIONS_VALUES.PER_ALERT,
},
});
};

Expand Down
9 changes: 5 additions & 4 deletions public/pages/MonitorDetails/containers/MonitorDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ export default class MonitorDetails extends Component {
};
}

isWorkflow = () => new URLSearchParams(this.props.location.search).get('type') === 'workflow';

componentDidMount() {
this.getMonitor(this.props.match.params.monitorId);
}
Expand Down Expand Up @@ -112,7 +114,7 @@ export default class MonitorDetails extends Component {
getMonitor = (id) => {
const { httpClient } = this.props;
httpClient
.get(`../api/alerting/monitors/${id}`)
.get(`../api/alerting/${this.isWorkflow() ? 'workflows' : 'monitors'}/${id}`)
.then((resp) => {
const {
ok,
Expand Down Expand Up @@ -450,9 +452,8 @@ export default class MonitorDetails extends Component {
<EuiTabs>{this.renderTableTabs()}</EuiTabs>
{this.state.tabContent}
</div>
) : (
this.renderAlertsTable()
)}
) : // this.renderAlertsTable()
null}

{isJsonModalOpen && (
<EuiOverlayMask>
Expand Down
2 changes: 2 additions & 0 deletions public/pages/MonitorDetails/containers/Triggers/Triggers.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export function getUnwrappedTriggers(monitor) {
return trigger[TRIGGER_TYPE.BUCKET_LEVEL];
case MONITOR_TYPE.DOC_LEVEL:
return trigger[TRIGGER_TYPE.DOC_LEVEL];
case MONITOR_TYPE.COMPOSITE_LEVEL:
return trigger[TRIGGER_TYPE.COMPOSITE_LEVEL];
default:
return trigger[TRIGGER_TYPE.QUERY_LEVEL];
}
Expand Down
14 changes: 14 additions & 0 deletions server/clusters/alerting/alertingPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
DESTINATION_BASE_API,
EMAIL_ACCOUNT_BASE_API,
EMAIL_GROUP_BASE_API,
WORKFLOW_BASE_API,
} from '../../services/utils/constants';

export default function alertingPlugin(Client, config, components) {
Expand All @@ -25,6 +26,19 @@ export default function alertingPlugin(Client, config, components) {
method: 'GET',
});

alerting.getWorkflow = ca({
url: {
fmt: `${API_ROUTE_PREFIX}/workflows/<%=monitorId%>`,
req: {
monitorId: {
type: 'string',
required: true,
},
},
},
method: 'GET',
});

alerting.getMonitor = ca({
url: {
fmt: `${MONITOR_BASE_API}/<%=monitorId%>`,
Expand Down
12 changes: 12 additions & 0 deletions server/routes/monitors.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ export default function (services, router) {
monitorService.executeMonitor
);

router.get(
{
path: '/api/alerting/workflows/{id}',
validate: {
params: schema.object({
id: schema.string(),
}),
},
},
monitorService.getWorkflow
);

router.get(
{
path: '/api/alerting/monitors/{id}',
Expand Down
34 changes: 34 additions & 0 deletions server/services/MonitorService.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,40 @@ export default class MonitorService {
}
};

getWorkflow = async (context, req, res) => {
try {
const { id } = req.params;
const params = { monitorId: id };
const { callAsCurrentUser } = await this.esDriver.asScoped(req);
const getResponse = await callAsCurrentUser('alerting.getWorkflow', params);
const monitor = _.get(getResponse, 'workflow', null);
const version = _.get(getResponse, '_version', null);
const ifSeqNo = _.get(getResponse, '_seq_no', null);
const ifPrimaryTerm = _.get(getResponse, '_primary_term', null);
monitor.monitor_type = monitor.workflow_type;

return res.ok({
body: {
ok: true,
resp: monitor,
activeCount: 0,
dayCount: 0,
version,
ifSeqNo,
ifPrimaryTerm,
},
});
} catch (err) {
console.error('Alerting - MonitorService - getMonitor:', err);
return res.ok({
body: {
ok: false,
resp: err.message,
},
});
}
};

updateMonitor = async (context, req, res) => {
try {
const { id } = req.params;
Expand Down
Loading

0 comments on commit f6b39fe

Please sign in to comment.