diff --git a/x-pack/plugins/uptime/common/runtime_types/monitor_management/monitor_types.ts b/x-pack/plugins/uptime/common/runtime_types/monitor_management/monitor_types.ts index 872ccdbb71ec8..1e8b89ce065fa 100644 --- a/x-pack/plugins/uptime/common/runtime_types/monitor_management/monitor_types.ts +++ b/x-pack/plugins/uptime/common/runtime_types/monitor_management/monitor_types.ts @@ -306,23 +306,19 @@ export type EncryptedSyntheticsMonitorWithId = t.TypeOf< typeof EncryptedSyntheticsMonitorWithIdCodec >; -export const MonitorManagementListResultCodec = t.intersection([ - t.type({ - monitors: t.array( - t.interface({ - id: t.string, - attributes: EncryptedSyntheticsMonitorCodec, - updated_at: t.string, - }) - ), - page: t.number, - perPage: t.number, - total: t.union([t.number, t.null]), - }), - t.partial({ - syncErrors: ServiceLocationErrors, - }), -]); +export const MonitorManagementListResultCodec = t.type({ + monitors: t.array( + t.interface({ + id: t.string, + attributes: EncryptedSyntheticsMonitorCodec, + updated_at: t.string, + }) + ), + page: t.number, + perPage: t.number, + total: t.union([t.number, t.null]), + syncErrors: t.union([ServiceLocationErrors, t.null]), +}); export type MonitorManagementListResult = t.TypeOf; diff --git a/x-pack/plugins/uptime/public/components/monitor_management/hooks/use_inline_errors.test.tsx b/x-pack/plugins/uptime/public/components/monitor_management/hooks/use_inline_errors.test.tsx index c0c1145e5cc2f..649b009687e33 100644 --- a/x-pack/plugins/uptime/public/components/monitor_management/hooks/use_inline_errors.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor_management/hooks/use_inline_errors.test.tsx @@ -70,7 +70,7 @@ describe('useInlineErrors', function () { { error: { monitorList: null, serviceLocations: null, enablement: null }, enablement: null, - list: { monitors: [], page: 1, perPage: 10, total: null }, + list: { monitors: [], page: 1, perPage: 10, total: null, syncErrors: null }, loading: { monitorList: false, serviceLocations: false, enablement: false }, locations: [], syntheticsService: { diff --git a/x-pack/plugins/uptime/public/components/monitor_management/hooks/use_inline_errors_count.test.tsx b/x-pack/plugins/uptime/public/components/monitor_management/hooks/use_inline_errors_count.test.tsx index c56ca40c59aad..e973e3dd1a7f1 100644 --- a/x-pack/plugins/uptime/public/components/monitor_management/hooks/use_inline_errors_count.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor_management/hooks/use_inline_errors_count.test.tsx @@ -68,7 +68,7 @@ describe('useInlineErrorsCount', function () { 'heartbeat-8*,heartbeat-7*,synthetics-*', { error: { monitorList: null, serviceLocations: null, enablement: null }, - list: { monitors: [], page: 1, perPage: 10, total: null }, + list: { monitors: [], page: 1, perPage: 10, total: null, syncErrors: null }, enablement: null, loading: { monitorList: false, serviceLocations: false, enablement: false }, locations: [], diff --git a/x-pack/plugins/uptime/public/components/monitor_management/hooks/use_locations.test.tsx b/x-pack/plugins/uptime/public/components/monitor_management/hooks/use_locations.test.tsx index fdb1c57712020..46b8981b74a0f 100644 --- a/x-pack/plugins/uptime/public/components/monitor_management/hooks/use_locations.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor_management/hooks/use_locations.test.tsx @@ -40,6 +40,7 @@ describe('useExpViewTimeRange', function () { page: 1, total: 0, monitors: [], + syncErrors: null, }, locations: [], enablement: null, diff --git a/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/invalid_monitors.tsx b/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/invalid_monitors.tsx index 87a6cf2dc1d2b..342b9c6547b1b 100644 --- a/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/invalid_monitors.tsx +++ b/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/invalid_monitors.tsx @@ -48,6 +48,7 @@ export const InvalidMonitors = ({ page: pageState.pageIndex, perPage: pageState.pageSize, total: invalidTotal ?? 0, + syncErrors: null, }, enablement: null, error: { monitorList: null, serviceLocations: null, enablement: null }, diff --git a/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/monitor_async_error.tsx b/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/monitor_async_error.tsx index c9e9dba2027a4..48aeaf3648a0b 100644 --- a/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/monitor_async_error.tsx +++ b/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/monitor_async_error.tsx @@ -36,11 +36,15 @@ export const MonitorAsyncError = () => { />

@@ -67,6 +71,13 @@ const STATUS_LABEL = i18n.translate( } ); +const NOT_AVAILABLE_LABEL = i18n.translate( + 'xpack.uptime.monitorManagement.monitorSync.failure.notAvailable', + { + defaultMessage: 'Not available', + } +); + const DISMISS_LABEL = i18n.translate( 'xpack.uptime.monitorManagement.monitorSync.failure.dismissLabel', { diff --git a/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/monitor_list.test.tsx b/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/monitor_list.test.tsx index 8d0bd67616576..40eb185a65f0c 100644 --- a/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/monitor_list.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor_management/monitor_list/monitor_list.test.tsx @@ -48,6 +48,7 @@ describe('', () => { page: 1, total: 6, monitors, + syncErrors: null, }, locations: [], enablement: null, diff --git a/x-pack/plugins/uptime/public/lib/__mocks__/uptime_store.mock.ts b/x-pack/plugins/uptime/public/lib/__mocks__/uptime_store.mock.ts index 1bb86877f9861..0286e884a68d7 100644 --- a/x-pack/plugins/uptime/public/lib/__mocks__/uptime_store.mock.ts +++ b/x-pack/plugins/uptime/public/lib/__mocks__/uptime_store.mock.ts @@ -69,6 +69,7 @@ export const mockState: AppState = { perPage: 10, total: null, monitors: [], + syncErrors: null, }, locations: [], loading: { diff --git a/x-pack/plugins/uptime/server/lib/synthetics_service/service_api_client.ts b/x-pack/plugins/uptime/server/lib/synthetics_service/service_api_client.ts index 68d4ebd385f07..3397dcad94e95 100644 --- a/x-pack/plugins/uptime/server/lib/synthetics_service/service_api_client.ts +++ b/x-pack/plugins/uptime/server/lib/synthetics_service/service_api_client.ts @@ -74,7 +74,7 @@ export class ServiceAPIClient { } async put(data: ServiceData) { - return this.callAPI('POST', data); + return this.callAPI('PUT', data); } async delete(data: ServiceData) { @@ -170,6 +170,9 @@ export class ServiceAPIClient { catchError((err) => { pushErrors.push({ locationId: id, error: err.response?.data }); this.logger.error(err); + if (err.response?.data?.reason) { + this.logger.error(err.response?.data?.reason); + } // we don't want to throw an unhandled exception here return of(true); }) diff --git a/x-pack/plugins/uptime/server/lib/synthetics_service/synthetics_service.ts b/x-pack/plugins/uptime/server/lib/synthetics_service/synthetics_service.ts index 24630cd0ec738..c6fa280f2f163 100644 --- a/x-pack/plugins/uptime/server/lib/synthetics_service/synthetics_service.ts +++ b/x-pack/plugins/uptime/server/lib/synthetics_service/synthetics_service.ts @@ -45,6 +45,11 @@ const SYNTHETICS_SERVICE_SYNC_MONITORS_TASK_TYPE = const SYNTHETICS_SERVICE_SYNC_MONITORS_TASK_ID = 'UPTIME:SyntheticsService:sync-task'; const SYNTHETICS_SERVICE_SYNC_INTERVAL_DEFAULT = '5m'; +type SyntheticsConfig = SyntheticsMonitorWithId & { + fields_under_root?: boolean; + fields?: { config_id: string; run_once?: boolean; test_run_id?: string }; +}; + export class SyntheticsService { private logger: Logger; private readonly server: UptimeServerSetup; @@ -218,14 +223,32 @@ export class SyntheticsService { }; } - async pushConfigs( - configs?: Array< - SyntheticsMonitorWithId & { - fields_under_root?: boolean; - fields?: { config_id: string }; - } - > - ) { + async addConfig(config: SyntheticsConfig) { + const monitors = this.formatConfigs([config]); + + this.apiKey = await this.getApiKey(); + + if (!this.apiKey) { + return null; + } + + const data = { + monitors, + output: await this.getOutput(this.apiKey), + }; + + this.logger.debug(`1 monitor will be pushed to synthetics service.`); + + try { + this.syncErrors = await this.apiClient.post(data); + return this.syncErrors; + } catch (e) { + this.logger.error(e); + throw e; + } + } + + async pushConfigs(configs?: SyntheticsConfig[]) { const monitors = this.formatConfigs(configs || (await this.getMonitorConfigs())); if (monitors.length === 0) { this.logger.debug('No monitor found which can be pushed to service.'); @@ -246,21 +269,15 @@ export class SyntheticsService { this.logger.debug(`${monitors.length} monitors will be pushed to synthetics service.`); try { - return await this.apiClient.post(data); + this.syncErrors = await this.apiClient.put(data); + return this.syncErrors; } catch (e) { this.logger.error(e); throw e; } } - async runOnceConfigs( - configs?: Array< - SyntheticsMonitorWithId & { - fields_under_root?: boolean; - fields?: { run_once: boolean; config_id: string }; - } - > - ) { + async runOnceConfigs(configs?: SyntheticsConfig[]) { const monitors = this.formatConfigs(configs || (await this.getMonitorConfigs())); if (monitors.length === 0) { return; @@ -284,15 +301,7 @@ export class SyntheticsService { } } - async triggerConfigs( - request?: KibanaRequest, - configs?: Array< - SyntheticsMonitorWithId & { - fields_under_root?: boolean; - fields?: { config_id: string; test_run_id: string }; - } - > - ) { + async triggerConfigs(request?: KibanaRequest, configs?: SyntheticsConfig[]) { const monitors = this.formatConfigs(configs || (await this.getMonitorConfigs())); if (monitors.length === 0) { return; @@ -328,7 +337,11 @@ export class SyntheticsService { monitors: this.formatConfigs(configs), output: await this.getOutput(this.apiKey), }; - return await this.apiClient.delete(data); + const result = await this.apiClient.delete(data); + if (this.syncErrors && this.syncErrors?.length > 0) { + this.syncErrors = await this.pushConfigs(); + } + return result; } async deleteAllConfigs() { diff --git a/x-pack/plugins/uptime/server/rest_api/synthetics_service/add_monitor.ts b/x-pack/plugins/uptime/server/rest_api/synthetics_service/add_monitor.ts index 19bc5050ddfcc..521dae85e85db 100644 --- a/x-pack/plugins/uptime/server/rest_api/synthetics_service/add_monitor.ts +++ b/x-pack/plugins/uptime/server/rest_api/synthetics_service/add_monitor.ts @@ -45,16 +45,14 @@ export const addSyntheticsMonitorRoute: UMRestApiRouteFactory = () => ({ const { syntheticsService } = server; - const errors = await syntheticsService.pushConfigs([ - { - ...monitor, - id: newMonitor.id, - fields: { - config_id: newMonitor.id, - }, - fields_under_root: true, + const errors = await syntheticsService.addConfig({ + ...monitor, + id: newMonitor.id, + fields: { + config_id: newMonitor.id, }, - ]); + fields_under_root: true, + }); sendTelemetryEvents( server.logger, diff --git a/x-pack/test/api_integration/apis/uptime/rest/monitor_states_real_data.ts b/x-pack/test/api_integration/apis/uptime/rest/monitor_states_real_data.ts index 909a485057f85..68d17cf3a4dd2 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/monitor_states_real_data.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/monitor_states_real_data.ts @@ -8,7 +8,10 @@ import expect from '@kbn/expect'; import { isRight } from 'fp-ts/lib/Either'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { MonitorSummariesResultType } from '../../../../../plugins/uptime/common/runtime_types'; +import { + MonitorSummariesResult, + MonitorSummariesResultType, +} from '../../../../../plugins/uptime/common/runtime_types'; import { API_URLS } from '../../../../../plugins/uptime/common/constants'; interface ExpectedMonitorStatesPage { @@ -40,7 +43,8 @@ const checkMonitorStatesResponse = ({ const decoded = MonitorSummariesResultType.decode(response); expect(isRight(decoded)).to.be.ok(); if (isRight(decoded)) { - const { summaries, prevPagePagination, nextPagePagination } = decoded.right; + const { summaries, prevPagePagination, nextPagePagination } = + decoded.right as MonitorSummariesResult; expect(summaries).to.have.length(size); expect(summaries?.map((s) => s.monitor_id)).to.eql(statesIds); expect(