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 = () => {
/>
- {Object.values(syncErrors).map((e) => {
+ {Object.values(syncErrors ?? {}).map((e) => {
return (
- - {`${
- locations.find((location) => location.id === e.locationId)?.label
- } - ${STATUS_LABEL}: ${e.error.status}; ${REASON_LABEL}: ${e.error.reason}.`}
+ -
+ {`${
+ locations.find((location) => location.id === e.locationId)?.label
+ } - ${STATUS_LABEL}: ${e.error?.status ?? NOT_AVAILABLE_LABEL}; ${REASON_LABEL}: ${
+ e.error?.reason ?? NOT_AVAILABLE_LABEL
+ }`}
+
);
})}
@@ -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(