[Synthetics] Fix private location filter usage (#151968)

Co-authored-by: Dominique Clarke <dominique.clarke@elastic.co>
This commit is contained in:
Shahzad 2023-02-27 10:07:12 +01:00 committed by GitHub
parent 2b9f2ba684
commit aa5d089ef1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 193 additions and 181 deletions

View file

@ -9,7 +9,6 @@ import React from 'react';
import { EuiFilterGroup } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useSelector } from 'react-redux';
import { ServiceLocations } from '../../../../../../../common/runtime_types';
import { selectServiceLocationsState } from '../../../../state';
import {
@ -20,10 +19,6 @@ import {
import { useFilters } from './use_filters';
import { FilterButton } from './filter_button';
export const findLocationItem = (query: string, locations: ServiceLocations) => {
return locations.find(({ id, label }) => query === id || label === query);
};
export const FilterGroup = ({
handleFilterChange,
}: {

View file

@ -5,14 +5,14 @@
* 2.0.
*/
import React from 'react';
import React, { memo } from 'react';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { FilterGroup } from './filter_group';
import { SearchField } from '../search_field';
import { SyntheticsMonitorFilterChangeHandler } from './filter_fields';
export function ListFilters({
export const ListFilters = memo(function ({
handleFilterChange,
}: {
handleFilterChange: SyntheticsMonitorFilterChangeHandler;
@ -27,4 +27,4 @@ export function ListFilters({
</EuiFlexItem>
</EuiFlexGroup>
);
}
});

View file

@ -40,7 +40,6 @@ describe('useMonitorList', () => {
absoluteTotal: state.monitorList.data.absoluteTotal ?? 0,
pageState: state.monitorList.pageState,
syntheticsMonitors: selectEncryptedSyntheticsSavedMonitors.resultFunc(state.monitorList),
overviewStatus: null,
handleFilterChange: jest.fn(),
};

View file

@ -8,7 +8,6 @@
import { useCallback, useEffect, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useDebounce } from 'react-use';
import { useOverviewStatus } from './use_overview_status';
import {
fetchMonitorListAction,
quietFetchMonitorListAction,
@ -27,8 +26,6 @@ export function useMonitorList() {
const { pageState, loading, loaded, error, data } = useSelector(selectMonitorListState);
const syntheticsMonitors = useSelector(selectEncryptedSyntheticsSavedMonitors);
const { status: overviewStatus } = useOverviewStatus();
const { handleFilterChange } = useMonitorFiltersState();
const { lastRefresh } = useSyntheticsRefreshContext();
@ -50,17 +47,20 @@ export function useMonitorList() {
}, [lastRefresh]);
// On initial mount, load the page
useEffect(() => {
if (isInitialMount.current) {
if (loaded) {
dispatch(quietFetchMonitorListAction(pageState));
} else {
dispatch(fetchMonitorListAction.get(pageState));
useDebounce(
() => {
if (isInitialMount.current) {
if (loaded) {
dispatch(quietFetchMonitorListAction(pageState));
} else {
dispatch(fetchMonitorListAction.get(pageState));
}
}
}
},
100,
// we don't use pageState here, for pageState, useDebounce will handle it
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dispatch]);
[dispatch]
);
useDebounce(
() => {
@ -86,7 +86,6 @@ export function useMonitorList() {
loadPage,
reloadPage,
absoluteTotal: data.absoluteTotal ?? 0,
overviewStatus,
handleFilterChange,
};
}

View file

@ -15,7 +15,7 @@ import {
selectOverviewStatus,
} from '../../../state/overview_status';
export function useOverviewStatus() {
export function useOverviewStatus({ scopeStatusByLocation }: { scopeStatusByLocation: boolean }) {
const pageState = useSelector(selectOverviewPageState);
const { status, error, loaded } = useSelector(selectOverviewStatus);
@ -24,16 +24,16 @@ export function useOverviewStatus() {
const dispatch = useDispatch();
const reload = useCallback(() => {
dispatch(fetchOverviewStatusAction.get(pageState));
}, [dispatch, pageState]);
dispatch(fetchOverviewStatusAction.get({ pageState, scopeStatusByLocation }));
}, [dispatch, pageState, scopeStatusByLocation]);
useEffect(() => {
if (loaded) {
dispatch(quietFetchOverviewStatusAction.get(pageState));
dispatch(quietFetchOverviewStatusAction.get({ pageState, scopeStatusByLocation }));
} else {
reload();
}
}, [dispatch, reload, lastRefresh, pageState, loaded]);
}, [dispatch, reload, lastRefresh, pageState, loaded, scopeStatusByLocation]);
return {
status,

View file

@ -8,11 +8,13 @@
import React from 'react';
import { EuiSpacer } from '@elastic/eui';
import { useSelector } from 'react-redux';
import type { useMonitorList } from '../hooks/use_monitor_list';
import { MonitorAsyncError } from './monitor_errors/monitor_async_error';
import { ListFilters } from '../common/monitor_filters/list_filters';
import { MonitorList } from './monitor_list_table/monitor_list';
import { MonitorStats } from './monitor_stats/monitor_stats';
import { selectOverviewStatus } from '../../../state/overview_status';
export const MonitorListContainer = ({
isEnabled,
@ -30,10 +32,11 @@ export const MonitorListContainer = ({
absoluteTotal,
loadPage,
reloadPage,
overviewStatus,
handleFilterChange,
} = monitorListProps;
const { status: overviewStatus } = useSelector(selectOverviewStatus);
// TODO: Display inline errors in the management table
// const { errorSummaries, loading: errorsLoading } = useInlineErrors({

View file

@ -10,6 +10,7 @@ import { Redirect } from 'react-router-dom';
import { EuiButton, EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui';
import { useTrackPageview } from '@kbn/observability-plugin/public';
import { useOverviewStatus } from './hooks/use_overview_status';
import { GETTING_STARTED_ROUTE } from '../../../../../common/constants';
import { ServiceAllowedWrapper } from '../common/wrappers/service_allowed_wrapper';
@ -24,7 +25,7 @@ import { useMonitorListBreadcrumbs } from './hooks/use_breadcrumbs';
import { useMonitorList } from './hooks/use_monitor_list';
import * as labels from './management/labels';
const MonitorPage: React.FC = () => {
const MonitorManagementPage: React.FC = () => {
useTrackPageview({ app: 'synthetics', path: 'monitors' });
useTrackPageview({ app: 'synthetics', path: 'monitors', delay: 15000 });
@ -37,6 +38,8 @@ const MonitorPage: React.FC = () => {
enableSynthetics,
} = useEnablement();
useOverviewStatus({ scopeStatusByLocation: false });
const monitorListProps = useMonitorList();
const { syntheticsMonitors, loading: monitorsLoading, absoluteTotal, loaded } = monitorListProps;
@ -91,6 +94,6 @@ const MonitorPage: React.FC = () => {
export const MonitorsPageWithServiceAllowed = React.memo(() => (
<ServiceAllowedWrapper>
<MonitorPage />
<MonitorManagementPage />
</ServiceAllowedWrapper>
));

View file

@ -20,7 +20,7 @@ import { useKibana } from '@kbn/kibana-react-plugin/public';
import { useSelector } from 'react-redux';
import { selectOverviewStatus } from '../../../../state/overview_status';
import { AlertsLink } from '../../../common/links/view_alerts';
import { useRefreshedRange } from '../../../../hooks';
import { useRefreshedRange, useGetUrlParams } from '../../../../hooks';
import { ClientPluginsStart } from '../../../../../../plugin';
export const OverviewAlerts = () => {
@ -33,6 +33,8 @@ export const OverviewAlerts = () => {
const { status } = useSelector(selectOverviewStatus);
const { locations } = useGetUrlParams();
const loading = !status?.allIds || status?.allIds.length === 0;
return (
@ -66,6 +68,7 @@ export const OverviewAlerts = () => {
status?.enabledMonitorQueryIds.length > 0
? status?.enabledMonitorQueryIds
: ['false-id'],
...(locations?.length ? { 'observer.geo.name': locations } : {}),
},
filters: [{ field: 'kibana.alert.status', values: ['active', 'recovered'] }],
color: theme.eui.euiColorVis1,
@ -92,6 +95,7 @@ export const OverviewAlerts = () => {
status?.enabledMonitorQueryIds.length > 0
? status?.enabledMonitorQueryIds
: ['false-id'],
...(locations?.length ? { 'observer.geo.name': locations } : {}),
},
dataType: 'alerts',
selectedMetricField: RECORDS_FIELD,

View file

@ -18,7 +18,7 @@ import { useSelector } from 'react-redux';
import { i18n } from '@kbn/i18n';
import { selectOverviewStatus } from '../../../../../state/overview_status';
import { OverviewErrorsSparklines } from './overview_errors_sparklines';
import { useRefreshedRange } from '../../../../../hooks';
import { useRefreshedRange, useGetUrlParams } from '../../../../../hooks';
import { OverviewErrorsCount } from './overview_errors_count';
export function OverviewErrors() {
@ -28,6 +28,8 @@ export function OverviewErrors() {
const { from, to } = useRefreshedRange(6, 'hours');
const params = useGetUrlParams();
return (
<EuiPanel hasShadow={false} hasBorder>
<EuiTitle size="xs">
@ -43,6 +45,7 @@ export function OverviewErrors() {
from={from}
to={to}
monitorIds={status?.enabledMonitorQueryIds ?? []}
locations={params.locations}
/>
</EuiFlexItem>
<EuiFlexItem grow={true}>
@ -50,6 +53,7 @@ export function OverviewErrors() {
from={from}
to={to}
monitorIds={status?.enabledMonitorQueryIds ?? []}
locations={params.locations}
/>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -16,13 +16,14 @@ interface MonitorErrorsCountProps {
to: string;
locationLabel?: string;
monitorIds: string[];
locations?: string[];
}
export const OverviewErrorsCount = ({
monitorIds,
from,
to,
locationLabel,
locations,
}: MonitorErrorsCountProps) => {
const { observability } = useKibana<ClientPluginsStart>().services;
@ -41,7 +42,7 @@ export const OverviewErrorsCount = ({
time,
reportDefinitions: {
'monitor.id': monitorIds.length > 0 ? monitorIds : ['false-monitor-id'],
...(locationLabel ? { 'observer.geo.name': [locationLabel] } : {}),
...(locations?.length ? { 'observer.geo.name': locations } : {}),
},
dataType: 'synthetics',
selectedMetricField: 'monitor_errors',

View file

@ -15,8 +15,9 @@ interface Props {
from: string;
to: string;
monitorIds: string[];
locations?: string[];
}
export const OverviewErrorsSparklines = ({ from, to, monitorIds }: Props) => {
export const OverviewErrorsSparklines = ({ from, to, monitorIds, locations }: Props) => {
const { observability } = useKibana<ClientPluginsStart>().services;
const { ExploratoryViewEmbeddable } = observability;
@ -38,6 +39,7 @@ export const OverviewErrorsSparklines = ({ from, to, monitorIds }: Props) => {
seriesType: 'area',
reportDefinitions: {
'monitor.id': monitorIds.length > 0 ? monitorIds : ['false-monitor-id'],
...(locations?.length ? { 'observer.geo.name': locations } : {}),
},
dataType: 'synthetics',
selectedMetricField: 'monitor_errors',

View file

@ -21,7 +21,7 @@ function title(t?: number) {
export function OverviewStatus() {
const { statusFilter } = useGetUrlParams();
const { status, error: statusError } = useOverviewStatus();
const { status, error: statusError } = useOverviewStatus({ scopeStatusByLocation: true });
const dispatch = useDispatch();
const [statusConfig, setStatusConfig] = useState({
up: status?.up,

View file

@ -100,11 +100,11 @@ export function* upsertMonitorEffect() {
if (action.payload.shouldQuietFetchAfterSuccess !== false) {
const monitorState = yield select(selectOverviewState);
if (hasPageState(monitorState)) {
yield put(quietFetchOverviewAction.get(monitorState.pageState));
yield put(
quietFetchOverviewAction.get(monitorState.pageState as MonitorOverviewPageState)
);
yield put(
quietFetchOverviewStatusAction.get(monitorState.pageState as MonitorOverviewPageState)
quietFetchOverviewStatusAction.get({
pageState: monitorState.pageState,
})
);
}
}

View file

@ -12,12 +12,12 @@ import { createAsyncAction } from '../utils/actions';
import { OverviewStatus } from '../../../../../common/runtime_types';
export const fetchOverviewStatusAction = createAsyncAction<
MonitorOverviewPageState,
{ pageState: MonitorOverviewPageState; scopeStatusByLocation?: boolean },
OverviewStatus
>('fetchOverviewStatusAction');
export const quietFetchOverviewStatusAction = createAsyncAction<
MonitorOverviewPageState,
{ pageState: MonitorOverviewPageState; scopeStatusByLocation?: boolean },
OverviewStatus
>('quietFetchOverviewStatusAction');

View file

@ -11,9 +11,17 @@ import { OverviewStatus, OverviewStatusCodec } from '../../../../../common/runti
import { apiService } from '../../../../utils/api_service';
import { toStatusOverviewQueryArgs } from '../overview/api';
export const fetchOverviewStatus = async (
pageState: MonitorOverviewPageState
): Promise<OverviewStatus> => {
export const fetchOverviewStatus = async ({
pageState,
scopeStatusByLocation,
}: {
pageState: MonitorOverviewPageState;
scopeStatusByLocation?: boolean;
}): Promise<OverviewStatus> => {
const params = toStatusOverviewQueryArgs(pageState);
return apiService.get(SYNTHETICS_API_URLS.OVERVIEW_STATUS, params, OverviewStatusCodec);
return apiService.get(
SYNTHETICS_API_URLS.OVERVIEW_STATUS,
{ ...params, scopeStatusByLocation },
OverviewStatusCodec
);
};

View file

@ -67,11 +67,11 @@ export class StatusRuleExecutor {
}
async getAllLocationNames() {
const { publicLocations, privateLocations } = await getAllLocations(
this.server,
this.syntheticsMonitorClient,
this.soClient
);
const { publicLocations, privateLocations } = await getAllLocations({
server: this.server,
syntheticsMonitorClient: this.syntheticsMonitorClient,
savedObjectsClient: this.soClient,
});
publicLocations.forEach((loc) => {
this.locationIdNameMap[loc.label] = loc.id;

View file

@ -109,15 +109,7 @@ export type UMRouteHandler = ({
subject?: Subject<unknown>;
}) => IKibanaResponse<any> | Promise<IKibanaResponse<any>>;
export type SyntheticsRouteHandler = ({
uptimeEsClient,
context,
request,
response,
server,
savedObjectsClient,
subject: Subject,
}: {
export interface RouteContext {
uptimeEsClient: UptimeEsClient;
context: UptimeRequestHandlerContext;
request: SyntheticsRequest;
@ -126,7 +118,17 @@ export type SyntheticsRouteHandler = ({
server: UptimeServerSetup;
syntheticsMonitorClient: SyntheticsMonitorClient;
subject?: Subject<unknown>;
}) => IKibanaResponse<any> | Promise<IKibanaResponse<any>>;
}
export type SyntheticsRouteHandler = ({
uptimeEsClient,
context,
request,
response,
server,
savedObjectsClient,
subject: Subject,
}: RouteContext) => IKibanaResponse<any> | Promise<IKibanaResponse<any>>;
export type SyntheticsStreamingRouteHandler = ({
uptimeEsClient,

View file

@ -6,11 +6,12 @@
*/
import { schema, TypeOf } from '@kbn/config-schema';
import { SavedObjectsClientContract, SavedObjectsFindResponse } from '@kbn/core/server';
import { SyntheticsService } from '../synthetics_service/synthetics_service';
import { SavedObjectsFindResponse } from '@kbn/core/server';
import { getAllLocations } from '../synthetics_service/get_all_locations';
import { EncryptedSyntheticsMonitor, ServiceLocations } from '../../common/runtime_types';
import { monitorAttributes } from '../../common/types/saved_objects';
import { syntheticsMonitorType } from '../legacy_uptime/lib/saved_objects/synthetics_monitor';
import { RouteContext } from '../legacy_uptime/routes';
export const QuerySchema = schema.object({
page: schema.maybe(schema.number()),
@ -40,6 +41,7 @@ export const OverviewStatusSchema = schema.object({
projects: schema.maybe(schema.oneOf([schema.string(), schema.arrayOf(schema.string())])),
schedules: schema.maybe(schema.oneOf([schema.string(), schema.arrayOf(schema.string())])),
status: schema.maybe(schema.oneOf([schema.string(), schema.arrayOf(schema.string())])),
scopeStatusByLocation: schema.maybe(schema.boolean()),
});
export type OverviewStatusQuery = TypeOf<typeof OverviewStatusSchema>;
@ -54,10 +56,8 @@ export const SEARCH_FIELDS = [
'project_id.text',
];
export const getMonitors = (
request: MonitorsQuery,
syntheticsService: SyntheticsService,
savedObjectsClient: SavedObjectsClientContract
export const getMonitors = async (
context: RouteContext
): Promise<SavedObjectsFindResponse<EncryptedSyntheticsMonitor>> => {
const {
perPage = 50,
@ -73,19 +73,19 @@ export const getMonitors = (
searchAfter,
projects,
schedules,
} = request as MonitorsQuery;
} = context.request.query as MonitorsQuery;
const filterStr = getMonitorFilters({
const filterStr = await getMonitorFilters({
filter,
monitorTypes,
tags,
locations,
serviceLocations: syntheticsService.locations,
projects,
schedules,
context,
});
return savedObjectsClient.find({
return context.savedObjectsClient.find({
type: syntheticsMonitorType,
perPage,
page,
@ -99,15 +99,14 @@ export const getMonitors = (
});
};
export const getMonitorFilters = ({
export const getMonitorFilters = async ({
tags,
ports,
filter,
locations,
projects,
monitorTypes,
schedules,
serviceLocations,
context,
}: {
filter?: string;
tags?: string | string[];
@ -115,10 +114,9 @@ export const getMonitorFilters = ({
locations?: string | string[];
projects?: string | string[];
schedules?: string | string[];
ports?: string | string[];
serviceLocations: ServiceLocations;
context: RouteContext;
}) => {
const locationFilter = parseLocationFilter(serviceLocations, locations);
const locationFilter = await parseLocationFilter(context, locations);
return [
filter,
@ -160,18 +158,20 @@ export const getKqlFilter = ({
return `${fieldKey}:"${values}"`;
};
const parseLocationFilter = (serviceLocations: ServiceLocations, locations?: string | string[]) => {
if (!locations) {
const parseLocationFilter = async (context: RouteContext, locations?: string | string[]) => {
if (!locations || locations?.length === 0) {
return '';
}
const { allLocations } = await getAllLocations(context);
if (Array.isArray(locations)) {
return locations
.map((loc) => findLocationItem(loc, serviceLocations)?.id ?? '')
.map((loc) => findLocationItem(loc, allLocations)?.id ?? '')
.filter((val) => !!val);
}
return findLocationItem(locations, serviceLocations)?.id ?? '';
return findLocationItem(locations, allLocations)?.id ?? '';
};
export const findLocationItem = (query: string, locations: ServiceLocations) => {

View file

@ -45,11 +45,11 @@ export const addSyntheticsProjectMonitorRouteLegacy: SyntheticsStreamingRouteFac
const { id: spaceId } = await server.spaces.spacesService.getActiveSpace(request);
const { keep_stale: keepStale, project: projectId } = request.body || {};
const { publicLocations, privateLocations } = await getAllLocations(
const { publicLocations, privateLocations } = await getAllLocations({
server,
syntheticsMonitorClient,
savedObjectsClient
);
savedObjectsClient,
});
const encryptedSavedObjectsClient = server.encryptedSavedObjects.getClient();
const pushMonitorFormatter = new ProjectMonitorFormatterLegacy({

View file

@ -25,13 +25,8 @@ export const deleteSyntheticsMonitorProjectRoute: SyntheticsRestApiRouteFactory
projectName: schema.string(),
}),
},
handler: async ({
request,
response,
savedObjectsClient,
server,
syntheticsMonitorClient,
}): Promise<any> => {
handler: async (routeContext): Promise<any> => {
const { request, response, savedObjectsClient, server, syntheticsMonitorClient } = routeContext;
const { projectName } = request.params;
const { monitors: monitorsToDelete } = request.body;
const decodedProjectName = decodeURI(projectName);
@ -43,20 +38,20 @@ export const deleteSyntheticsMonitorProjectRoute: SyntheticsRestApiRouteFactory
});
}
const { saved_objects: monitors } = await getMonitors(
{
filter: `${syntheticsMonitorType}.attributes.${
ConfigKey.PROJECT_ID
}: "${decodedProjectName}" AND ${getKqlFilter({
field: 'journey_id',
values: monitorsToDelete.map((id: string) => `${id}`),
})}`,
fields: [],
perPage: 500,
const deleteFilter = `${syntheticsMonitorType}.attributes.${
ConfigKey.PROJECT_ID
}: "${decodedProjectName}" AND ${getKqlFilter({
field: 'journey_id',
values: monitorsToDelete.map((id: string) => `${id}`),
})}`;
const { saved_objects: monitors } = await getMonitors({
...routeContext,
request: {
...request,
query: { ...request.query, filter: deleteFilter, fields: [], perPage: 500 },
},
syntheticsMonitorClient.syntheticsService,
savedObjectsClient
);
});
const {
integrations: { writeIntegrationPolicies },

View file

@ -65,7 +65,8 @@ export const getAllSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () =>
validate: {
query: QuerySchema,
},
handler: async ({ request, savedObjectsClient, syntheticsMonitorClient }): Promise<any> => {
handler: async (routeContext): Promise<any> => {
const { request, savedObjectsClient, syntheticsMonitorClient } = routeContext;
const totalCountQuery = async () => {
if (isMonitorsQueryFiltered(request.query)) {
return savedObjectsClient.find({
@ -77,7 +78,7 @@ export const getAllSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () =>
};
const [queryResult, totalCount] = await Promise.all([
getMonitors(request.query, syntheticsMonitorClient.syntheticsService, savedObjectsClient),
getMonitors(routeContext),
totalCountQuery(),
]);
@ -101,7 +102,9 @@ export const getSyntheticsMonitorOverviewRoute: SyntheticsRestApiRouteFactory =
validate: {
query: QuerySchema,
},
handler: async ({ request, savedObjectsClient, syntheticsMonitorClient }): Promise<any> => {
handler: async (routeContext): Promise<any> => {
const { request, savedObjectsClient } = routeContext;
const {
sortField,
sortOrder,
@ -109,9 +112,9 @@ export const getSyntheticsMonitorOverviewRoute: SyntheticsRestApiRouteFactory =
locations: queriedLocations,
} = request.query as MonitorsQuery;
const filtersStr = getMonitorFilters({
const filtersStr = await getMonitorFilters({
...request.query,
serviceLocations: syntheticsMonitorClient.syntheticsService.locations,
context: routeContext,
});
const allMonitorConfigs = await getAllMonitors({

View file

@ -25,31 +25,33 @@ export const getSyntheticsProjectMonitorsRoute: SyntheticsRestApiRouteFactory =
}),
query: querySchema,
},
handler: async ({
request,
response,
server: { logger },
savedObjectsClient,
syntheticsMonitorClient,
}): Promise<any> => {
handler: async (routeContext): Promise<any> => {
const {
request,
server: { logger },
} = routeContext;
const { projectName } = request.params;
const { per_page: perPage = 500, search_after: searchAfter } = request.query;
const decodedProjectName = decodeURI(projectName);
const decodedSearchAfter = searchAfter ? decodeURI(searchAfter) : undefined;
try {
const { saved_objects: monitors, total } = await getMonitors(
{
filter: `${syntheticsMonitorType}.attributes.${ConfigKey.PROJECT_ID}: "${decodedProjectName}"`,
fields: [ConfigKey.JOURNEY_ID, ConfigKey.CONFIG_HASH],
perPage,
sortField: ConfigKey.JOURNEY_ID,
sortOrder: 'asc',
searchAfter: decodedSearchAfter ? [...decodedSearchAfter.split(',')] : undefined,
const { saved_objects: monitors, total } = await getMonitors({
...routeContext,
request: {
...request,
query: {
...request.query,
filter: `${syntheticsMonitorType}.attributes.${ConfigKey.PROJECT_ID}: "${decodedProjectName}"`,
fields: [ConfigKey.JOURNEY_ID, ConfigKey.CONFIG_HASH],
perPage,
sortField: ConfigKey.JOURNEY_ID,
sortOrder: 'asc',
searchAfter: decodedSearchAfter ? [...decodedSearchAfter.split(',')] : undefined,
},
},
syntheticsMonitorClient.syntheticsService,
savedObjectsClient
);
});
const projectMonitors = monitors.map((monitor) => ({
journey_id: monitor.attributes[ConfigKey.JOURNEY_ID],
hash: monitor.attributes[ConfigKey.CONFIG_HASH] || '',

View file

@ -6,20 +6,16 @@
*/
import { intersection } from 'lodash';
import datemath, { Unit } from '@kbn/datemath';
import { SavedObjectsClientContract } from '@kbn/core/server';
import moment from 'moment';
import { ConfigKey } from '../../../common/runtime_types';
import {
getAllMonitors,
processMonitors,
} from '../../saved_objects/synthetics_monitor/get_all_monitors';
import { UptimeServerSetup } from '../../legacy_uptime/lib/adapters';
import { queryMonitorStatus } from '../../queries/query_monitor_status';
import { SYNTHETICS_API_URLS } from '../../../common/constants';
import { UMServerLibs } from '../../legacy_uptime/uptime_server';
import { SyntheticsRestApiRouteFactory } from '../../legacy_uptime/routes';
import { UptimeEsClient } from '../../legacy_uptime/lib/lib';
import { SyntheticsMonitorClient } from '../../synthetics_service/synthetics_monitor/synthetics_monitor_client';
import { RouteContext, SyntheticsRestApiRouteFactory } from '../../legacy_uptime/routes';
import { getMonitorFilters, OverviewStatusSchema, OverviewStatusQuery } from '../common';
/**
@ -40,14 +36,10 @@ export function periodToMs(schedule: { number: string; unit: Unit }) {
* Subsequently, fetch the status for each monitor per location in the data streams.
* @returns The counts of up/down/disabled monitor by location, and a map of each monitor:location status.
*/
export async function getStatus(
server: UptimeServerSetup,
uptimeEsClient: UptimeEsClient,
soClient: SavedObjectsClientContract,
syntheticsMonitorClient: SyntheticsMonitorClient,
params: OverviewStatusQuery
) {
const { query, locations: queryLocations } = params;
export async function getStatus(context: RouteContext, params: OverviewStatusQuery) {
const { uptimeEsClient, syntheticsMonitorClient, savedObjectsClient, server } = context;
const { query, locations: queryLocations, scopeStatusByLocation = true } = params;
/**
* Walk through all monitor saved objects, bucket IDs by disabled/enabled status.
*
@ -55,12 +47,13 @@ export async function getStatus(
* latest ping for all enabled monitors.
*/
const filtersStr = getMonitorFilters({
const filtersStr = await getMonitorFilters({
...params,
serviceLocations: syntheticsMonitorClient.syntheticsService.locations,
context,
});
const allMonitors = await getAllMonitors({
soClient,
soClient: savedObjectsClient,
search: query ? `${query}*` : undefined,
filter: filtersStr,
fields: [
@ -83,14 +76,15 @@ export async function getStatus(
disabledMonitorsCount,
projectMonitorsCount,
monitorQueryIdToConfigIdMap,
} = await processMonitors(allMonitors, server, soClient, syntheticsMonitorClient);
} = await processMonitors(allMonitors, server, savedObjectsClient, syntheticsMonitorClient);
// Account for locations filter
const queryLocationsArray =
queryLocations && !Array.isArray(queryLocations) ? [queryLocations] : queryLocations;
const listOfLocationAfterFilter = queryLocationsArray
? intersection(listOfLocations, queryLocationsArray)
: listOfLocations;
const listOfLocationAfterFilter =
queryLocationsArray && scopeStatusByLocation
? intersection(listOfLocations, queryLocationsArray)
: listOfLocations;
const range = {
from: moment().subtract(maxPeriod, 'milliseconds').subtract(20, 'minutes').toISOString(),
@ -128,20 +122,10 @@ export const createGetCurrentStatusRoute: SyntheticsRestApiRouteFactory = (libs:
validate: {
query: OverviewStatusSchema,
},
handler: async ({
server,
uptimeEsClient,
savedObjectsClient,
syntheticsMonitorClient,
request,
}): Promise<any> => {
handler: async (routeContext): Promise<any> => {
const { request } = routeContext;
const params = request.query as OverviewStatusQuery;
return await getStatus(
server,
uptimeEsClient,
savedObjectsClient,
syntheticsMonitorClient,
params
);
return await getStatus(routeContext, params);
},
});

View file

@ -14,14 +14,14 @@ export const getServiceLocationsRoute: SyntheticsRestApiRouteFactory = () => ({
path: API_URLS.SERVICE_LOCATIONS,
validate: {},
handler: async ({ server, savedObjectsClient, syntheticsMonitorClient }): Promise<any> => {
const { publicLocations, privateLocations, throttling } = await getAllLocations(
const { throttling, allLocations } = await getAllLocations({
server,
syntheticsMonitorClient,
savedObjectsClient
);
savedObjectsClient,
});
return {
locations: [...publicLocations, ...privateLocations],
locations: allLocations,
throttling,
};
},

View file

@ -87,11 +87,11 @@ export const processMonitors = async (
const getLocationLabel = async (locationId: string) => {
if (!allLocations) {
const { publicLocations, privateLocations } = await getAllLocations(
const { publicLocations, privateLocations } = await getAllLocations({
server,
syntheticsMonitorClient,
soClient
);
savedObjectsClient: soClient,
});
allLocations = [...publicLocations, ...privateLocations];
}

View file

@ -10,20 +10,29 @@ import { getServiceLocations } from './get_service_locations';
import { SyntheticsMonitorClient } from './synthetics_monitor/synthetics_monitor_client';
import { UptimeServerSetup } from '../legacy_uptime/lib/adapters/framework';
export async function getAllLocations(
server: UptimeServerSetup,
syntheticsMonitorClient: SyntheticsMonitorClient,
savedObjectsClient: SavedObjectsClientContract
) {
export async function getAllLocations({
syntheticsMonitorClient,
savedObjectsClient,
server,
}: {
server: UptimeServerSetup;
syntheticsMonitorClient: SyntheticsMonitorClient;
savedObjectsClient: SavedObjectsClientContract;
}) {
try {
const [privateLocations, { locations: publicLocations, throttling }] = await Promise.all([
getPrivateLocations(syntheticsMonitorClient, savedObjectsClient),
getServicePublicLocations(server, syntheticsMonitorClient),
]);
return { publicLocations, privateLocations, throttling };
return {
publicLocations,
privateLocations,
throttling,
allLocations: [...publicLocations, ...privateLocations],
};
} catch (e) {
server.logger.error(e);
return { publicLocations: [], privateLocations: [] };
return { publicLocations: [], privateLocations: [], allLocations: [] };
}
}

View file

@ -120,11 +120,11 @@ export class ProjectMonitorFormatter {
}
init = async () => {
const locationsPromise = getAllLocations(
this.server,
this.syntheticsMonitorClient,
this.savedObjectsClient
);
const locationsPromise = getAllLocations({
server: this.server,
syntheticsMonitorClient: this.syntheticsMonitorClient,
savedObjectsClient: this.savedObjectsClient,
});
const existingMonitorsPromise = this.getProjectMonitorsForProject();
const [locations, existingMonitors] = await Promise.all([

View file

@ -30,7 +30,6 @@ import { syntheticsMonitorType } from '../../legacy_uptime/lib/saved_objects/syn
export class SyntheticsMonitorClient {
public syntheticsService: SyntheticsService;
public privateLocationAPI: SyntheticsPrivateLocation;
constructor(syntheticsService: SyntheticsService, server: UptimeServerSetup) {