From 351f83ba0120fa4960d4557683c79fe6daa8ed0d Mon Sep 17 00:00:00 2001 From: Bryce Buchanan <75274611+bryce-b@users.noreply.github.com> Date: Mon, 27 Jan 2025 10:09:32 -0800 Subject: [PATCH] Added versioning to inventory_view_saved_object (#207007) ## Summary Fixes #187254 Strict checks on the attribute `legend.steps` was added to the inventory view API in v8.10 (#160852), but they were not defined in the saved object type for that data, resulting in older versions migrating bad data, and being unable to use the API. This PR adds versioning to the Inventory view saved object type that constrains legend.steps to between 2 and 18, per the strict typing added in #160852 #### Open questions Should we add notes to all versions of kibana between v8.10 and oldest version available for backport describing this bug? ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> (cherry picked from commit a108c632a459240f9c27262395e2584f92d43779) # Conflicts: # x-pack/solutions/observability/plugins/infra/tsconfig.json --- .../check_registered_types.test.ts | 2 +- .../inventory_view_saved_object.test.ts | 61 +++++++++++++++++++ .../inventory_view_saved_object.ts | 33 ++++++++++ .../observability/plugins/infra/tsconfig.json | 3 +- 4 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 x-pack/solutions/observability/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.test.ts diff --git a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts index 846197ba37c1e..4f8031ffa3f5a 100644 --- a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts +++ b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts @@ -126,7 +126,7 @@ describe('checking migration metadata changes on all registered SO types', () => "ingest-outputs": "daafff49255ab700e07491376fe89f04fc998b91", "ingest-package-policies": "870f8c21fe3602f31075430a1fdfb052c62d4a14", "ingest_manager_settings": "111a616eb72627c002029c19feb9e6c439a10505", - "inventory-view": "b8683c8e352a286b4aca1ab21003115a4800af83", + "inventory-view": "fd2b7fe713956f261018dded00d8f8c986417763", "kql-telemetry": "93c1d16c1a0dfca9c8842062cf5ef8f62ae401ad", "legacy-url-alias": "9b8cca3fbb2da46fd12823d3cd38fdf1c9f24bc8", "lens": "5cfa2c52b979b4f8df56dd13c477e152183468b9", diff --git a/x-pack/solutions/observability/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.test.ts b/x-pack/solutions/observability/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.test.ts new file mode 100644 index 0000000000000..af29eb91b5f8e --- /dev/null +++ b/x-pack/solutions/observability/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.test.ts @@ -0,0 +1,61 @@ +/* + * 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 { + createModelVersionTestMigrator, + type ModelVersionTestMigrator, +} from '@kbn/core-test-helpers-model-versions'; + +import { inventoryViewSavedObjectType } from './inventory_view_saved_object'; + +describe('invetoryViewSavedObject model version transformation', () => { + let migrator: ModelVersionTestMigrator; + beforeEach(() => { + migrator = createModelVersionTestMigrator({ type: inventoryViewSavedObjectType }); + }); + + describe('model veresion 2', () => { + const inventoryViewV2 = { + id: 'someId', + type: 'inventory-view', + attributes: { + metric: { type: 'cpu' }, + sort: { by: 'name', direction: 'desc' }, + groupBy: [], + nodeType: 'host', + view: 'map', + customOptions: [], + customMetrics: [], + boundsOverride: { min: 0, max: 1 }, + autoBounds: true, + accountId: '', + region: '', + autoReload: false, + filterQuery: { expression: '', kind: 'kuery' }, + legend: { palette: 'cool', reverseColors: false, steps: 18 }, + timelineOpen: false, + name: 'test', + }, + references: [], + }; + + it('should clamp legend.steps to 18 when converting from v1 to v2', () => { + const inventoryViewV1 = JSON.parse(JSON.stringify(inventoryViewV2)); + inventoryViewV1.attributes.legend.steps = 20; + const migrated = migrator.migrate({ + document: { + ...inventoryViewV1, + attributes: { + ...inventoryViewV1.attributes, + }, + }, + fromVersion: 1, + toVersion: 2, + }); + expect(migrated.attributes).toEqual(inventoryViewV2.attributes); + }); + }); +}); diff --git a/x-pack/solutions/observability/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.ts b/x-pack/solutions/observability/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.ts index f9c4c4d354024..5cbe9a876e222 100644 --- a/x-pack/solutions/observability/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.ts +++ b/x-pack/solutions/observability/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { schema } from '@kbn/config-schema'; import { fold } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; import type { SavedObject, SavedObjectsType } from '@kbn/core/server'; @@ -21,6 +22,11 @@ const getInventoryViewTitle = (savedObject: SavedObject) => ) ); +const schemaV1 = schema.object({}, { unknowns: 'allow' }); +const schemaV2 = schema.object({ + legend: schema.object({ steps: schema.number({ max: 18, min: 2 }) }), +}); + export const inventoryViewSavedObjectType: SavedObjectsType = { name: inventoryViewSavedObjectName, hidden: false, @@ -36,4 +42,31 @@ export const inventoryViewSavedObjectType: SavedObjectsType = { dynamic: false, properties: {}, }, + modelVersions: { + 1: { + changes: [], + schemas: { + create: schemaV1, + }, + }, + 2: { + changes: [ + { + type: 'unsafe_transform', + transformFn: (document) => { + if (document.attributes.legend.steps > 18) { + document.attributes.legend.steps = 18; + } else if (document.attributes.legend.steps < 2) { + document.attributes.legend.steps = 2; + } + return { document }; + }, + }, + ], + schemas: { + forwardCompatibility: schemaV2.extends({}, { unknowns: 'ignore' }), + create: schemaV2, + }, + }, + }, }; diff --git a/x-pack/solutions/observability/plugins/infra/tsconfig.json b/x-pack/solutions/observability/plugins/infra/tsconfig.json index 618f7a5612ac9..07d4c98d9786f 100644 --- a/x-pack/solutions/observability/plugins/infra/tsconfig.json +++ b/x-pack/solutions/observability/plugins/infra/tsconfig.json @@ -120,7 +120,8 @@ "@kbn/core-plugins-server", "@kbn/config", "@kbn/response-ops-rule-params", - "@kbn/charts-theme" + "@kbn/charts-theme", + "@kbn/core-test-helpers-model-versions" ], "exclude": ["target/**/*"] }