From 698ff714dee51ba45a8bb4fd5315aea2f6f2ceeb Mon Sep 17 00:00:00 2001 From: Shahzad Date: Thu, 27 Jul 2023 13:00:09 +0200 Subject: [PATCH] [Synthetics] Clarify location geo property type (#162371) --- .../group2/check_registered_types.test.ts | 2 +- .../synthetics_private_locations.ts | 6 +- .../private_locations/helpers.test.ts | 6 +- .../settings/private_locations/helpers.ts | 10 +- .../server/runtime_types/private_locations.ts | 4 +- .../private_locations/model_version_1.test.ts | 180 ++++++++++++++++++ .../private_locations/model_version_1.ts} | 40 ++-- .../server/saved_objects/private_locations.ts | 4 + 8 files changed, 221 insertions(+), 31 deletions(-) create mode 100644 x-pack/plugins/synthetics/server/saved_objects/migrations/private_locations/model_version_1.test.ts rename x-pack/plugins/synthetics/server/{legacy_uptime/lib/saved_objects/migrations/private_locations/8.10.0.ts => saved_objects/migrations/private_locations/model_version_1.ts} (61%) diff --git a/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts index 2a60484107362..063ed46c443f6 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts @@ -142,7 +142,7 @@ describe('checking migration metadata changes on all registered SO types', () => "spaces-usage-stats": "3abca98713c52af8b30300e386c7779b3025a20e", "synthetics-monitor": "33ddc4b8979f378edf58bcc7ba13c5c5b572f42d", "synthetics-param": "3ebb744e5571de678b1312d5c418c8188002cf5e", - "synthetics-privates-locations": "9cfbd6d1d2e2c559bf96dd6fbc27ff0c47719dd3", + "synthetics-privates-locations": "f53d799d5c9bc8454aaa32c6abc99a899b025d5c", "tag": "e2544392fe6563e215bb677abc8b01c2601ef2dc", "task": "04f30bd7bae923f3a53c31ab3b9745a93872fc02", "telemetry": "7b00bcf1c7b4f6db1192bb7405a6a63e78b699fd", diff --git a/x-pack/plugins/synthetics/common/runtime_types/monitor_management/synthetics_private_locations.ts b/x-pack/plugins/synthetics/common/runtime_types/monitor_management/synthetics_private_locations.ts index caa3ac686fd61..c0366d8e3935f 100644 --- a/x-pack/plugins/synthetics/common/runtime_types/monitor_management/synthetics_private_locations.ts +++ b/x-pack/plugins/synthetics/common/runtime_types/monitor_management/synthetics_private_locations.ts @@ -18,11 +18,9 @@ export const PrivateLocationCodec = t.intersection([ isServiceManaged: t.boolean, isInvalid: t.boolean, tags: t.array(t.string), - /* Empty Lat lon was accidentally saved as an empty string instead of undefined or null - * Need a migration to fix */ geo: t.interface({ - lat: t.union([t.string, t.number, t.null]), - lon: t.union([t.string, t.number, t.null]), + lat: t.number, + lon: t.number, }), }), ]); diff --git a/x-pack/plugins/synthetics/server/routes/settings/private_locations/helpers.test.ts b/x-pack/plugins/synthetics/server/routes/settings/private_locations/helpers.test.ts index 584cc2a334697..fe08ed89cadac 100644 --- a/x-pack/plugins/synthetics/server/routes/settings/private_locations/helpers.test.ts +++ b/x-pack/plugins/synthetics/server/routes/settings/private_locations/helpers.test.ts @@ -48,7 +48,7 @@ const testLocations2 = { label: 'BEEP', agentPolicyId: 'e3134290-0f73-11ee-ba15-159f4f728dec', id: 'e3134290-0f73-11ee-ba15-159f4f728dec', - geo: { lat: '-10', lon: '20' }, + geo: { lat: -10, lon: 20 }, concurrentMonitors: 1, isInvalid: true, isServiceManaged: true, @@ -113,8 +113,8 @@ describe('toClientContract', () => { agentPolicyId: 'e3134290-0f73-11ee-ba15-159f4f728dec', concurrentMonitors: 1, geo: { - lat: '-10', - lon: '20', + lat: -10, + lon: 20, }, id: 'e3134290-0f73-11ee-ba15-159f4f728dec', isInvalid: true, diff --git a/x-pack/plugins/synthetics/server/routes/settings/private_locations/helpers.ts b/x-pack/plugins/synthetics/server/routes/settings/private_locations/helpers.ts index 42fd6e42c4277..7f64b1bed7425 100644 --- a/x-pack/plugins/synthetics/server/routes/settings/private_locations/helpers.ts +++ b/x-pack/plugins/synthetics/server/routes/settings/private_locations/helpers.ts @@ -25,10 +25,7 @@ export const toClientContract = ( isServiceManaged: false, isInvalid: !Boolean(agentPolicies?.find((policy) => policy.id === location.agentPolicyId)), tags: location.tags, - geo: { - lat: location.geo?.lat ?? null, - lon: location.geo?.lon ?? null, - }, + geo: location.geo, })), }; }; @@ -41,9 +38,6 @@ export const toSavedObjectContract = (location: PrivateLocation): PrivateLocatio concurrentMonitors: location.concurrentMonitors, tags: location.tags, isServiceManaged: false, - geo: { - lat: location.geo?.lat ?? null, - lon: location.geo?.lon ?? null, - }, + geo: location.geo, }; }; diff --git a/x-pack/plugins/synthetics/server/runtime_types/private_locations.ts b/x-pack/plugins/synthetics/server/runtime_types/private_locations.ts index 5b87332c19279..d8b4e41ede17a 100644 --- a/x-pack/plugins/synthetics/server/runtime_types/private_locations.ts +++ b/x-pack/plugins/synthetics/server/runtime_types/private_locations.ts @@ -18,8 +18,8 @@ export const PrivateLocationAttributesCodec = t.intersection([ t.partial({ tags: t.array(t.string), geo: t.interface({ - lat: t.union([t.null, t.number, t.string]), - lon: t.union([t.null, t.number, t.string]), + lat: t.number, + lon: t.number, }), }), ]); diff --git a/x-pack/plugins/synthetics/server/saved_objects/migrations/private_locations/model_version_1.test.ts b/x-pack/plugins/synthetics/server/saved_objects/migrations/private_locations/model_version_1.test.ts new file mode 100644 index 0000000000000..63a9f940143a4 --- /dev/null +++ b/x-pack/plugins/synthetics/server/saved_objects/migrations/private_locations/model_version_1.test.ts @@ -0,0 +1,180 @@ +/* + * 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 { transformGeoProperty } from './model_version_1'; +import { privateLocationsSavedObjectName } from '../../../../common/saved_objects/private_locations'; + +describe('model version 1 migration', () => { + const testLocation = { + label: 'us-east-1', + id: 'us-east-1', + geo: { + lat: '40.7128', + lon: '-74.0060', + }, + agentPolicyId: 'agentPolicyId', + concurrentMonitors: 1, + }; + const testObject = { + type: privateLocationsSavedObjectName, + id: 'synthetics-privates-locations-singleton', + attributes: { + locations: [testLocation], + }, + }; + it('should return expected result', function () { + const result = transformGeoProperty(testObject, {} as any); + expect(result.document).toEqual({ + attributes: { + locations: [ + { + agentPolicyId: 'agentPolicyId', + concurrentMonitors: 1, + geo: { + lat: 40.7128, + lon: -74.006, + }, + id: 'us-east-1', + isServiceManaged: false, + label: 'us-east-1', + }, + ], + }, + id: 'synthetics-privates-locations-singleton', + type: 'synthetics-privates-locations', + }); + }); + + it('should return expected result for zero values', function () { + testLocation.geo.lat = '0'; + testLocation.geo.lon = '0'; + const result = transformGeoProperty(testObject, {} as any); + expect(result.document).toEqual({ + attributes: { + locations: [ + { + agentPolicyId: 'agentPolicyId', + concurrentMonitors: 1, + geo: { + lat: 0, + lon: 0, + }, + id: 'us-east-1', + isServiceManaged: false, + label: 'us-east-1', + }, + ], + }, + id: 'synthetics-privates-locations-singleton', + type: 'synthetics-privates-locations', + }); + }); + + it('should return expected result for zero integers', function () { + // @ts-ignore + testLocation.geo.lat = 0; + // @ts-ignore + testLocation.geo.lon = 0; + const result = transformGeoProperty(testObject, {} as any); + expect(result.document).toEqual({ + attributes: { + locations: [ + { + agentPolicyId: 'agentPolicyId', + concurrentMonitors: 1, + geo: { + lat: 0, + lon: 0, + }, + id: 'us-east-1', + isServiceManaged: false, + label: 'us-east-1', + }, + ], + }, + id: 'synthetics-privates-locations-singleton', + type: 'synthetics-privates-locations', + }); + }); + + it('should return expected result for empty values', function () { + // @ts-ignore + testLocation.geo.lat = ''; + // @ts-ignore + testLocation.geo.lon = ''; + const result = transformGeoProperty(testObject, {} as any); + expect(result.document).toEqual({ + attributes: { + locations: [ + { + agentPolicyId: 'agentPolicyId', + concurrentMonitors: 1, + geo: { + lat: 0, + lon: 0, + }, + id: 'us-east-1', + isServiceManaged: false, + label: 'us-east-1', + }, + ], + }, + id: 'synthetics-privates-locations-singleton', + type: 'synthetics-privates-locations', + }); + }); + it('should return expected result for null values', function () { + // @ts-ignore + testLocation.geo.lat = null; + // @ts-ignore + testLocation.geo.lon = null; + const result = transformGeoProperty(testObject, {} as any); + expect(result.document).toEqual({ + attributes: { + locations: [ + { + agentPolicyId: 'agentPolicyId', + concurrentMonitors: 1, + geo: { + lat: 0, + lon: 0, + }, + id: 'us-east-1', + isServiceManaged: false, + label: 'us-east-1', + }, + ], + }, + id: 'synthetics-privates-locations-singleton', + type: 'synthetics-privates-locations', + }); + }); + + it('should return expected result for undefined values', function () { + // @ts-ignore + testLocation.geo = undefined; + const result = transformGeoProperty(testObject, {} as any); + expect(result.document).toEqual({ + attributes: { + locations: [ + { + agentPolicyId: 'agentPolicyId', + concurrentMonitors: 1, + geo: { + lat: 0, + lon: 0, + }, + id: 'us-east-1', + isServiceManaged: false, + label: 'us-east-1', + }, + ], + }, + id: 'synthetics-privates-locations-singleton', + type: 'synthetics-privates-locations', + }); + }); +}); diff --git a/x-pack/plugins/synthetics/server/legacy_uptime/lib/saved_objects/migrations/private_locations/8.10.0.ts b/x-pack/plugins/synthetics/server/saved_objects/migrations/private_locations/model_version_1.ts similarity index 61% rename from x-pack/plugins/synthetics/server/legacy_uptime/lib/saved_objects/migrations/private_locations/8.10.0.ts rename to x-pack/plugins/synthetics/server/saved_objects/migrations/private_locations/model_version_1.ts index 6108abdc638a1..2b7d5be016bf0 100644 --- a/x-pack/plugins/synthetics/server/legacy_uptime/lib/saved_objects/migrations/private_locations/8.10.0.ts +++ b/x-pack/plugins/synthetics/server/saved_objects/migrations/private_locations/model_version_1.ts @@ -5,8 +5,11 @@ * 2.0. */ import * as t from 'io-ts'; -import type { SavedObjectMigrationFn } from '@kbn/core/server'; -import type { SyntheticsPrivateLocationsAttributes } from '../../../../../runtime_types/private_locations'; +import { + SavedObjectModelTransformationFn, + SavedObjectsModelVersion, +} from '@kbn/core-saved-objects-server'; +import { SyntheticsPrivateLocationsAttributes } from '../../../runtime_types/private_locations'; export const PrivateLocationAttributesCodecLegacy = t.intersection([ t.interface({ @@ -29,22 +32,33 @@ export type SyntheticsPrivateLocationsAttributesLegacy = t.TypeOf< typeof SyntheticsPrivateLocationsAttributesCodecLegacy >; -export const migration8100: SavedObjectMigrationFn< +export const transformGeoProperty: SavedObjectModelTransformationFn< SyntheticsPrivateLocationsAttributesLegacy, SyntheticsPrivateLocationsAttributes > = (privateLocationDoc) => { const { locations } = privateLocationDoc.attributes; return { - ...privateLocationDoc, - attributes: { - locations: locations.map((location) => ({ - ...location, - geo: { - lat: location.geo?.lat ? Number(location.geo?.lat) : null, - lon: location.geo?.lon ? Number(location.geo.lon) : null, - }, - isServiceManaged: false, - })), + document: { + ...privateLocationDoc, + attributes: { + locations: locations.map((location) => ({ + ...location, + geo: { + lat: Number(location.geo?.lat ?? 0), + lon: Number(location.geo?.lon ?? 0), + }, + isServiceManaged: false, + })), + }, }, }; }; + +export const modelVersion1: SavedObjectsModelVersion = { + changes: [ + { + type: 'unsafe_transform', + transformFn: transformGeoProperty, + }, + ], +}; diff --git a/x-pack/plugins/synthetics/server/saved_objects/private_locations.ts b/x-pack/plugins/synthetics/server/saved_objects/private_locations.ts index 0585b3a786ef7..ee7426ead23af 100644 --- a/x-pack/plugins/synthetics/server/saved_objects/private_locations.ts +++ b/x-pack/plugins/synthetics/server/saved_objects/private_locations.ts @@ -6,6 +6,7 @@ */ import { SavedObjectsType } from '@kbn/core/server'; +import { modelVersion1 } from './migrations/private_locations/model_version_1'; import { privateLocationsSavedObjectName } from '../../common/saved_objects/private_locations'; export const privateLocationsSavedObjectId = 'synthetics-privates-locations-singleton'; @@ -25,4 +26,7 @@ export const PRIVATE_LOCATIONS_SAVED_OBJECT_TYPE: SavedObjectsType = { management: { importableAndExportable: true, }, + modelVersions: { + 1: modelVersion1, + }, };