Skip to content

Commit

Permalink
[Uptime] Monitor Details - fallback to saved objects when monitor det…
Browse files Browse the repository at this point in the history
…ails are unavailable from last ping (#125333)

* uptime - synthetic service - fallback to saved objects when monitor details cannot be found

* fix monitor url

* fix tests
  • Loading branch information
dominiqueclarke authored Feb 11, 2022
1 parent 97bd50d commit f1fcbe7
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 29 deletions.
1 change: 1 addition & 0 deletions x-pack/plugins/uptime/e2e/journeys/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from './uptime.journey';
export * from './step_duration.journey';
export * from './alerts';
export * from './read_only_user';
export * from './monitor_details.journey';
export * from './monitor_name.journey';
export * from './monitor_management.journey';
export * from './monitor_details';
44 changes: 44 additions & 0 deletions x-pack/plugins/uptime/e2e/journeys/monitor_details.journey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { journey, step, expect, before, Page } from '@elastic/synthetics';
import { monitorManagementPageProvider } from '../page_objects/monitor_management';

journey('MontiorDetails', async ({ page, params }: { page: Page; params: any }) => {
const uptime = monitorManagementPageProvider({ page, kibanaUrl: params.kibanaUrl });

before(async () => {
await uptime.waitForLoadingToFinish();
});

step('Go to monitor-management', async () => {
await uptime.navigateToMonitorManagement();
});

step('login to Kibana', async () => {
await uptime.loginToKibana();
const invalid = await page.locator(`text=Username or password is incorrect. Please try again.`);
expect(await invalid.isVisible()).toBeFalsy();
});

step('navigate to monitor details page', async () => {
await uptime.assertText({ text: 'Test Monitor' });
await Promise.all([page.waitForNavigation(), page.click('text="Test Monitor"')]);
await uptime.assertText({ text: 'Test Monitor' });
const url = await page.textContent('[data-test-subj="monitor-page-url"]');
const type = await page.textContent('[data-test-subj="monitor-page-type"]');
expect(url).toEqual('https://www.google.com(opens in a new tab or window)');
expect(type).toEqual('HTTP');
});
});

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,19 @@ export const MonitorStatusBar: React.FC = () => {
/>
</MonListDescription>
<MonListTitle>{URL_LABEL}</MonListTitle>
<MonListDescription>
<EuiLink aria-label={labels.monitorUrlLinkAriaLabel} href={full} target="_blank" external>
{full}
</EuiLink>
<MonListDescription data-test-subj="monitor-page-url">
{full ? (
<EuiLink
aria-label={labels.monitorUrlLinkAriaLabel}
href={full}
target="_blank"
external
>
{full}
</EuiLink>
) : (
'--'
)}
</MonListDescription>
<MonListTitle>{MonitorIDLabel}</MonListTitle>
<MonListDescription data-test-subj="monitor-page-title">{monitorId}</MonListDescription>
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/uptime/public/state/actions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export interface QueryParams {
filters?: string;
statusFilter?: string;
location?: string;
refresh?: boolean;
}

export interface MonitorDetailsActionPayload {
Expand Down
62 changes: 62 additions & 0 deletions x-pack/plugins/uptime/public/state/reducers/monitor_status.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { Action } from 'redux-actions';

import { monitorStatusReducer, MonitorStatusState, MonitorStatusPayload } from './monitor_status';
import { getMonitorStatusAction } from '../actions/monitor_status';

describe('selectedFiltersReducer', () => {
let state: MonitorStatusState;

beforeEach(() => {
state = {
loading: false,
status: {
timestamp: '',
docId: '',
monitor: {
id: 'testid',
status: 'up',
duration: {
us: 1,
},
type: 'browser',
},
},
};
});

describe('setSelectedFilters', () => {
it('sets state to the action payload if state is null', () => {
state.status = {
timestamp: '',
docId: '',
monitor: {
id: 'testid',
status: 'up',
duration: {
us: 1,
},
type: 'browser',
},
};
expect(
monitorStatusReducer(
state,
getMonitorStatusAction({
monitorId: 'testid2',
dateStart: 'start',
dateEnd: 'end',
}) as Action<MonitorStatusPayload>
)
).toEqual({
loading: true,
status: null,
});
});
});
});
8 changes: 5 additions & 3 deletions x-pack/plugins/uptime/public/state/reducers/monitor_status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,19 @@ export interface MonitorStatusState {
loading: boolean;
}

const initialState: MonitorStatusState = {
export const initialState: MonitorStatusState = {
status: null,
loading: false,
};

type MonitorStatusPayload = QueryParams & Ping;
export type MonitorStatusPayload = QueryParams & Ping;

export const monitorStatusReducer = handleActions<MonitorStatusState, MonitorStatusPayload>(
{
[String(getMonitorStatusAction)]: (state) => ({
[String(getMonitorStatusAction)]: (state, action) => ({
...state,
// reset state if monitorId changes
status: action.payload.monitorId === state?.status?.monitor?.id ? state.status : null,
loading: true,
}),

Expand Down
24 changes: 24 additions & 0 deletions x-pack/plugins/uptime/server/lib/requests/get_monitor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { SavedObject, SavedObjectsClientContract } from 'kibana/server';
import { SyntheticsMonitor } from '../../../common/runtime_types';
import { syntheticsMonitorType } from '../../lib/saved_objects/synthetics_monitor';

export const getSyntheticsMonitor = async ({
monitorId,
savedObjectsClient,
}: {
monitorId: string;
savedObjectsClient: SavedObjectsClientContract;
}): Promise<SavedObject<SyntheticsMonitor>> => {
try {
return await savedObjectsClient.get(syntheticsMonitorType, monitorId);
} catch (e) {
throw e;
}
};
2 changes: 2 additions & 0 deletions x-pack/plugins/uptime/server/lib/requests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ import { getNetworkEvents } from './get_network_events';
import { getJourneyFailedSteps } from './get_journey_failed_steps';
import { getLastSuccessfulCheck } from './get_last_successful_check';
import { getJourneyScreenshotBlocks } from './get_journey_screenshot_blocks';
import { getSyntheticsMonitor } from './get_monitor';

export const requests = {
getCerts,
getIndexPattern,
getLatestMonitor,
getMonitorAvailability,
getSyntheticsMonitor,
getMonitorDurationChart,
getMonitorDetails,
getMonitorLocations,
Expand Down
44 changes: 42 additions & 2 deletions x-pack/plugins/uptime/server/rest_api/monitors/monitor_status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema';
import { UMServerLibs } from '../../lib/lib';
import { UMRestApiRouteFactory } from '../types';
import { API_URLS } from '../../../common/constants';
import { ConfigKey, MonitorFields } from '../../../common/runtime_types';

export const createGetStatusBarRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({
method: 'GET',
Expand All @@ -20,14 +21,53 @@ export const createGetStatusBarRoute: UMRestApiRouteFactory = (libs: UMServerLib
dateEnd: schema.string(),
}),
},
handler: async ({ uptimeEsClient, request }): Promise<any> => {
handler: async ({ uptimeEsClient, request, server }): Promise<any> => {
const { monitorId, dateStart, dateEnd } = request.query;

return await libs.requests.getLatestMonitor({
const latestMonitor = await libs.requests.getLatestMonitor({
uptimeEsClient,
monitorId,
dateStart,
dateEnd,
});

if (latestMonitor.docId) {
return latestMonitor;
}

if (!server.savedObjectsClient) {
return null;
}

try {
const monitorSavedObject = await libs.requests.getSyntheticsMonitor({
monitorId,
savedObjectsClient: server.savedObjectsClient,
});

if (!monitorSavedObject) {
return null;
}

const {
[ConfigKey.URLS]: url,
[ConfigKey.NAME]: name,
[ConfigKey.HOSTS]: host,
[ConfigKey.MONITOR_TYPE]: type,
} = monitorSavedObject.attributes as MonitorFields;

return {
url: {
full: url || host,
},
monitor: {
name,
type,
id: monitorSavedObject.id,
},
};
} catch (e) {
server.logger.error(e);
}
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@

import { schema } from '@kbn/config-schema';
import { SavedObjectsErrorHelpers } from '../../../../../../src/core/server';
import { UMServerLibs } from '../../lib/lib';
import { UMRestApiRouteFactory } from '../types';
import { API_URLS } from '../../../common/constants';
import { syntheticsMonitorType } from '../../lib/saved_objects/synthetics_monitor';
import { getMonitorNotFoundResponse } from './service_errors';

export const getSyntheticsMonitorRoute: UMRestApiRouteFactory = () => ({
export const getSyntheticsMonitorRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({
method: 'GET',
path: API_URLS.SYNTHETICS_MONITORS + '/{monitorId}',
validate: {
Expand All @@ -23,7 +24,7 @@ export const getSyntheticsMonitorRoute: UMRestApiRouteFactory = () => ({
handler: async ({ request, response, savedObjectsClient }): Promise<any> => {
const { monitorId } = request.params;
try {
return await savedObjectsClient.get(syntheticsMonitorType, monitorId);
return await libs.requests.getSyntheticsMonitor({ monitorId, savedObjectsClient });
} catch (getErr) {
if (SavedObjectsErrorHelpers.isNotFoundError(getErr)) {
return getMonitorNotFoundResponse(response, monitorId);
Expand Down

0 comments on commit f1fcbe7

Please sign in to comment.