Skip to content

Commit

Permalink
Initial PR to enable MDS support for Monitors and Alerts Triggers wit…
Browse files Browse the repository at this point in the history
…hin the Alerting Plugin. (opensearch-project#949)

* first setup for alerting MDS support

Signed-off-by: Riya Saxena <[email protected]>

* fixed some create-monitor issues

Signed-off-by: Riya Saxena <[email protected]>

* fixed create Monitor

Signed-off-by: Riya Saxena <[email protected]>

* fixed monitor actions for mds support

Signed-off-by: Riya Saxena <[email protected]>

* fix jest tests and added neo support for alertTriggers

Signed-off-by: Riya Saxena <[email protected]>

* minor bug fixes

Signed-off-by: Riya Saxena <[email protected]>

* minor bug fixes

Signed-off-by: Riya Saxena <[email protected]>

* remve dev code

Signed-off-by: Riya Saxena <[email protected]>

* address the comments by fixing minor issues

Signed-off-by: Riya Saxena <[email protected]>

* address the comments by fixing minor issues

Signed-off-by: Riya Saxena <[email protected]>

* address the comments

Signed-off-by: Riya Saxena <[email protected]>

* address the review comments

Signed-off-by: Riya Saxena <[email protected]>

---------

Signed-off-by: Riya Saxena <[email protected]>
Signed-off-by: Riya <[email protected]>
  • Loading branch information
riysaxen-amzn authored May 22, 2024
1 parent c239ded commit da99e39
Show file tree
Hide file tree
Showing 75 changed files with 957 additions and 427 deletions.
1 change: 1 addition & 0 deletions opensearch_dashboards.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "3.0.0.0",
"opensearchDashboardsVersion": "3.0.0",
"configPath": ["opensearch_alerting"],
"optionalPlugins": ["dataSource", "dataSourceManagement"],
"requiredPlugins": [
"uiActions",
"dashboard",
Expand Down
9 changes: 6 additions & 3 deletions public/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import ReactDOM from 'react-dom';
import { HashRouter as Router, Route } from 'react-router-dom';
Expand All @@ -13,7 +12,7 @@ import 'react-vis/dist/style.css';
import './app.scss';
import Main from './pages/Main';
import { CoreContext } from './utils/CoreContext';
import { ServicesContext, NotificationService } from './services';
import { ServicesContext, NotificationService, getDataSourceEnabled } from './services';
import { initManageChannelsUrl } from './utils/helpers';

export function renderApp(coreStart, params) {
Expand All @@ -22,6 +21,10 @@ export function renderApp(coreStart, params) {
coreStart.chrome.setBreadcrumbs([{ text: 'Alerting' }]); // Set Breadcrumbs for the plugin
const notificationService = new NotificationService(http);
const services = { notificationService };
const mdsProps = {
setActionMenu: params.setHeaderActionMenu,
dataSourceEnabled: getDataSourceEnabled()?.enabled,
};

// Load Chart's dark mode CSS
if (isDarkMode) {
Expand All @@ -44,7 +47,7 @@ export function renderApp(coreStart, params) {
chrome: coreStart.chrome,
}}
>
<Route render={(props) => <Main title="Alerting" {...props} />} />
<Route render={(props) => <Main title="Alerting" {...mdsProps} {...props} />} />
</CoreContext.Provider>
</ServicesContext.Provider>
</Router>,
Expand Down
11 changes: 10 additions & 1 deletion public/components/Breadcrumbs/Breadcrumbs.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
MONITOR_ACTIONS,
TRIGGER_ACTIONS,
} from '../../utils/constants';
import { getDataSourceQueryObj } from '../../pages/utils/helpers';

export async function getBreadcrumbs(httpClient, history, location) {
const { state: routeState } = location;
Expand Down Expand Up @@ -65,7 +66,15 @@ export async function getBreadcrumb(route, routeState, httpClient) {
try {
const searchPool =
type === 'workflow' || monitorType === 'composite' ? 'workflows' : 'monitors';
const response = await httpClient.get(`../api/alerting/${searchPool}/${base}`);

// Construct the full URL with the query parameters
const dataSourceQueryObj = getDataSourceQueryObj();

const response = await httpClient.get(
`../api/alerting/${searchPool}/${base}`,
dataSourceQueryObj
);

if (response.ok) {
monitorName = response.resp.name;
}
Expand Down
8 changes: 6 additions & 2 deletions public/components/Breadcrumbs/Breadcrumbs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,14 @@ describe('getBreadcrumb', () => {

describe('when matching document IDs', () => {
test('calls get monitor route', async () => {
const routeState = {}; // Provide a non-empty routeState object if necessary
httpClientMock.get.mockResolvedValue({ ok: true, resp: { name: 'random_name' } });
await getBreadcrumb(monitorId, {}, httpClientMock);
await getBreadcrumb(monitorId, routeState, httpClientMock);
expect(httpClientMock.get).toHaveBeenCalled();
expect(httpClientMock.get).toHaveBeenCalledWith(`../api/alerting/monitors/${monitorId}`);
expect(httpClientMock.get).toHaveBeenCalledWith(
`../api/alerting/monitors/${monitorId}`,
undefined
);
});

test('returns monitor name', async () => {
Expand Down
6 changes: 4 additions & 2 deletions public/components/DeleteModal/DeleteMonitorModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
EuiOverlayMask
} from '@elastic/eui';
import { PLUGIN_NAME } from '../../../utils/constants';
import { getDataSourceQueryObj, constructUrlFromDataSource } from '../../pages/utils/helpers';

interface DeleteModalProps {
monitors: any[];
Expand Down Expand Up @@ -38,7 +39,8 @@ export const DeleteMonitorModal = ({
setAssociatedWorkflows(monitors[0].associated_workflows);
}
else {
httpClient?.get(`../api/alerting/monitors/${monitors[0].id}`)
const dataSourceQuery = getDataSourceQueryObj();
httpClient?.get(`../api/alerting/monitors/${monitors[0].id}`, dataSourceQuery)
.then((res: any) => {
setAssociatedWorkflows(res.resp.associated_workflows);
})
Expand All @@ -53,7 +55,7 @@ export const DeleteMonitorModal = ({
{`The monitor ${monitorNames[0]} is currently being used as a delegate monitor for composite monitors. Unlink from the following composite monitors before deleting this monitor:`}
{ associatedWorkflows ?
<ul>
{associatedWorkflows.map(({ id, name }) => <li><EuiLink target='_blank' href={`${PLUGIN_NAME}#/monitors/${id}?type=workflow`}>{name}</EuiLink></li>)}
{associatedWorkflows.map(({ id, name }) => <li><EuiLink target='_blank' href={constructUrlFromDataSource(`${PLUGIN_NAME}#/monitors/${id}?type=workflow`)}>{name}</EuiLink></li>)}
</ul>
: null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import { stateToLabel } from '../../../../utils/contextMenu/monitors';
import { dateOptionsLong } from '../../../../utils/contextMenu/helpers';
import './styles.scss';
import { constructUrlFromDataSource } from '../../../../pages/utils/helpers';

function AssociateExisting({ monitors, selectedMonitorId, setSelectedMonitorId }) {
const selectedOptions = useMemo(() => {
Expand Down Expand Up @@ -127,7 +128,10 @@ function AssociateExisting({ monitors, selectedMonitorId, setSelectedMonitorId }
</EuiHealth>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiLink href={`alerting#/monitors/${monitor.id}`} target="_blank">
<EuiLink
href={constructUrlFromDataSource(`alerting#/monitors/${monitor.id}`)}
target="_blank"
>
View monitor page
</EuiLink>
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import {
getDataSources,
getLocalClusterName,
} from '../../../../pages/CreateMonitor/components/CrossClusterConfigurations/utils/helpers';
import { getDataSourceId } from '../../../../pages/utils/helpers';

export const DEFAULT_NUM_FLYOUT_ROWS = 10;

Expand Down Expand Up @@ -204,8 +205,12 @@ export default class AlertsDashboardFlyoutComponent extends Component {

const queryParamsString = queryString.stringify(params);
history.replace({ ...this.props.location, search: queryParamsString });

httpClient.get('../api/alerting/alerts', { query: params })?.then((resp) => {
const dataSourceId = getDataSourceId();
const extendedParams = {
...(dataSourceId !== undefined && { dataSourceId }), // Only include dataSourceId if it exists
...params, // Other parameters
};
httpClient.get('../api/alerting/alerts', { query: extendedParams })?.then((resp) => {
if (resp.ok) {
const { alerts } = resp;
const filteredAlerts = _.filter(alerts, { trigger_id: triggerID });
Expand Down
2 changes: 1 addition & 1 deletion public/components/Flyout/flyouts/dataSources.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const dataSources = ({
size={'m'}
data-test-subj={'dataSourcesFlyout_header'}
>
<h3>{`Data sources`}</h3>
<h3>{`Index`}</h3>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
Expand Down
13 changes: 10 additions & 3 deletions public/expressions/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
PointInTimeEventsVisLayer,
} from '../../../../src/plugins/vis_augmenter/public';
import { Alert } from '../models/interfaces';
import { getDataSourceId, getDataSourceQueryObj } from '../pages/utils/helpers';

export const getAlerts = async (
monitorId: string,
Expand All @@ -24,7 +25,12 @@ export const getAlerts = async (
monitorIds: [monitorId],
};

const resp = await getClient().get('/api/alerting/alerts', { query: params });
const dataSourceId = getDataSourceId();
const extendedParams = {
...(dataSourceId !== undefined && { dataSourceId }),
...params // Other parameters
};
const resp = await getClient().get('/api/alerting/alerts', { query: extendedParams });

if (resp.ok) {
const filteredAlerts = resp.alerts.filter(
Expand All @@ -37,8 +43,9 @@ export const getAlerts = async (
return [];
};

export const getMonitorName = async (monitorId: string): Promise<string> => {
const resp = await getClient().get(`/api/alerting/monitors/${monitorId}`);
export const getMonitorName = async (monitorId: string, dataSourceEnabled?: boolean): Promise<string> => {
const dataSourceQuery = getDataSourceQueryObj();
const resp = await getClient().get(`/api/alerting/monitors/${monitorId}`, dataSourceQuery);
if (resp.ok) {
return resp.resp.name;
} else if (resp.resp === '[alerting_exception] Monitor not found.') {
Expand Down
4 changes: 2 additions & 2 deletions public/expressions/overlay_alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export type OverlayAlertsExpressionFunctionDefinition = ExpressionFunctionDefini
>;


export const overlayAlertsFunction = (): OverlayAlertsExpressionFunctionDefinition => ({
export const overlayAlertsFunction = (dataSourceEnabled): OverlayAlertsExpressionFunctionDefinition => ({
name,
type: 'vis_layers',
inputTypes: ['vis_layers'],
Expand Down Expand Up @@ -66,7 +66,7 @@ export const overlayAlertsFunction = (): OverlayAlertsExpressionFunctionDefiniti
}

const alerts = await getAlerts(monitorId, startTimeInMillis, endTimeInMillis);
const monitorName = await getMonitorName(monitorId);
const monitorName = await getMonitorName(monitorId, dataSourceEnabled);
let error: VisLayerError | undefined;
if (monitorName === VisLayerErrorTypes.RESOURCE_DELETED)
error = {
Expand Down
12 changes: 12 additions & 0 deletions public/models/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,15 @@ export interface Alert {
severity: string;
action_execution_results: ActionExecutionResult[];
}

export interface DataSourceEnabled {
enabled: boolean;
}

export interface DataSource {
dataSourceId: string;
}

export interface DataSourceReadOnly {
isReadOnly: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,20 @@ import MonitorsList from './components/MonitorsList';
import MonitorsEditor from './components/MonitorsEditor';
import { monitorTypesForComposition } from '../../../../utils/constants';
import { titleTemplate } from '../../../../utils/helpers';
import { getDataSourceQueryObj } from '../../../utils/helpers';

export const getMonitors = async (httpClient) => {
const dataSourceQuery = getDataSourceQueryObj();
const queryObj = {
from: 0,
size: 1000,
search: '',
sortField: 'name',
sortDirection: 'desc',
state: 'all',
};
const response = await httpClient.get('../api/alerting/monitors', {
query: {
from: 0,
size: 1000,
search: '',
sortField: 'name',
sortDirection: 'desc',
state: 'all',
},
query: { ...queryObj, ...dataSourceQuery?.query },
});

if (response.ok) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { FormikComboBox } from '../../../../../components/FormControls';
import { MONITOR_TYPE } from '../../../../../utils/constants';
import { connect } from 'formik';
import { validateIndex } from '../../../../../utils/validate';
import { getDataSourceId } from '../../../../utils/helpers';
export const CROSS_CLUSTER_SETUP_LINK =
'https://opensearch.org/docs/latest/security/access-control/cross-cluster-search/';

Expand Down Expand Up @@ -56,6 +57,7 @@ export class CrossClusterConfiguration extends Component {
const query = {
indexes: indexes.length === 0 ? '*,*:*' : indexes.join(','),
include_mappings: !loadedInitialValues,
dataSourceId: getDataSourceId(),
};
const response = await httpClient.get(`../api/alerting/remote/indexes`, { query: query });
if (response.ok) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import { DEFAULT_EMPTY_DATA, MONITOR_TYPE } from '../../../../../utils/constants
export const CROSS_CLUSTER_MONITORING_ENABLED_SETTING =
'plugins.alerting.cross_cluster_monitoring_enabled';

export const getLocalClusterName = async (httpClient) => {
export const getLocalClusterName = async (httpClient, dataSourceQuery) => {
let localClusterName = DEFAULT_EMPTY_DATA;
try {
const response = await httpClient.get('../api/alerting/_health');
const response = await httpClient.get('../api/alerting/_health', dataSourceQuery);
if (response.ok) {
localClusterName = response.resp[0]?.cluster;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ export default class CreateMonitor extends Component {
notificationService,
} = this.props;
const { createModalOpen, initialValues, plugins } = this.state;

return (
<div style={{ padding: '25px 50px' }}>
<Formik
Expand All @@ -173,7 +172,6 @@ export default class CreateMonitor extends Component {
>
{({ values, errors, handleSubmit, isSubmitting, isValid, touched }) => {
const isComposite = values.monitor_type === MONITOR_TYPE.COMPOSITE_LEVEL;

return (
<Fragment>
<EuiTitle size="l">
Expand Down Expand Up @@ -221,6 +219,7 @@ export default class CreateMonitor extends Component {
detectorId={this.props.detectorId}
notifications={notifications}
isDarkMode={isDarkMode}
landingDataSourceId={this.props.landingDataSourceId}
/>
<EuiSpacer />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { triggerToFormik } from '../../../../CreateTrigger/containers/CreateTrig
import { TRIGGER_TYPE } from '../../../../CreateTrigger/containers/CreateTrigger/utils/constants';
import { getInitialTriggerValues } from '../../../../CreateTrigger/components/AddTriggerButton/utils';
import { AGGREGATION_TYPES } from '../../../components/MonitorExpressions/expressions/utils/constants';
import { getDataSourceQueryObj } from '../../../../utils/helpers';

export const getInitialValues = ({
title,
Expand Down Expand Up @@ -94,7 +95,8 @@ const getMetricAgg = (embeddable) => {

export const getPlugins = async (httpClient) => {
try {
const pluginsResponse = await httpClient.get('../api/alerting/_plugins');
const dataSourceQuery = getDataSourceQueryObj();
const pluginsResponse = await httpClient.get('../api/alerting/_plugins', dataSourceQuery);
if (pluginsResponse.ok) {
return pluginsResponse.resp.map((plugin) => plugin.component);
} else {
Expand Down Expand Up @@ -182,8 +184,10 @@ export const create = async ({
try {
const isWorkflow = monitor.workflow_type === MONITOR_TYPE.COMPOSITE_LEVEL;
const creationPool = isWorkflow ? 'workflows' : 'monitors';
const dataSourceQuery = getDataSourceQueryObj();
const resp = await httpClient.post(`../api/alerting/${creationPool}`, {
body: JSON.stringify(monitor),
query: dataSourceQuery?.query,
});
setSubmitting(false);
const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class DataSource extends Component {
monitorType={monitor_type}
canCallGetRemoteIndexes={canCallGetRemoteIndexes}
remoteMonitoringEnabled={remoteMonitoringEnabled}
landingDataSourceId={this.props.landingDataSourceId}
/>

{displayTimeField && (
Expand All @@ -62,7 +63,7 @@ class DataSource extends Component {
}
return (
<ContentPanel
title="Data source"
title="Select data"
titleSize="s"
panelStyles={{ paddingLeft: '10px', paddingRight: '10px' }}
bodyStyles={{ padding: 'initial' }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ exports[`DataSource renders 1`] = `
"paddingRight": "10px",
}
}
title="Data source"
title="Select data"
titleSize="s"
>
<MonitorIndex
Expand Down
Loading

0 comments on commit da99e39

Please sign in to comment.