diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/edit_monitor_bulk.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/edit_monitor_bulk.ts index 833e0203e3817..f106dc46c0708 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/edit_monitor_bulk.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/edit_monitor_bulk.ts @@ -28,7 +28,6 @@ import { export interface MonitorConfigUpdate { normalizedMonitor: SyntheticsMonitor; monitorWithRevision: SyntheticsMonitorWithSecretsAttributes; - previousMonitor: SavedObject; decryptedPreviousMonitor: SavedObject; } @@ -40,14 +39,14 @@ const updateConfigSavedObjects = async ({ monitorsToUpdate: MonitorConfigUpdate[]; }) => { return await routeContext.savedObjectsClient.bulkUpdate( - monitorsToUpdate.map(({ previousMonitor, monitorWithRevision }) => ({ + monitorsToUpdate.map(({ monitorWithRevision, decryptedPreviousMonitor }) => ({ type: syntheticsMonitorType, - id: previousMonitor.id, + id: decryptedPreviousMonitor.id, attributes: { ...monitorWithRevision, - [ConfigKey.CONFIG_ID]: previousMonitor.id, + [ConfigKey.CONFIG_ID]: decryptedPreviousMonitor.id, [ConfigKey.MONITOR_QUERY_ID]: - monitorWithRevision[ConfigKey.CUSTOM_HEARTBEAT_ID] || previousMonitor.id, + monitorWithRevision[ConfigKey.CUSTOM_HEARTBEAT_ID] || decryptedPreviousMonitor.id, }, })) ); @@ -67,15 +66,14 @@ async function syncUpdatedMonitors({ const { syntheticsMonitorClient } = routeContext; return await syntheticsMonitorClient.editMonitors( - monitorsToUpdate.map(({ normalizedMonitor, previousMonitor, decryptedPreviousMonitor }) => ({ + monitorsToUpdate.map(({ normalizedMonitor, decryptedPreviousMonitor }) => ({ monitor: { ...(normalizedMonitor as MonitorFields), - [ConfigKey.CONFIG_ID]: previousMonitor.id, + [ConfigKey.CONFIG_ID]: decryptedPreviousMonitor.id, [ConfigKey.MONITOR_QUERY_ID]: - normalizedMonitor[ConfigKey.CUSTOM_HEARTBEAT_ID] || previousMonitor.id, + normalizedMonitor[ConfigKey.CUSTOM_HEARTBEAT_ID] || decryptedPreviousMonitor.id, }, - id: previousMonitor.id, - previousMonitor, + id: decryptedPreviousMonitor.id, decryptedPreviousMonitor, })), privateLocations, @@ -104,9 +102,9 @@ export const syncEditedMonitorBulk = async ({ const { failedPolicyUpdates, publicSyncErrors } = editSyncResponse; - monitorsToUpdate.forEach(({ normalizedMonitor, previousMonitor }) => { + monitorsToUpdate.forEach(({ normalizedMonitor, decryptedPreviousMonitor }) => { const editedMonitorSavedObject = editedMonitorSavedObjects?.saved_objects.find( - (obj) => obj.id === previousMonitor.id + (obj) => obj.id === decryptedPreviousMonitor.id ); sendTelemetryEvents( @@ -114,7 +112,7 @@ export const syncEditedMonitorBulk = async ({ server.telemetry, formatTelemetryUpdateEvent( editedMonitorSavedObject as SavedObjectsUpdateResponse, - previousMonitor, + decryptedPreviousMonitor.updated_at, server.stackVersion, Boolean((normalizedMonitor as MonitorFields)[ConfigKey.SOURCE_INLINE]), publicSyncErrors @@ -150,9 +148,9 @@ export const rollbackCompletely = async ({ const { savedObjectsClient, server } = routeContext; try { await savedObjectsClient.bulkUpdate( - monitorsToUpdate.map(({ previousMonitor, decryptedPreviousMonitor }) => ({ + monitorsToUpdate.map(({ decryptedPreviousMonitor }) => ({ type: syntheticsMonitorType, - id: previousMonitor.id, + id: decryptedPreviousMonitor.id, attributes: decryptedPreviousMonitor.attributes, })) ); @@ -167,7 +165,6 @@ export const rollbackFailedUpdates = async ({ monitorsToUpdate, }: { monitorsToUpdate: Array<{ - previousMonitor: SavedObject; decryptedPreviousMonitor: SavedObject; }>; routeContext: RouteContext; @@ -194,12 +191,12 @@ export const rollbackFailedUpdates = async ({ }); const monitorsToRevert = monitorsToUpdate - .filter(({ previousMonitor }) => { - return failedConfigs[previousMonitor.id]; + .filter(({ decryptedPreviousMonitor }) => { + return failedConfigs[decryptedPreviousMonitor.id]; }) - .map(({ previousMonitor, decryptedPreviousMonitor }) => ({ + .map(({ decryptedPreviousMonitor }) => ({ type: syntheticsMonitorType, - id: previousMonitor.id, + id: decryptedPreviousMonitor.id, attributes: decryptedPreviousMonitor.attributes, })); diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.ts index d9261847db1ab..d460b71037950 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.ts @@ -272,7 +272,7 @@ export const syncEditedMonitor = async ({ server.telemetry, formatTelemetryUpdateEvent( editedMonitorSavedObject as SavedObjectsUpdateResponse, - decryptedPreviousMonitor, + decryptedPreviousMonitor.updated_at, server.stackVersion, Boolean((normalizedMonitor as MonitorFields)[ConfigKey.SOURCE_INLINE]), publicSyncErrors diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/get_monitor_project.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/get_monitor_project.ts index b0b4eee392d56..ac55807f9412f 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/get_monitor_project.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/get_monitor_project.ts @@ -32,7 +32,7 @@ export const getSyntheticsProjectMonitorsRoute: SyntheticsRestApiRouteFactory = } = routeContext; const { projectName } = request.params; - const { per_page: perPage = 500, search_after: searchAfter } = request.query; + const { per_page: perPage = 1000, search_after: searchAfter } = request.query; const decodedProjectName = decodeURI(projectName); const decodedSearchAfter = searchAfter ? decodeURI(searchAfter) : undefined; diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/telemetry/monitor_upgrade_sender.test.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/telemetry/monitor_upgrade_sender.test.ts index 299ab62f09028..761472bb7fa8c 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/telemetry/monitor_upgrade_sender.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/telemetry/monitor_upgrade_sender.test.ts @@ -152,7 +152,7 @@ describe('monitor upgrade telemetry helpers', () => { it('handles formatting update events', () => { const actual = formatTelemetryUpdateEvent( createTestConfig({}, '2011-10-05T16:48:00.000Z'), - testConfig, + testConfig.updated_at, stackVersion, false, errors diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/telemetry/monitor_upgrade_sender.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/telemetry/monitor_upgrade_sender.ts index f008d00a18536..f000108620f45 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/telemetry/monitor_upgrade_sender.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/telemetry/monitor_upgrade_sender.ts @@ -109,23 +109,22 @@ export function formatTelemetryEvent({ export function formatTelemetryUpdateEvent( currentMonitor: SavedObjectsUpdateResponse, - previousMonitor: SavedObject, + previousMonitorUpdatedAt: string | undefined, stackVersion: string, isInlineScript: boolean, errors?: ServiceLocationErrors | null ) { let durationSinceLastUpdated: number = 0; - if (currentMonitor.updated_at && previousMonitor.updated_at) { + if (currentMonitor.updated_at && previousMonitorUpdatedAt) { durationSinceLastUpdated = - new Date(currentMonitor.updated_at).getTime() - - new Date(previousMonitor.updated_at).getTime(); + new Date(currentMonitor.updated_at).getTime() - new Date(previousMonitorUpdatedAt).getTime(); } return formatTelemetryEvent({ stackVersion, monitor: currentMonitor as SavedObject, durationSinceLastUpdated, - lastUpdatedAt: previousMonitor.updated_at, + lastUpdatedAt: previousMonitorUpdatedAt, isInlineScript, errors, }); diff --git a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/project_monitor/project_monitor_formatter.ts b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/project_monitor/project_monitor_formatter.ts index 6069076e375a2..1fe5d30048418 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/project_monitor/project_monitor_formatter.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/project_monitor/project_monitor_formatter.ts @@ -45,6 +45,17 @@ import { normalizeProjectMonitor } from './normalizers'; type FailedError = Array<{ id?: string; reason: string; details: string; payload?: object }>; +export interface ExistingMonitor { + [ConfigKey.JOURNEY_ID]: string; + [ConfigKey.CONFIG_ID]: string; + [ConfigKey.REVISION]: number; + [ConfigKey.MONITOR_TYPE]: string; +} + +export interface PreviousMonitorForUpdate extends ExistingMonitor { + updated_at?: string; +} + export const CANNOT_UPDATE_MONITOR_TO_DIFFERENT_TYPE = i18n.translate( 'xpack.synthetics.service.projectMonitors.cannotUpdateMonitorToDifferentType', { @@ -128,14 +139,13 @@ export class ProjectMonitorFormatter { const normalizedNewMonitors: SyntheticsMonitor[] = []; const normalizedUpdateMonitors: Array<{ - previousMonitor: SavedObjectsFindResult; + previousMonitor: PreviousMonitorForUpdate; monitor: SyntheticsMonitor; }> = []; for (const monitor of this.monitors) { const previousMonitor = existingMonitors.find( - (monitorObj) => - (monitorObj.attributes as SyntheticsMonitor)[ConfigKey.JOURNEY_ID] === monitor.id + (monitorObj) => monitorObj[ConfigKey.JOURNEY_ID] === monitor.id ); const normM = await this.validateProjectMonitor({ @@ -146,7 +156,7 @@ export class ProjectMonitorFormatter { if (normM) { if ( previousMonitor && - previousMonitor.attributes[ConfigKey.MONITOR_TYPE] !== normM[ConfigKey.MONITOR_TYPE] + previousMonitor[ConfigKey.MONITOR_TYPE] !== normM[ConfigKey.MONITOR_TYPE] ) { this.failedMonitors.push({ reason: CANNOT_UPDATE_MONITOR_TO_DIFFERENT_TYPE, @@ -157,7 +167,7 @@ export class ProjectMonitorFormatter { 'Monitor {monitorId} of type {previousType} cannot be updated to type {currentType}. Please delete the monitor first and try again.', values: { currentType: monitor.type, - previousType: previousMonitor.attributes[ConfigKey.MONITOR_TYPE], + previousType: previousMonitor[ConfigKey.MONITOR_TYPE], monitorId: monitor.id, }, } @@ -246,19 +256,33 @@ export class ProjectMonitorFormatter { } }; - public getProjectMonitorsForProject = async () => { - const finder = this.savedObjectsClient.createPointInTimeFinder({ + public getProjectMonitorsForProject = async (): Promise => { + const journeyIds = this.monitors.map((monitor) => monitor.id); + const journeyFilter = getSavedObjectKqlFilter({ + field: ConfigKey.JOURNEY_ID, + values: journeyIds, + }); + const finder = this.savedObjectsClient.createPointInTimeFinder({ type: syntheticsMonitorType, perPage: 5000, - filter: this.projectFilter, + filter: `${this.projectFilter} AND ${journeyFilter}`, + fields: [ + ConfigKey.JOURNEY_ID, + ConfigKey.CONFIG_ID, + ConfigKey.REVISION, + ConfigKey.MONITOR_TYPE, + ], }); - const hits: Array> = []; + const hits: PreviousMonitorForUpdate[] = []; for await (const result of finder.find()) { hits.push( - ...(result.saved_objects as Array< - SavedObjectsFindResult - >) + ...result.saved_objects.map((monitor) => { + return { + ...monitor.attributes, + updated_at: monitor.updated_at, + }; + }) ); } @@ -333,10 +357,8 @@ export class ProjectMonitorFormatter { } }; - private getDecryptedMonitors = async ( - monitors: Array> - ) => { - const configIds = monitors.map((monitor) => monitor.attributes[ConfigKey.CONFIG_ID]); + private getDecryptedMonitors = async (monitors: PreviousMonitorForUpdate[]) => { + const configIds = monitors.map((monitor) => monitor[ConfigKey.CONFIG_ID]); const monitorFilter = getSavedObjectKqlFilter({ field: ConfigKey.CONFIG_ID, values: configIds, @@ -344,7 +366,7 @@ export class ProjectMonitorFormatter { const finder = await this.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( { - search: monitorFilter, + filter: monitorFilter, type: syntheticsMonitorType, perPage: 500, namespaces: [this.spaceId], @@ -365,7 +387,7 @@ export class ProjectMonitorFormatter { private updateMonitorsBulk = async ( monitors: Array<{ monitor: SyntheticsMonitor; - previousMonitor: SavedObjectsFindResult; + previousMonitor: PreviousMonitorForUpdate; }> ): Promise< | { @@ -390,10 +412,11 @@ export class ProjectMonitorFormatter { const monitorsToUpdate: MonitorConfigUpdate[] = []; decryptedPreviousMonitors.forEach((decryptedPreviousMonitor) => { - const monitor = monitors.find((m) => m.previousMonitor.id === decryptedPreviousMonitor.id); + const monitor = monitors.find( + (m) => m.previousMonitor[ConfigKey.CONFIG_ID] === decryptedPreviousMonitor.id + ); if (monitor) { const normalizedMonitor = monitor?.monitor; - const previousMonitor = monitor?.previousMonitor; const { attributes: { [ConfigKey.REVISION]: _, ...normalizedPrevMonitorAttr }, } = normalizeSecrets(decryptedPreviousMonitor); @@ -401,11 +424,10 @@ export class ProjectMonitorFormatter { const monitorWithRevision = formatSecrets({ ...normalizedPrevMonitorAttr, ...normalizedMonitor, - revision: (previousMonitor.attributes[ConfigKey.REVISION] || 0) + 1, + revision: (decryptedPreviousMonitor.attributes[ConfigKey.REVISION] || 0) + 1, }); monitorsToUpdate.push({ normalizedMonitor, - previousMonitor, monitorWithRevision, decryptedPreviousMonitor, }); diff --git a/x-pack/test/api_integration/apis/synthetics/get_monitor_project.ts b/x-pack/test/api_integration/apis/synthetics/get_monitor_project.ts index 53089d2bec2d3..dd3fcbef3088d 100644 --- a/x-pack/test/api_integration/apis/synthetics/get_monitor_project.ts +++ b/x-pack/test/api_integration/apis/synthetics/get_monitor_project.ts @@ -95,6 +95,9 @@ export default function ({ getService }: FtrProviderContext) { const firstPageResponse = await supertest .get(SYNTHETICS_API_URLS.SYNTHETICS_MONITORS_PROJECT.replace('{projectName}', project)) + .query({ + per_page: 500, + }) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -185,6 +188,9 @@ export default function ({ getService }: FtrProviderContext) { const firstPageResponse = await supertest .get(SYNTHETICS_API_URLS.SYNTHETICS_MONITORS_PROJECT.replace('{projectName}', project)) + .query({ + per_page: 500, + }) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -279,6 +285,9 @@ export default function ({ getService }: FtrProviderContext) { const firstPageResponse = await supertest .get(SYNTHETICS_API_URLS.SYNTHETICS_MONITORS_PROJECT.replace('{projectName}', project)) + .query({ + per_page: 500, + }) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -372,6 +381,9 @@ export default function ({ getService }: FtrProviderContext) { .expect(200); const firstPageResponse = await supertest .get(SYNTHETICS_API_URLS.SYNTHETICS_MONITORS_PROJECT.replace('{projectName}', project)) + .query({ + per_page: 500, + }) .set('kbn-xsrf', 'true') .send() .expect(200); @@ -481,6 +493,9 @@ export default function ({ getService }: FtrProviderContext) { encodeURI(projectName) ) ) + .query({ + per_page: 500, + }) .set('kbn-xsrf', 'true') .send() .expect(200);