From 3ec7402302aab506248ac8ba465c620c5d8106e3 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Tue, 11 Apr 2023 11:19:39 +0200 Subject: [PATCH 01/20] feat(infra): wip on inventory views --- .../inventory_views/delete_inventory_view.ts | 0 .../inventory_views/find_inventory_view.ts | 0 .../inventory_views/get_inventory_view.ts | 0 .../server/routes/inventory_views/index.ts | 23 + .../inventory_views/put_inventory_view.ts | 0 .../server/services/inventory_views/errors.ts | 13 + .../server/services/inventory_views/index.ts | 14 + .../inventory_views_client.mock.ts | 19 + .../inventory_views_client.test.ts | 430 ++++++++++++++++++ .../inventory_views/inventory_views_client.ts | 239 ++++++++++ .../inventory_views_service.mock.ts | 20 + .../inventory_views_service.ts | 65 +++ .../server/services/inventory_views/types.ts | 52 +++ 13 files changed, 875 insertions(+) create mode 100644 x-pack/plugins/infra/server/routes/inventory_views/delete_inventory_view.ts create mode 100644 x-pack/plugins/infra/server/routes/inventory_views/find_inventory_view.ts create mode 100644 x-pack/plugins/infra/server/routes/inventory_views/get_inventory_view.ts create mode 100644 x-pack/plugins/infra/server/routes/inventory_views/index.ts create mode 100644 x-pack/plugins/infra/server/routes/inventory_views/put_inventory_view.ts create mode 100644 x-pack/plugins/infra/server/services/inventory_views/errors.ts create mode 100644 x-pack/plugins/infra/server/services/inventory_views/index.ts create mode 100644 x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts create mode 100644 x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts create mode 100644 x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts create mode 100644 x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts create mode 100644 x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts create mode 100644 x-pack/plugins/infra/server/services/inventory_views/types.ts diff --git a/x-pack/plugins/infra/server/routes/inventory_views/delete_inventory_view.ts b/x-pack/plugins/infra/server/routes/inventory_views/delete_inventory_view.ts new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/x-pack/plugins/infra/server/routes/inventory_views/find_inventory_view.ts b/x-pack/plugins/infra/server/routes/inventory_views/find_inventory_view.ts new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/x-pack/plugins/infra/server/routes/inventory_views/get_inventory_view.ts b/x-pack/plugins/infra/server/routes/inventory_views/get_inventory_view.ts new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/x-pack/plugins/infra/server/routes/inventory_views/index.ts b/x-pack/plugins/infra/server/routes/inventory_views/index.ts new file mode 100644 index 0000000000000..8c55857c05b5c --- /dev/null +++ b/x-pack/plugins/infra/server/routes/inventory_views/index.ts @@ -0,0 +1,23 @@ +/* + * 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 { KibanaFramework } from '../../lib/adapters/framework/kibana_framework_adapter'; +import { InfraPluginStartServicesAccessor } from '../../types'; +import { initDeleteInventoryViewRoute } from './delete_inventory_view'; +import { initFindInventoryViewRoute } from './find_inventory_view'; +import { initGetInventoryViewRoute } from './get_inventory_view'; +import { initPutInventoryViewRoute } from './put_inventory_view'; + +export const initInventoryViewRoutes = (dependencies: { + framework: KibanaFramework; + getStartServices: InfraPluginStartServicesAccessor; +}) => { + initDeleteInventoryViewRoute(dependencies); + initFindInventoryViewRoute(dependencies); + initGetInventoryViewRoute(dependencies); + initPutInventoryViewRoute(dependencies); +}; diff --git a/x-pack/plugins/infra/server/routes/inventory_views/put_inventory_view.ts b/x-pack/plugins/infra/server/routes/inventory_views/put_inventory_view.ts new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/x-pack/plugins/infra/server/services/inventory_views/errors.ts b/x-pack/plugins/infra/server/services/inventory_views/errors.ts new file mode 100644 index 0000000000000..fb0dc3b031511 --- /dev/null +++ b/x-pack/plugins/infra/server/services/inventory_views/errors.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export class NotFoundError extends Error { + constructor(message?: string) { + super(message); + Object.setPrototypeOf(this, new.target.prototype); + } +} diff --git a/x-pack/plugins/infra/server/services/inventory_views/index.ts b/x-pack/plugins/infra/server/services/inventory_views/index.ts new file mode 100644 index 0000000000000..2deff89789686 --- /dev/null +++ b/x-pack/plugins/infra/server/services/inventory_views/index.ts @@ -0,0 +1,14 @@ +/* + * 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. + */ + +export { InventoryViewsService } from './log_views_service'; +export { InventoryViewsClient } from './inventory_views_client'; +export type { + InventoryViewsServiceSetup, + InventoryViewsServiceStart, + InventoryViewsServiceStartDeps, +} from './types'; diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts new file mode 100644 index 0000000000000..3e7e204c4707d --- /dev/null +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts @@ -0,0 +1,19 @@ +/* + * 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 { InventoryViewReference } from '../../../common/log_views'; +import { createResolvedInventoryViewMock } from '../../../common/log_views/resolved_log_view.mock'; +import { IInventoryViewsClient } from './types'; + +export const createInventoryViewsClientMock = (): jest.Mocked => ({ + getInventoryView: jest.fn(), + getResolvedInventoryView: jest.fn((inventoryViewReference: InventoryViewReference) => + Promise.resolve(createResolvedInventoryViewMock()) + ), + putInventoryView: jest.fn(), + resolveInventoryView: jest.fn(), +}); diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts new file mode 100644 index 0000000000000..501dd99bf0549 --- /dev/null +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts @@ -0,0 +1,430 @@ +/* + * 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 { loggerMock } from '@kbn/logging-mocks'; +import { SavedObject, SavedObjectsUtils } from '@kbn/core/server'; +import { savedObjectsClientMock } from '@kbn/core/server/mocks'; +import { createStubDataView } from '@kbn/data-views-plugin/common/stubs'; +import { dataViewsService as dataViewsServiceMock } from '@kbn/data-views-plugin/server/mocks'; +import { + defaultInventoryViewId, + InventoryView, + InventoryViewAttributes, + InventoryViewsStaticConfig, +} from '../../../common/log_views'; +import { createInventoryViewMock } from '../../../common/log_views/log_view.mock'; +import { InfraSource } from '../../lib/sources'; +import { createInfraSourcesMock } from '../../lib/sources/mocks'; +import { + extractInventoryViewSavedObjectReferences, + inventoryViewSavedObjectName, +} from '../../saved_objects/log_view'; +import { + getAttributesFromSourceConfiguration, + InventoryViewsClient, +} from './inventory_views_client'; + +describe('getAttributesFromSourceConfiguration function', () => { + it('converts the index_pattern log indices type to data_view', () => { + const inventoryViewAttributes = getAttributesFromSourceConfiguration( + basicTestSourceConfiguration + ); + + expect(inventoryViewAttributes.logIndices).toEqual({ + type: 'data_view', + dataViewId: 'INDEX_PATTERN_ID', + }); + }); + + it('preserves the index_name log indices type', () => { + const inventoryViewAttributes = getAttributesFromSourceConfiguration({ + ...basicTestSourceConfiguration, + configuration: { + ...basicTestSourceConfiguration.configuration, + logIndices: { + type: 'index_name', + indexName: 'INDEX_NAME', + }, + }, + }); + + expect(inventoryViewAttributes.logIndices).toEqual({ + type: 'index_name', + indexName: 'INDEX_NAME', + }); + }); +}); + +describe('InventoryViewsClient class', () => { + it('getInventoryView resolves the default id to a real saved object id if it exists', async () => { + const { inventoryViewsClient, savedObjectsClient } = createInventoryViewsClient(); + + const inventoryViewMock = createInventoryViewMock('SAVED_OBJECT_ID'); + const inventoryViewSavedObject: SavedObject = { + ...extractInventoryViewSavedObjectReferences(inventoryViewMock.attributes), + id: inventoryViewMock.id, + type: inventoryViewSavedObjectName, + }; + + savedObjectsClient.get.mockResolvedValue(inventoryViewSavedObject); + + savedObjectsClient.find.mockResolvedValue({ + total: 1, + saved_objects: [ + { + score: 0, + ...inventoryViewSavedObject, + }, + ], + per_page: 1, + page: 1, + }); + + const inventoryView = await inventoryViewsClient.getInventoryView(defaultInventoryViewId); + + expect(savedObjectsClient.get).toHaveBeenCalledWith( + inventoryViewSavedObjectName, + 'SAVED_OBJECT_ID' + ); + expect(inventoryView).toEqual(inventoryViewMock); + }); + + it('getInventoryView preserves non-default ids', async () => { + const { inventoryViewsClient, savedObjectsClient } = createInventoryViewsClient(); + + const inventoryViewMock = createInventoryViewMock('SAVED_OBJECT_ID'); + const inventoryViewSavedObject: SavedObject = { + ...extractInventoryViewSavedObjectReferences(inventoryViewMock.attributes), + id: inventoryViewMock.id, + type: inventoryViewSavedObjectName, + }; + + savedObjectsClient.get.mockResolvedValue(inventoryViewSavedObject); + + savedObjectsClient.find.mockResolvedValue({ + total: 1, + saved_objects: [ + { + score: 0, + ...inventoryViewSavedObject, + }, + ], + per_page: 1, + page: 1, + }); + + const inventoryView = await inventoryViewsClient.getInventoryView('SAVED_OBJECT_ID'); + + expect(savedObjectsClient.get).toHaveBeenCalledWith( + inventoryViewSavedObjectName, + 'SAVED_OBJECT_ID' + ); + expect(inventoryView).toEqual(inventoryViewMock); + }); + + it('getInventoryView preserves the default id for fallback lookups', async () => { + const { infraSources, inventoryViewsClient, savedObjectsClient } = createInventoryViewsClient(); + + infraSources.getSourceConfiguration.mockResolvedValue(basicTestSourceConfiguration); + + savedObjectsClient.find.mockResolvedValue({ + total: 0, + saved_objects: [], + per_page: 0, + page: 1, + }); + + await inventoryViewsClient.getInventoryView(defaultInventoryViewId); + + expect(infraSources.getSourceConfiguration).toHaveBeenCalledWith( + savedObjectsClient, + defaultInventoryViewId + ); + }); + + it('putInventoryView resolves the default id to a real saved object id if one exists', async () => { + const { inventoryViewsClient, savedObjectsClient } = createInventoryViewsClient(); + + const existingInventoryViewMock = createInventoryViewMock('SAVED_OBJECT_ID'); + const existingInventoryViewSavedObject: SavedObject = { + ...extractInventoryViewSavedObjectReferences(existingInventoryViewMock.attributes), + id: existingInventoryViewMock.id, + type: inventoryViewSavedObjectName, + }; + + const newInventoryViewMock = createInventoryViewMock('SAVED_OBJECT_ID', 'stored', { + name: 'New Log View', + }); + const newInventoryViewSavedObject: SavedObject = { + ...extractInventoryViewSavedObjectReferences(newInventoryViewMock.attributes), + id: newInventoryViewMock.id, + type: inventoryViewSavedObjectName, + }; + + savedObjectsClient.create.mockResolvedValue(newInventoryViewSavedObject); + + savedObjectsClient.find.mockResolvedValue({ + total: 1, + saved_objects: [ + { + score: 0, + ...existingInventoryViewSavedObject, + }, + ], + per_page: 1, + page: 1, + }); + + const inventoryView = await inventoryViewsClient.putInventoryView( + defaultInventoryViewId, + newInventoryViewMock.attributes + ); + + expect(savedObjectsClient.create).toHaveBeenCalledWith( + inventoryViewSavedObjectName, + newInventoryViewMock.attributes, + expect.objectContaining({ id: 'SAVED_OBJECT_ID' }) + ); + expect(inventoryView).toEqual(newInventoryViewMock); + }); + + it('putInventoryView resolves the default id to a new uuid if no default exists', async () => { + const { inventoryViewsClient, savedObjectsClient } = createInventoryViewsClient(); + + const newInventoryViewMock = createInventoryViewMock('NOT_THE_FINAL_ID', 'stored', { + name: 'New Log View', + }); + const newInventoryViewSavedObject: SavedObject = { + ...extractInventoryViewSavedObjectReferences(newInventoryViewMock.attributes), + id: newInventoryViewMock.id, + type: inventoryViewSavedObjectName, + }; + + savedObjectsClient.create.mockImplementation(async (_type, _attributes, { id = '' } = {}) => ({ + ...newInventoryViewSavedObject, + id, + })); + + savedObjectsClient.find.mockResolvedValue({ + total: 0, + saved_objects: [], + per_page: 0, + page: 1, + }); + + const inventoryView = await inventoryViewsClient.putInventoryView( + defaultInventoryViewId, + newInventoryViewMock.attributes + ); + + expect(savedObjectsClient.create).toHaveBeenCalledWith( + inventoryViewSavedObjectName, + newInventoryViewMock.attributes, + expect.objectContaining({ + id: expect.any(String), // the id was generated + }) + ); + expect(inventoryView).toEqual( + expect.objectContaining({ + ...newInventoryViewMock, + id: expect.any(String), // the id was generated + }) + ); + expect(SavedObjectsUtils.isRandomId(inventoryView.id)).toBeTruthy(); + }); + + it('resolveInventoryView method resolves given InventoryViewAttributes with DataView reference', async () => { + const { inventoryViewsClient, dataViews } = createInventoryViewsClient(); + + dataViews.get.mockResolvedValue( + createStubDataView({ + spec: { + id: 'LOG_DATA_VIEW', + title: 'log-indices-*', + timeFieldName: '@timestamp', + runtimeFieldMap: { + runtime_field: { + type: 'keyword', + script: { + source: 'emit("runtime value")', + }, + }, + }, + }, + }) + ); + + const resolvedInventoryView = await inventoryViewsClient.resolveInventoryView('log-view-id', { + name: 'LOG VIEW', + description: 'LOG VIEW DESCRIPTION', + logIndices: { + type: 'data_view', + dataViewId: 'LOG_DATA_VIEW', + }, + logColumns: [ + { timestampColumn: { id: 'TIMESTAMP_COLUMN_ID' } }, + { + fieldColumn: { + id: 'DATASET_COLUMN_ID', + field: 'event.dataset', + }, + }, + { + messageColumn: { id: 'MESSAGE_COLUMN_ID' }, + }, + ], + }); + + expect(resolvedInventoryView).toMatchInlineSnapshot(` + Object { + "columns": Array [ + Object { + "timestampColumn": Object { + "id": "TIMESTAMP_COLUMN_ID", + }, + }, + Object { + "fieldColumn": Object { + "field": "event.dataset", + "id": "DATASET_COLUMN_ID", + }, + }, + Object { + "messageColumn": Object { + "id": "MESSAGE_COLUMN_ID", + }, + }, + ], + "dataViewReference": DataView { + "allowNoIndex": false, + "deleteFieldFormat": [Function], + "fieldAttrs": Object {}, + "fieldFormatMap": Object {}, + "fieldFormats": Object { + "deserialize": [MockFunction], + "getByFieldType": [MockFunction], + "getDefaultConfig": [MockFunction], + "getDefaultInstance": [MockFunction], + "getDefaultInstanceCacheResolver": [MockFunction], + "getDefaultInstancePlain": [MockFunction], + "getDefaultType": [MockFunction], + "getDefaultTypeName": [MockFunction], + "getInstance": [MockFunction], + "getType": [MockFunction], + "getTypeNameByEsTypes": [MockFunction], + "getTypeWithoutMetaParams": [MockFunction], + "has": [MockFunction], + "init": [MockFunction], + "parseDefaultTypeMap": [MockFunction], + "register": [MockFunction], + }, + "fields": FldList [], + "flattenHit": [Function], + "getFieldAttrs": [Function], + "getIndexPattern": [Function], + "getName": [Function], + "getOriginalSavedObjectBody": [Function], + "id": "LOG_DATA_VIEW", + "matchedIndices": Array [], + "metaFields": Array [ + "_id", + "_type", + "_source", + ], + "name": "", + "namespaces": Array [], + "originalSavedObjectBody": Object {}, + "resetOriginalSavedObjectBody": [Function], + "runtimeFieldMap": Object { + "runtime_field": Object { + "script": Object { + "source": "emit(\\"runtime value\\")", + }, + "type": "keyword", + }, + }, + "setFieldFormat": [Function], + "setIndexPattern": [Function], + "shortDotsEnable": false, + "sourceFilters": Array [], + "timeFieldName": "@timestamp", + "title": "log-indices-*", + "type": undefined, + "typeMeta": undefined, + "version": "1", + }, + "description": "LOG VIEW DESCRIPTION", + "fields": FldList [], + "indices": "log-indices-*", + "messageField": Array [ + "message", + ], + "name": "LOG VIEW", + "runtimeMappings": Object { + "runtime_field": Object { + "script": Object { + "source": "emit(\\"runtime value\\")", + }, + "type": "keyword", + }, + }, + "tiebreakerField": "_doc", + "timestampField": "@timestamp", + } + `); + }); +}); + +const createInventoryViewsClient = () => { + const logger = loggerMock.create(); + const dataViews = dataViewsServiceMock; + const savedObjectsClient = savedObjectsClientMock.create(); + const infraSources = createInfraSourcesMock(); + const internalInventoryViews = new Map(); + const inventoryViewStaticConfig: InventoryViewsStaticConfig = { + messageFields: ['message'], + }; + + const inventoryViewsClient = new InventoryViewsClient( + logger, + Promise.resolve(dataViews), + savedObjectsClient, + infraSources, + internalInventoryViews, + inventoryViewStaticConfig + ); + + return { + dataViews, + infraSources, + internalInventoryViews, + inventoryViewStaticConfig, + inventoryViewsClient, + savedObjectsClient, + }; +}; + +const basicTestSourceConfiguration: InfraSource = { + id: 'ID', + origin: 'stored', + configuration: { + name: 'NAME', + description: 'DESCRIPTION', + logIndices: { + type: 'index_pattern', + indexPatternId: 'INDEX_PATTERN_ID', + }, + logColumns: [], + fields: { + message: [], + }, + metricAlias: 'METRIC_ALIAS', + inventoryDefaultView: 'INVENTORY_DEFAULT_VIEW', + metricsExplorerDefaultView: 'METRICS_EXPLORER_DEFAULT_VIEW', + anomalyThreshold: 0, + }, +}; diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts new file mode 100644 index 0000000000000..a3fdd6cb4ec86 --- /dev/null +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts @@ -0,0 +1,239 @@ +/* + * 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 type { PluginStart as DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; +import { + Logger, + SavedObject, + SavedObjectsClientContract, + SavedObjectsUtils, + SavedObjectsErrorHelpers, +} from '@kbn/core/server'; +import { + defaultInventoryViewAttributes, + defaultInventoryViewId, + LogIndexReference, + InventoryView, + InventoryViewAttributes, + InventoryViewReference, + InventoryViewsStaticConfig, + persistedInventoryViewReferenceRT, + ResolvedInventoryView, + resolveInventoryView, +} from '../../../common/log_views'; +import { decodeOrThrow } from '../../../common/runtime_types'; +import { LogIndexReference as SourceConfigurationLogIndexReference } from '../../../common/source_configuration/source_configuration'; +import type { IInfraSources, InfraSource } from '../../lib/sources'; +import { + extractInventoryViewSavedObjectReferences, + inventoryViewSavedObjectName, + resolveInventoryViewSavedObjectReferences, +} from '../../saved_objects/log_view'; +import { inventoryViewSavedObjectRT } from '../../saved_objects/log_view/types'; +import { NotFoundError } from './errors'; +import { IInventoryViewsClient } from './types'; + +type DataViewsService = ReturnType; + +export class InventoryViewsClient implements IInventoryViewsClient { + static errors = { + NotFoundError, + }; + + constructor( + private readonly logger: Logger, + private readonly dataViews: DataViewsService, + private readonly savedObjectsClient: SavedObjectsClientContract, + private readonly infraSources: IInfraSources, + private readonly internalInventoryViews: Map, + private readonly config: InventoryViewsStaticConfig + ) {} + + public async getInventoryView(inventoryViewId: string): Promise { + return await this.getSavedInventoryView(inventoryViewId) + .catch((err) => + SavedObjectsErrorHelpers.isNotFoundError(err) || err instanceof NotFoundError + ? this.getInternalInventoryView(inventoryViewId) + : Promise.reject(err) + ) + .catch((err) => + err instanceof NotFoundError + ? this.getInventoryViewFromInfraSourceConfiguration(inventoryViewId) + : Promise.reject(err) + ); + } + + findInventoryView() {} + deleteInventoryView(inventoryViewId: string) {} + + public async getResolvedInventoryView( + inventoryViewReference: InventoryViewReference + ): Promise { + const inventoryView = persistedInventoryViewReferenceRT.is(inventoryViewReference) + ? await this.getInventoryView(inventoryViewReference.inventoryViewId) + : inventoryViewReference; + const resolvedInventoryView = await this.resolveInventoryView( + inventoryView.id, + inventoryView.attributes + ); + return resolvedInventoryView; + } + + public async putInventoryView( + inventoryViewId: string, + inventoryViewAttributes: Partial + ): Promise { + const resolvedInventoryViewId = + (await this.resolveInventoryViewId(inventoryViewId)) ?? SavedObjectsUtils.generateId(); + + this.logger.debug( + `Trying to store inventory view "${inventoryViewId}" as "${resolvedInventoryViewId}"...` + ); + + const inventoryViewAttributesWithDefaults = { + ...defaultInventoryViewAttributes, + ...inventoryViewAttributes, + }; + + const { attributes, references } = extractInventoryViewSavedObjectReferences( + inventoryViewAttributesWithDefaults + ); + + const savedObject = await this.savedObjectsClient.create( + inventoryViewSavedObjectName, + attributes, + { + id: resolvedInventoryViewId, + overwrite: true, + references, + } + ); + + return getInventoryViewFromSavedObject(savedObject); + } + + public async resolveInventoryView( + inventoryViewId: string, + inventoryViewAttributes: InventoryViewAttributes + ): Promise { + return await resolveInventoryView( + inventoryViewId, + inventoryViewAttributes, + await this.dataViews, + this.config + ); + } + + private async getSavedInventoryView(inventoryViewId: string): Promise { + this.logger.debug(`Trying to load stored log view "${inventoryViewId}"...`); + + const resolvedInventoryViewId = await this.resolveInventoryViewId(inventoryViewId); + + if (!resolvedInventoryViewId) { + throw new NotFoundError( + `Failed to load saved log view: the log view id "${inventoryViewId}" could not be resolved.` + ); + } + + const savedObject = await this.savedObjectsClient.get( + inventoryViewSavedObjectName, + resolvedInventoryViewId + ); + + return getInventoryViewFromSavedObject(savedObject); + } + + private async getInternalInventoryView(inventoryViewId: string): Promise { + this.logger.debug(`Trying to load internal log view "${inventoryViewId}"...`); + + const internalInventoryView = this.internalInventoryViews.get(inventoryViewId); + + if (!internalInventoryView) { + throw new NotFoundError( + `Failed to load internal log view: no view with id "${inventoryViewId}" found.` + ); + } + + return internalInventoryView; + } + + private async getInventoryViewFromInfraSourceConfiguration( + sourceId: string + ): Promise { + this.logger.debug(`Trying to load log view from source configuration "${sourceId}"...`); + + const sourceConfiguration = await this.infraSources.getSourceConfiguration( + this.savedObjectsClient, + sourceId + ); + + return { + id: sourceConfiguration.id, + version: sourceConfiguration.version, + updatedAt: sourceConfiguration.updatedAt, + origin: `infra-source-${sourceConfiguration.origin}`, + attributes: getAttributesFromSourceConfiguration(sourceConfiguration), + }; + } + + private async resolveInventoryViewId(inventoryViewId: string): Promise { + // only the default id needs to be transformed + if (inventoryViewId !== defaultInventoryViewId) { + return inventoryViewId; + } + + return await this.getNewestSavedInventoryViewId(); + } + + private async getNewestSavedInventoryViewId(): Promise { + const response = await this.savedObjectsClient.find({ + type: inventoryViewSavedObjectName, + sortField: 'updated_at', + sortOrder: 'desc', + perPage: 1, + fields: [], + }); + + const [newestSavedInventoryView] = response.saved_objects; + + return newestSavedInventoryView?.id ?? null; + } +} + +const getInventoryViewFromSavedObject = (savedObject: SavedObject): InventoryView => { + const inventoryViewSavedObject = decodeOrThrow(inventoryViewSavedObjectRT)(savedObject); + + return { + id: inventoryViewSavedObject.id, + version: inventoryViewSavedObject.version, + updatedAt: inventoryViewSavedObject.updated_at, + origin: 'stored', + attributes: resolveInventoryViewSavedObjectReferences( + inventoryViewSavedObject.attributes, + savedObject.references + ), + }; +}; + +export const getAttributesFromSourceConfiguration = ({ + configuration: { name, description, logIndices, logColumns }, +}: InfraSource): InventoryViewAttributes => ({ + name, + description, + logIndices: getLogIndicesFromSourceConfigurationLogIndices(logIndices), + logColumns, +}); + +const getLogIndicesFromSourceConfigurationLogIndices = ( + logIndices: SourceConfigurationLogIndexReference +): LogIndexReference => + logIndices.type === 'index_pattern' + ? { + type: 'data_view', + dataViewId: logIndices.indexPatternId, + } + : logIndices; diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts new file mode 100644 index 0000000000000..a98cfd6fb86dc --- /dev/null +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts @@ -0,0 +1,20 @@ +/* + * 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 { createInventoryViewsClientMock } from './log_views_client.mock'; +import { InventoryViewsServiceSetup, InventoryViewsServiceStart } from './types'; + +export const createInventoryViewsServiceSetupMock = (): jest.Mocked => ({ + defineInternalInventoryView: jest.fn(), +}); + +export const createInventoryViewsServiceStartMock = (): jest.Mocked => ({ + getClient: jest.fn((_savedObjectsClient: any, _elasticsearchClient: any) => + createInventoryViewsClientMock() + ), + getScopedClient: jest.fn((_request: any) => createInventoryViewsClientMock()), +}); diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts new file mode 100644 index 0000000000000..7ebb0279620ba --- /dev/null +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts @@ -0,0 +1,65 @@ +/* + * 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 { + ElasticsearchClient, + KibanaRequest, + Logger, + SavedObjectsClientContract, +} from '@kbn/core/server'; +import { + defaultInventoryViewAttributes, + InventoryView, + InventoryViewAttributes, +} from '../../../common/log_views'; +import { InventoryViewsClient } from './inventory_views_client'; +import { + InventoryViewsServiceSetup, + InventoryViewsServiceStart, + InventoryViewsServiceStartDeps, +} from './types'; + +export class InventoryViewsService { + private internalInventoryViews: Map = new Map(); + + constructor(private readonly logger: Logger) {} + + public setup(): InventoryViewsServiceSetup {} + + public start({ + config, + dataViews, + elasticsearch, + infraSources, + savedObjects, + }: InventoryViewsServiceStartDeps): InventoryViewsServiceStart { + const { internalInventoryViews, logger } = this; + + return { + getClient( + savedObjectsClient: SavedObjectsClientContract, + elasticsearchClient: ElasticsearchClient, + request?: KibanaRequest + ) { + return new InventoryViewsClient( + logger, + dataViews.dataViewsServiceFactory(savedObjectsClient, elasticsearchClient, request), + savedObjectsClient, + infraSources, + internalInventoryViews, + config + ); + }, + getScopedClient(request: KibanaRequest) { + const savedObjectsClient = savedObjects.getScopedClient(request); + const elasticsearchClient = elasticsearch.client.asScoped(request).asCurrentUser; + + return this.getClient(savedObjectsClient, elasticsearchClient, request); + }, + }; + } +} diff --git a/x-pack/plugins/infra/server/services/inventory_views/types.ts b/x-pack/plugins/infra/server/services/inventory_views/types.ts new file mode 100644 index 0000000000000..c1b73ad5fd1e8 --- /dev/null +++ b/x-pack/plugins/infra/server/services/inventory_views/types.ts @@ -0,0 +1,52 @@ +/* + * 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 { + ElasticsearchClient, + ElasticsearchServiceStart, + KibanaRequest, + SavedObjectsClientContract, + SavedObjectsServiceStart, +} from '@kbn/core/server'; +import { PluginStart as DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; +import { + InventoryView, + InventoryViewAttributes, + InventoryViewReference, + InventoryViewsStaticConfig, + ResolvedInventoryView, +} from '../../../common/log_views'; +import { InfraSources } from '../../lib/sources'; + +export interface InventoryViewsServiceStartDeps { + config: InventoryViewsStaticConfig; + dataViews: DataViewsServerPluginStart; + elasticsearch: ElasticsearchServiceStart; + infraSources: InfraSources; + savedObjects: SavedObjectsServiceStart; +} + +export type InventoryViewsServiceSetup = void; + +export interface InventoryViewsServiceStart { + getClient( + savedObjectsClient: SavedObjectsClientContract, + elasticsearchClient: ElasticsearchClient, + request?: KibanaRequest + ): IInventoryViewsClient; + getScopedClient(request: KibanaRequest): IInventoryViewsClient; +} + +export interface IInventoryViewsClient { + findInventoryView(inventoryViewId: string): Promise; + getInventoryView(inventoryViewId: string): Promise; + putInventoryView( + inventoryViewId: string, + inventoryViewAttributes: Partial + ): Promise; + deleteInventoryView(inventoryViewId: string): Promise; +} From 10e34e8026e32c71bf86d85513dff9c7519ae95c Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Tue, 11 Apr 2023 16:21:28 +0200 Subject: [PATCH 02/20] refactor(infra): move saved objects into server --- .../saved_objects/metrics_explorer_view.ts | 23 ----------- .../infra/server/saved_objects/index.ts | 2 + .../saved_objects/inventory_view/index.ts | 12 ++++++ .../inventory_view_saved_object.ts} | 18 ++++++++- .../saved_objects/inventory_view/types.ts | 21 ++++++++++ .../metrics_explorer_view/index.ts | 12 ++++++ .../metrics_explorer_view_saved_object.ts | 39 +++++++++++++++++++ .../metrics_explorer_view/types.ts | 21 ++++++++++ 8 files changed, 124 insertions(+), 24 deletions(-) delete mode 100644 x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts create mode 100644 x-pack/plugins/infra/server/saved_objects/inventory_view/index.ts rename x-pack/plugins/infra/{common/saved_objects/inventory_view.ts => server/saved_objects/inventory_view/inventory_view_saved_object.ts} (50%) create mode 100644 x-pack/plugins/infra/server/saved_objects/inventory_view/types.ts create mode 100644 x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/index.ts create mode 100644 x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/metrics_explorer_view_saved_object.ts create mode 100644 x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/types.ts diff --git a/x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts b/x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts deleted file mode 100644 index 7f7ca7a932203..0000000000000 --- a/x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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 type { SavedObjectsType } from '@kbn/core/server'; - -export const metricsExplorerViewSavedObjectName = 'metrics-explorer-view'; - -export const metricsExplorerViewSavedObjectType: SavedObjectsType = { - name: metricsExplorerViewSavedObjectName, - hidden: false, - namespaceType: 'single', - management: { - importableAndExportable: true, - }, - mappings: { - dynamic: false, - properties: {}, - }, -}; diff --git a/x-pack/plugins/infra/server/saved_objects/index.ts b/x-pack/plugins/infra/server/saved_objects/index.ts index bd7ecac5179a1..cf6906fc733f7 100644 --- a/x-pack/plugins/infra/server/saved_objects/index.ts +++ b/x-pack/plugins/infra/server/saved_objects/index.ts @@ -5,4 +5,6 @@ * 2.0. */ +export * from './inventory_view'; export * from './log_view'; +export * from './metrics_explorer_view'; diff --git a/x-pack/plugins/infra/server/saved_objects/inventory_view/index.ts b/x-pack/plugins/infra/server/saved_objects/inventory_view/index.ts new file mode 100644 index 0000000000000..458d3fa65c6a0 --- /dev/null +++ b/x-pack/plugins/infra/server/saved_objects/inventory_view/index.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +export { + inventoryViewSavedObjectName, + inventoryViewSavedObjectType, +} from './inventory_view_saved_object'; +export { inventoryViewSavedObjectRT } from './types'; diff --git a/x-pack/plugins/infra/common/saved_objects/inventory_view.ts b/x-pack/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.ts similarity index 50% rename from x-pack/plugins/infra/common/saved_objects/inventory_view.ts rename to x-pack/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.ts index 7e935086cb08a..7fe1dfec2195f 100644 --- a/x-pack/plugins/infra/common/saved_objects/inventory_view.ts +++ b/x-pack/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.ts @@ -5,15 +5,31 @@ * 2.0. */ -import type { SavedObjectsType } from '@kbn/core/server'; +import { fold } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { SavedObject, SavedObjectsType } from '@kbn/core/server'; +import { inventoryViewSavedObjectRT } from './types'; export const inventoryViewSavedObjectName = 'inventory-view'; +const getInventoryViewTitle = (savedObject: SavedObject) => + pipe( + inventoryViewSavedObjectRT.decode(savedObject), + fold( + () => `Inventory view [id=${savedObject.id}]`, + ({ attributes: { name } }) => name + ) + ); + export const inventoryViewSavedObjectType: SavedObjectsType = { name: inventoryViewSavedObjectName, hidden: false, namespaceType: 'single', management: { + defaultSearchField: 'name', + displayName: 'inventory view', + getTitle: getInventoryViewTitle, + icon: 'metricsApp', importableAndExportable: true, }, mappings: { diff --git a/x-pack/plugins/infra/server/saved_objects/inventory_view/types.ts b/x-pack/plugins/infra/server/saved_objects/inventory_view/types.ts new file mode 100644 index 0000000000000..540b91ee740dd --- /dev/null +++ b/x-pack/plugins/infra/server/saved_objects/inventory_view/types.ts @@ -0,0 +1,21 @@ +/* + * 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 { isoToEpochRt } from '@kbn/io-ts-utils'; +import * as rt from 'io-ts'; +import { inventoryViewAttributesRT } from '../../../common/inventory_views'; + +export const inventoryViewSavedObjectRT = rt.intersection([ + rt.type({ + id: rt.string, + attributes: inventoryViewAttributesRT, + }), + rt.partial({ + version: rt.string, + updated_at: isoToEpochRt, + }), +]); diff --git a/x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/index.ts b/x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/index.ts new file mode 100644 index 0000000000000..6f3f926319cf2 --- /dev/null +++ b/x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/index.ts @@ -0,0 +1,12 @@ +/* + * 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. + */ + +export { + metricsExplorerViewSavedObjectName, + metricsExplorerViewSavedObjectType, +} from './metrics_explorer_view_saved_object'; +export { metricsExplorerViewSavedObjectRT } from './types'; diff --git a/x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/metrics_explorer_view_saved_object.ts b/x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/metrics_explorer_view_saved_object.ts new file mode 100644 index 0000000000000..7281a51f96fcd --- /dev/null +++ b/x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/metrics_explorer_view_saved_object.ts @@ -0,0 +1,39 @@ +/* + * 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 { fold } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { SavedObject, SavedObjectsType } from '@kbn/core/server'; +import { metricsExplorerViewSavedObjectRT } from './types'; + +export const metricsExplorerViewSavedObjectName = 'metrics-explorer-view'; + +const getMetricsExplorerViewTitle = (savedObject: SavedObject) => + pipe( + metricsExplorerViewSavedObjectRT.decode(savedObject), + fold( + () => `Metrics explorer view [id=${savedObject.id}]`, + ({ attributes: { name } }) => name + ) + ); + +export const metricsExplorerViewSavedObjectType: SavedObjectsType = { + name: metricsExplorerViewSavedObjectName, + hidden: false, + namespaceType: 'single', + management: { + defaultSearchField: 'name', + displayName: 'metrics explorer view', + getTitle: getMetricsExplorerViewTitle, + icon: 'metricsApp', + importableAndExportable: true, + }, + mappings: { + dynamic: false, + properties: {}, + }, +}; diff --git a/x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/types.ts b/x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/types.ts new file mode 100644 index 0000000000000..1168b2003994e --- /dev/null +++ b/x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/types.ts @@ -0,0 +1,21 @@ +/* + * 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 { isoToEpochRt } from '@kbn/io-ts-utils'; +import * as rt from 'io-ts'; +import { metricsExplorerViewAttributesRT } from '../../../common/metrics_explorer_views'; + +export const metricsExplorerViewSavedObjectRT = rt.intersection([ + rt.type({ + id: rt.string, + attributes: metricsExplorerViewAttributesRT, + }), + rt.partial({ + version: rt.string, + updated_at: isoToEpochRt, + }), +]); From a7c9330ee0f7934b0177ecab0887be3e55522260 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Tue, 11 Apr 2023 16:22:29 +0200 Subject: [PATCH 03/20] feat(infra): add inventory view to common types with versioning --- x-pack/plugins/infra/common/http_api/index.ts | 6 ++++ .../http_api/inventory_views/v1/common.ts | 11 +++++++ .../inventory_views/v1/get_inventory_view.ts | 18 ++++++++++ .../http_api/inventory_views/v1/index.ts | 10 ++++++ .../inventory_views/v1/put_inventory_view.ts | 22 +++++++++++++ .../plugins/infra/common/http_api/latest.ts | 8 +++++ .../infra/common/inventory_views/index.ts | 8 +++++ .../infra/common/inventory_views/types.ts | 33 +++++++++++++++++++ .../common/metrics_explorer_views/index.ts | 8 +++++ .../common/metrics_explorer_views/types.ts | 33 +++++++++++++++++++ 10 files changed, 157 insertions(+) create mode 100644 x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts create mode 100644 x-pack/plugins/infra/common/http_api/inventory_views/v1/get_inventory_view.ts create mode 100644 x-pack/plugins/infra/common/http_api/inventory_views/v1/index.ts create mode 100644 x-pack/plugins/infra/common/http_api/inventory_views/v1/put_inventory_view.ts create mode 100644 x-pack/plugins/infra/common/http_api/latest.ts create mode 100644 x-pack/plugins/infra/common/inventory_views/index.ts create mode 100644 x-pack/plugins/infra/common/inventory_views/types.ts create mode 100644 x-pack/plugins/infra/common/metrics_explorer_views/index.ts create mode 100644 x-pack/plugins/infra/common/metrics_explorer_views/types.ts diff --git a/x-pack/plugins/infra/common/http_api/index.ts b/x-pack/plugins/infra/common/http_api/index.ts index 52906bcabb65a..ad0cda12ceea9 100644 --- a/x-pack/plugins/infra/common/http_api/index.ts +++ b/x-pack/plugins/infra/common/http_api/index.ts @@ -13,3 +13,9 @@ export * from './metrics_api'; export * from './log_alerts'; export * from './snapshot_api'; export * from './host_details'; + +/** + * Exporting versioned APIs types + */ +export * from './latest'; +export * as inventoryViewsV1 from './inventory_views/v1'; diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts new file mode 100644 index 0000000000000..96611f1eff8b2 --- /dev/null +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +export const INVENTORY_VIEW_URL_PREFIX = '/api/infra/log_views'; +export const INVENTORY_VIEW_URL = `${INVENTORY_VIEW_URL_PREFIX}/{inventoryViewId}`; +export const getInventoryViewUrl = (inventoryViewId: string) => + `${INVENTORY_VIEW_URL_PREFIX}/${inventoryViewId}`; diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/get_inventory_view.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/get_inventory_view.ts new file mode 100644 index 0000000000000..cce3f4849c6f4 --- /dev/null +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/get_inventory_view.ts @@ -0,0 +1,18 @@ +/* + * 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 * as rt from 'io-ts'; +// import { logViewRT } from '../../log_views'; + +export const getInventoryViewRequestParamsRT = rt.type({ + // the id of the log view + logViewId: rt.string, +}); + +// export const getInventoryViewResponsePayloadRT = rt.type({ +// data: logViewRT, +// }); diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/index.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/index.ts new file mode 100644 index 0000000000000..8b5e7b95c62d7 --- /dev/null +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/index.ts @@ -0,0 +1,10 @@ +/* + * 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. + */ + +export { getInventoryViewUrl, INVENTORY_VIEW_URL } from './common'; +export * from './get_inventory_view'; +export * from './put_inventory_view'; diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/put_inventory_view.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/put_inventory_view.ts new file mode 100644 index 0000000000000..d694d2d985bee --- /dev/null +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/put_inventory_view.ts @@ -0,0 +1,22 @@ +/* + * 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 * as rt from 'io-ts'; +// import { logViewAttributesRT, logViewRT } from '../../log_views'; + +export const putLogViewRequestParamsRT = rt.type({ + logViewId: rt.string, +}); + +// export const putLogViewRequestPayloadRT = rt.type({ +// attributes: rt.partial(logViewAttributesRT.type.props), +// }); +// export type PutLogViewRequestPayload = rt.TypeOf; + +// export const putLogViewResponsePayloadRT = rt.type({ +// data: logViewRT, +// }); diff --git a/x-pack/plugins/infra/common/http_api/latest.ts b/x-pack/plugins/infra/common/http_api/latest.ts new file mode 100644 index 0000000000000..519da4a60dec1 --- /dev/null +++ b/x-pack/plugins/infra/common/http_api/latest.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './inventory_views/v1'; diff --git a/x-pack/plugins/infra/common/inventory_views/index.ts b/x-pack/plugins/infra/common/inventory_views/index.ts new file mode 100644 index 0000000000000..6cc0ccaa93a6d --- /dev/null +++ b/x-pack/plugins/infra/common/inventory_views/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './types'; diff --git a/x-pack/plugins/infra/common/inventory_views/types.ts b/x-pack/plugins/infra/common/inventory_views/types.ts new file mode 100644 index 0000000000000..59cb6a6cca6f7 --- /dev/null +++ b/x-pack/plugins/infra/common/inventory_views/types.ts @@ -0,0 +1,33 @@ +/* + * 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 * as rt from 'io-ts'; + +export const inventoryViewAttributesRT = rt.intersection([ + rt.strict({ + name: rt.string, + }), + rt.UnknownRecord, +]); + +export type InventoryViewAttributes = rt.TypeOf; + +// export const inventoryViewRT = rt.exact( +// rt.intersection([ +// rt.type({ +// id: rt.string, +// origin: logViewOriginRT, +// attributes: logViewAttributesRT, +// }), +// rt.partial({ +// updatedAt: rt.number, +// version: rt.string, +// }), +// ]) +// ); + +// export type LogView = rt.TypeOf; diff --git a/x-pack/plugins/infra/common/metrics_explorer_views/index.ts b/x-pack/plugins/infra/common/metrics_explorer_views/index.ts new file mode 100644 index 0000000000000..6cc0ccaa93a6d --- /dev/null +++ b/x-pack/plugins/infra/common/metrics_explorer_views/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './types'; diff --git a/x-pack/plugins/infra/common/metrics_explorer_views/types.ts b/x-pack/plugins/infra/common/metrics_explorer_views/types.ts new file mode 100644 index 0000000000000..8c80e78136957 --- /dev/null +++ b/x-pack/plugins/infra/common/metrics_explorer_views/types.ts @@ -0,0 +1,33 @@ +/* + * 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 * as rt from 'io-ts'; + +export const metricsExplorerViewAttributesRT = rt.intersection([ + rt.strict({ + name: rt.string, + }), + rt.UnknownRecord, +]); + +export type MetricsExplorerViewAttributes = rt.TypeOf; + +// export const inventoryViewRT = rt.exact( +// rt.intersection([ +// rt.type({ +// id: rt.string, +// origin: logViewOriginRT, +// attributes: logViewAttributesRT, +// }), +// rt.partial({ +// updatedAt: rt.number, +// version: rt.string, +// }), +// ]) +// ); + +// export type LogView = rt.TypeOf; From c3d9c8ef9a610b0121c7584463071191f5bc33a9 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Wed, 12 Apr 2023 08:46:05 +0200 Subject: [PATCH 04/20] feat(infra): wip endpoints --- .../http_api/inventory_views/v1/common.ts | 2 +- x-pack/plugins/infra/server/plugin.ts | 8 +- .../server/services/inventory_views/index.ts | 2 +- .../inventory_views_client.mock.ts | 4 +- .../inventory_views_client.test.ts | 73 ++++++++++--------- .../inventory_views/inventory_views_client.ts | 43 ++++++----- .../inventory_views_service.mock.ts | 20 ++--- .../inventory_views_service.ts | 8 +- .../server/services/inventory_views/types.ts | 4 +- 9 files changed, 86 insertions(+), 78 deletions(-) diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts index 96611f1eff8b2..1353adc8f5a58 100644 --- a/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts @@ -5,7 +5,7 @@ * 2.0. */ -export const INVENTORY_VIEW_URL_PREFIX = '/api/infra/log_views'; +export const INVENTORY_VIEW_URL_PREFIX = '/api/infra/inventory_views'; export const INVENTORY_VIEW_URL = `${INVENTORY_VIEW_URL_PREFIX}/{inventoryViewId}`; export const getInventoryViewUrl = (inventoryViewId: string) => `${INVENTORY_VIEW_URL_PREFIX}/${inventoryViewId}`; diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index 0fb0aad42d0cc..c23065076cc2e 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -20,8 +20,6 @@ import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; import { LOGS_FEATURE_ID, METRICS_FEATURE_ID } from '../common/constants'; import { defaultLogViewsStaticConfig } from '../common/log_views'; import { publicConfigKeys } from '../common/plugin_config_types'; -import { inventoryViewSavedObjectType } from '../common/saved_objects/inventory_view'; -import { metricsExplorerViewSavedObjectType } from '../common/saved_objects/metrics_explorer_view'; import { configDeprecations, getInfraDeprecationsFactory } from './deprecations'; import { LOGS_FEATURE, METRICS_FEATURE } from './features'; import { initInfraServer } from './infra_server'; @@ -43,7 +41,11 @@ import { InfraBackendLibs, InfraDomainLibs } from './lib/infra_types'; import { makeGetMetricIndices } from './lib/metrics/make_get_metric_indices'; import { infraSourceConfigurationSavedObjectType, InfraSources } from './lib/sources'; import { InfraSourceStatus } from './lib/source_status'; -import { logViewSavedObjectType } from './saved_objects'; +import { + inventoryViewSavedObjectType, + logViewSavedObjectType, + metricsExplorerViewSavedObjectType, +} from './saved_objects'; import { LogEntriesService } from './services/log_entries'; import { LogViewsService } from './services/log_views'; import { RulesService } from './services/rules'; diff --git a/x-pack/plugins/infra/server/services/inventory_views/index.ts b/x-pack/plugins/infra/server/services/inventory_views/index.ts index 2deff89789686..1df6b8cd44814 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/index.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -export { InventoryViewsService } from './log_views_service'; +export { InventoryViewsService } from './inventory_views_service'; export { InventoryViewsClient } from './inventory_views_client'; export type { InventoryViewsServiceSetup, diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts index 3e7e204c4707d..0e116c52a4db0 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { InventoryViewReference } from '../../../common/log_views'; -import { createResolvedInventoryViewMock } from '../../../common/log_views/resolved_log_view.mock'; +import { InventoryViewReference } from '../../../common/inventory_views'; +import { createResolvedInventoryViewMock } from '../../../common/inventory_views/resolved_Inventory_view.mock'; import { IInventoryViewsClient } from './types'; export const createInventoryViewsClientMock = (): jest.Mocked => ({ diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts index 501dd99bf0549..03fbd042f6730 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { loggerMock } from '@kbn/logging-mocks'; +import { LoggerMock } from '@kbn/logging-mocks'; import { SavedObject, SavedObjectsUtils } from '@kbn/core/server'; import { savedObjectsClientMock } from '@kbn/core/server/mocks'; import { createStubDataView } from '@kbn/data-views-plugin/common/stubs'; @@ -15,44 +15,44 @@ import { InventoryView, InventoryViewAttributes, InventoryViewsStaticConfig, -} from '../../../common/log_views'; -import { createInventoryViewMock } from '../../../common/log_views/log_view.mock'; +} from '../../../common/inventory_views'; +import { createInventoryViewMock } from '../../../common/inventory_views/inventory_view.mock'; import { InfraSource } from '../../lib/sources'; import { createInfraSourcesMock } from '../../lib/sources/mocks'; import { extractInventoryViewSavedObjectReferences, inventoryViewSavedObjectName, -} from '../../saved_objects/log_view'; +} from '../../saved_objects/inventory_view'; import { getAttributesFromSourceConfiguration, InventoryViewsClient, } from './inventory_views_client'; describe('getAttributesFromSourceConfiguration function', () => { - it('converts the index_pattern log indices type to data_view', () => { + it('converts the index_pattern Inventory indices type to data_view', () => { const inventoryViewAttributes = getAttributesFromSourceConfiguration( basicTestSourceConfiguration ); - expect(inventoryViewAttributes.logIndices).toEqual({ + expect(inventoryViewAttributes.InventoryIndices).toEqual({ type: 'data_view', dataViewId: 'INDEX_PATTERN_ID', }); }); - it('preserves the index_name log indices type', () => { + it('preserves the index_name Inventory indices type', () => { const inventoryViewAttributes = getAttributesFromSourceConfiguration({ ...basicTestSourceConfiguration, configuration: { ...basicTestSourceConfiguration.configuration, - logIndices: { + InventoryIndices: { type: 'index_name', indexName: 'INDEX_NAME', }, }, }); - expect(inventoryViewAttributes.logIndices).toEqual({ + expect(inventoryViewAttributes.InventoryIndices).toEqual({ type: 'index_name', indexName: 'INDEX_NAME', }); @@ -244,7 +244,7 @@ describe('InventoryViewsClient class', () => { createStubDataView({ spec: { id: 'LOG_DATA_VIEW', - title: 'log-indices-*', + title: 'Inventory-indices-*', timeFieldName: '@timestamp', runtimeFieldMap: { runtime_field: { @@ -258,26 +258,29 @@ describe('InventoryViewsClient class', () => { }) ); - const resolvedInventoryView = await inventoryViewsClient.resolveInventoryView('log-view-id', { - name: 'LOG VIEW', - description: 'LOG VIEW DESCRIPTION', - logIndices: { - type: 'data_view', - dataViewId: 'LOG_DATA_VIEW', - }, - logColumns: [ - { timestampColumn: { id: 'TIMESTAMP_COLUMN_ID' } }, - { - fieldColumn: { - id: 'DATASET_COLUMN_ID', - field: 'event.dataset', - }, + const resolvedInventoryView = await inventoryViewsClient.resolveInventoryView( + 'Inventory-view-id', + { + name: 'LOG VIEW', + description: 'LOG VIEW DESCRIPTION', + InventoryIndices: { + type: 'data_view', + dataViewId: 'LOG_DATA_VIEW', }, - { - messageColumn: { id: 'MESSAGE_COLUMN_ID' }, - }, - ], - }); + InventoryColumns: [ + { timestampColumn: { id: 'TIMESTAMP_COLUMN_ID' } }, + { + fieldColumn: { + id: 'DATASET_COLUMN_ID', + field: 'event.dataset', + }, + }, + { + messageColumn: { id: 'MESSAGE_COLUMN_ID' }, + }, + ], + } + ); expect(resolvedInventoryView).toMatchInlineSnapshot(` Object { @@ -352,14 +355,14 @@ describe('InventoryViewsClient class', () => { "shortDotsEnable": false, "sourceFilters": Array [], "timeFieldName": "@timestamp", - "title": "log-indices-*", + "title": "Inventory-indices-*", "type": undefined, "typeMeta": undefined, "version": "1", }, "description": "LOG VIEW DESCRIPTION", "fields": FldList [], - "indices": "log-indices-*", + "indices": "Inventory-indices-*", "messageField": Array [ "message", ], @@ -380,7 +383,7 @@ describe('InventoryViewsClient class', () => { }); const createInventoryViewsClient = () => { - const logger = loggerMock.create(); + const Inventoryger = LoggerMock.create(); const dataViews = dataViewsServiceMock; const savedObjectsClient = savedObjectsClientMock.create(); const infraSources = createInfraSourcesMock(); @@ -390,7 +393,7 @@ const createInventoryViewsClient = () => { }; const inventoryViewsClient = new InventoryViewsClient( - logger, + Inventoryger, Promise.resolve(dataViews), savedObjectsClient, infraSources, @@ -414,11 +417,11 @@ const basicTestSourceConfiguration: InfraSource = { configuration: { name: 'NAME', description: 'DESCRIPTION', - logIndices: { + InventoryIndices: { type: 'index_pattern', indexPatternId: 'INDEX_PATTERN_ID', }, - logColumns: [], + InventoryColumns: [], fields: { message: [], }, diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts index a3fdd6cb4ec86..328445b148331 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts @@ -24,7 +24,7 @@ import { persistedInventoryViewReferenceRT, ResolvedInventoryView, resolveInventoryView, -} from '../../../common/log_views'; +} from '../../../common/inventory_views'; import { decodeOrThrow } from '../../../common/runtime_types'; import { LogIndexReference as SourceConfigurationLogIndexReference } from '../../../common/source_configuration/source_configuration'; import type { IInfraSources, InfraSource } from '../../lib/sources'; @@ -32,8 +32,8 @@ import { extractInventoryViewSavedObjectReferences, inventoryViewSavedObjectName, resolveInventoryViewSavedObjectReferences, -} from '../../saved_objects/log_view'; -import { inventoryViewSavedObjectRT } from '../../saved_objects/log_view/types'; +} from '../../saved_objects/inventory_view'; +import { inventoryViewSavedObjectRT } from '../../saved_objects/inventory_view/types'; import { NotFoundError } from './errors'; import { IInventoryViewsClient } from './types'; @@ -49,11 +49,10 @@ export class InventoryViewsClient implements IInventoryViewsClient { private readonly dataViews: DataViewsService, private readonly savedObjectsClient: SavedObjectsClientContract, private readonly infraSources: IInfraSources, - private readonly internalInventoryViews: Map, private readonly config: InventoryViewsStaticConfig ) {} - public async getInventoryView(inventoryViewId: string): Promise { + public async get(inventoryViewId: string): Promise { return await this.getSavedInventoryView(inventoryViewId) .catch((err) => SavedObjectsErrorHelpers.isNotFoundError(err) || err instanceof NotFoundError @@ -67,8 +66,14 @@ export class InventoryViewsClient implements IInventoryViewsClient { ); } - findInventoryView() {} - deleteInventoryView(inventoryViewId: string) {} + public async find() { + const savedObject = await this.savedObjectsClient.find({ + type: inventoryViewSavedObjectName, + perPage: 1000, // Fetch 1 page by default with a max of 1000 results + }); + } + + public async deleteInventoryView(inventoryViewId: string) {} public async getResolvedInventoryView( inventoryViewReference: InventoryViewReference @@ -129,13 +134,13 @@ export class InventoryViewsClient implements IInventoryViewsClient { } private async getSavedInventoryView(inventoryViewId: string): Promise { - this.logger.debug(`Trying to load stored log view "${inventoryViewId}"...`); + this.logger.debug(`Trying to load stored Inventory view "${inventoryViewId}"...`); const resolvedInventoryViewId = await this.resolveInventoryViewId(inventoryViewId); if (!resolvedInventoryViewId) { throw new NotFoundError( - `Failed to load saved log view: the log view id "${inventoryViewId}" could not be resolved.` + `Failed to load saved Inventory view: the Inventory view id "${inventoryViewId}" could not be resolved.` ); } @@ -148,13 +153,13 @@ export class InventoryViewsClient implements IInventoryViewsClient { } private async getInternalInventoryView(inventoryViewId: string): Promise { - this.logger.debug(`Trying to load internal log view "${inventoryViewId}"...`); + this.logger.debug(`Trying to load internal Inventory view "${inventoryViewId}"...`); const internalInventoryView = this.internalInventoryViews.get(inventoryViewId); if (!internalInventoryView) { throw new NotFoundError( - `Failed to load internal log view: no view with id "${inventoryViewId}" found.` + `Failed to load internal Inventory view: no view with id "${inventoryViewId}" found.` ); } @@ -164,7 +169,7 @@ export class InventoryViewsClient implements IInventoryViewsClient { private async getInventoryViewFromInfraSourceConfiguration( sourceId: string ): Promise { - this.logger.debug(`Trying to load log view from source configuration "${sourceId}"...`); + this.logger.debug(`Trying to load Inventory view from source configuration "${sourceId}"...`); const sourceConfiguration = await this.infraSources.getSourceConfiguration( this.savedObjectsClient, @@ -220,20 +225,20 @@ const getInventoryViewFromSavedObject = (savedObject: SavedObject): Inv }; export const getAttributesFromSourceConfiguration = ({ - configuration: { name, description, logIndices, logColumns }, + configuration: { name, description, InventoryIndices, InventoryColumns }, }: InfraSource): InventoryViewAttributes => ({ name, description, - logIndices: getLogIndicesFromSourceConfigurationLogIndices(logIndices), - logColumns, + InventoryIndices: getLogIndicesFromSourceConfigurationLogIndices(InventoryIndices), + InventoryColumns, }); const getLogIndicesFromSourceConfigurationLogIndices = ( - logIndices: SourceConfigurationLogIndexReference + InventoryIndices: SourceConfigurationLogIndexReference ): LogIndexReference => - logIndices.type === 'index_pattern' + InventoryIndices.type === 'index_pattern' ? { type: 'data_view', - dataViewId: logIndices.indexPatternId, + dataViewId: InventoryIndices.indexPatternId, } - : logIndices; + : InventoryIndices; diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts index a98cfd6fb86dc..79c21dca7b195 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts @@ -5,16 +5,16 @@ * 2.0. */ -import { createInventoryViewsClientMock } from './log_views_client.mock'; +import { createInventoryViewsClientMock } from './inventory_views_client.mock'; import { InventoryViewsServiceSetup, InventoryViewsServiceStart } from './types'; -export const createInventoryViewsServiceSetupMock = (): jest.Mocked => ({ - defineInternalInventoryView: jest.fn(), -}); +export const createInventoryViewsServiceSetupMock = + (): jest.Mocked => {}; -export const createInventoryViewsServiceStartMock = (): jest.Mocked => ({ - getClient: jest.fn((_savedObjectsClient: any, _elasticsearchClient: any) => - createInventoryViewsClientMock() - ), - getScopedClient: jest.fn((_request: any) => createInventoryViewsClientMock()), -}); +export const createInventoryViewsServiceStartMock = + (): jest.Mocked => ({ + getClient: jest.fn((_savedObjectsClient: any, _elasticsearchClient: any) => + createInventoryViewsClientMock() + ), + getScopedClient: jest.fn((_request: any) => createInventoryViewsClientMock()), + }); diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts index 7ebb0279620ba..4cb132bc55a09 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts @@ -15,7 +15,7 @@ import { defaultInventoryViewAttributes, InventoryView, InventoryViewAttributes, -} from '../../../common/log_views'; +} from '../../../common/inventory_views'; import { InventoryViewsClient } from './inventory_views_client'; import { InventoryViewsServiceSetup, @@ -24,8 +24,6 @@ import { } from './types'; export class InventoryViewsService { - private internalInventoryViews: Map = new Map(); - constructor(private readonly logger: Logger) {} public setup(): InventoryViewsServiceSetup {} @@ -37,7 +35,7 @@ export class InventoryViewsService { infraSources, savedObjects, }: InventoryViewsServiceStartDeps): InventoryViewsServiceStart { - const { internalInventoryViews, logger } = this; + const { logger } = this; return { getClient( @@ -50,10 +48,10 @@ export class InventoryViewsService { dataViews.dataViewsServiceFactory(savedObjectsClient, elasticsearchClient, request), savedObjectsClient, infraSources, - internalInventoryViews, config ); }, + getScopedClient(request: KibanaRequest) { const savedObjectsClient = savedObjects.getScopedClient(request); const elasticsearchClient = elasticsearch.client.asScoped(request).asCurrentUser; diff --git a/x-pack/plugins/infra/server/services/inventory_views/types.ts b/x-pack/plugins/infra/server/services/inventory_views/types.ts index c1b73ad5fd1e8..a689f784cec42 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/types.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/types.ts @@ -19,7 +19,7 @@ import { InventoryViewReference, InventoryViewsStaticConfig, ResolvedInventoryView, -} from '../../../common/log_views'; +} from '../../../common/inventory_views'; import { InfraSources } from '../../lib/sources'; export interface InventoryViewsServiceStartDeps { @@ -48,5 +48,5 @@ export interface IInventoryViewsClient { inventoryViewId: string, inventoryViewAttributes: Partial ): Promise; - deleteInventoryView(inventoryViewId: string): Promise; + deleteInventoryView(inventoryViewId: string): Promise; } From bab4c469bd1ad5b54d7ac0276567832af9765059 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Thu, 13 Apr 2023 12:21:18 +0200 Subject: [PATCH 05/20] feat(infra): implement inventory view endpoints --- .../http_api/inventory_views/v1/common.ts | 49 +++- .../v1/create_inventory_view.ts | 28 ++ .../inventory_views/v1/find_inventory_view.ts | 33 +++ .../inventory_views/v1/get_inventory_view.ts | 10 +- .../http_api/inventory_views/v1/index.ts | 6 +- .../inventory_views/v1/put_inventory_view.ts | 22 -- .../v1/update_inventory_view.ts | 28 ++ .../infra/common/inventory_views/types.ts | 31 +- x-pack/plugins/infra/server/infra_server.ts | 2 + x-pack/plugins/infra/server/plugin.ts | 11 + .../inventory_views/create_inventory_view.ts | 57 ++++ .../inventory_views/delete_inventory_view.ts | 54 ++++ .../inventory_views/find_inventory_view.ts | 49 ++++ .../inventory_views/get_inventory_view.ts | 59 ++++ .../server/routes/inventory_views/index.ts | 16 +- .../inventory_views/put_inventory_view.ts | 0 .../inventory_views/update_inventory_view.ts | 65 +++++ .../saved_objects/inventory_view/types.ts | 10 +- .../server/services/inventory_views/errors.ts | 13 - .../inventory_views_client.mock.ts | 13 +- .../inventory_views/inventory_views_client.ts | 273 ++++++------------ .../inventory_views_service.mock.ts | 4 +- .../inventory_views_service.ts | 32 +- .../server/services/inventory_views/types.ts | 37 +-- x-pack/plugins/infra/server/types.ts | 2 + 25 files changed, 589 insertions(+), 315 deletions(-) create mode 100644 x-pack/plugins/infra/common/http_api/inventory_views/v1/create_inventory_view.ts create mode 100644 x-pack/plugins/infra/common/http_api/inventory_views/v1/find_inventory_view.ts delete mode 100644 x-pack/plugins/infra/common/http_api/inventory_views/v1/put_inventory_view.ts create mode 100644 x-pack/plugins/infra/common/http_api/inventory_views/v1/update_inventory_view.ts create mode 100644 x-pack/plugins/infra/server/routes/inventory_views/create_inventory_view.ts delete mode 100644 x-pack/plugins/infra/server/routes/inventory_views/put_inventory_view.ts create mode 100644 x-pack/plugins/infra/server/routes/inventory_views/update_inventory_view.ts delete mode 100644 x-pack/plugins/infra/server/services/inventory_views/errors.ts diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts index 1353adc8f5a58..190e26588b4a0 100644 --- a/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts @@ -4,8 +4,49 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { nonEmptyStringRt } from '@kbn/io-ts-utils'; +import * as rt from 'io-ts'; -export const INVENTORY_VIEW_URL_PREFIX = '/api/infra/inventory_views'; -export const INVENTORY_VIEW_URL = `${INVENTORY_VIEW_URL_PREFIX}/{inventoryViewId}`; -export const getInventoryViewUrl = (inventoryViewId: string) => - `${INVENTORY_VIEW_URL_PREFIX}/${inventoryViewId}`; +export const INVENTORY_VIEW_URL = '/api/infra/inventory_views'; +export const INVENTORY_VIEW_URL_ENTITY = `${INVENTORY_VIEW_URL}/{inventoryViewId}`; +export const getInventoryViewUrl = (inventoryViewId?: string) => + [INVENTORY_VIEW_URL, inventoryViewId].filter(Boolean).join('/'); + +export const inventoryViewRequestParamsRT = rt.type({ + inventoryViewId: rt.string, +}); + +export type InventoryViewRequestParams = rt.TypeOf; + +export const inventoryViewRequestQueryRT = rt.partial({ + sourceId: rt.string, +}); + +export type InventoryViewRequestQuery = rt.TypeOf; + +const inventoryViewAttributesResponseRT = rt.intersection([ + rt.strict({ + name: nonEmptyStringRt, + isDefault: rt.boolean, + }), + rt.UnknownRecord, +]); + +const inventoryViewResponseRT = rt.exact( + rt.intersection([ + rt.type({ + id: rt.string, + attributes: inventoryViewAttributesResponseRT, + }), + rt.partial({ + updatedAt: rt.number, + version: rt.string, + }), + ]) +); + +export const inventoryViewResponsePayloadRT = rt.type({ + data: inventoryViewResponseRT, +}); + +export type GetInventoryViewResponsePayload = rt.TypeOf; diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/create_inventory_view.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/create_inventory_view.ts new file mode 100644 index 0000000000000..9742348a6887f --- /dev/null +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/create_inventory_view.ts @@ -0,0 +1,28 @@ +/* + * 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 { nonEmptyStringRt } from '@kbn/io-ts-utils'; +import * as rt from 'io-ts'; + +export const createInventoryViewAttributesRequestPayloadRT = rt.intersection([ + rt.type({ + name: nonEmptyStringRt, + }), + rt.UnknownRecord, +]); + +export type CreateInventoryViewAttributesRequestPayload = rt.TypeOf< + typeof createInventoryViewAttributesRequestPayloadRT +>; + +export const createInventoryViewRequestPayloadRT = rt.type({ + attributes: createInventoryViewAttributesRequestPayloadRT, +}); + +export type CreateInventoryViewRequestPayload = rt.TypeOf< + typeof createInventoryViewRequestPayloadRT +>; diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/find_inventory_view.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/find_inventory_view.ts new file mode 100644 index 0000000000000..56c6b989bb734 --- /dev/null +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/find_inventory_view.ts @@ -0,0 +1,33 @@ +/* + * 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 { nonEmptyStringRt } from '@kbn/io-ts-utils'; +import * as rt from 'io-ts'; + +export const findInventoryViewAttributesResponseRT = rt.strict({ + name: nonEmptyStringRt, + isDefault: rt.boolean, +}); + +const findInventoryViewResponseRT = rt.exact( + rt.intersection([ + rt.type({ + id: rt.string, + attributes: findInventoryViewAttributesResponseRT, + }), + rt.partial({ + updatedAt: rt.number, + version: rt.string, + }), + ]) +); + +export const findInventoryViewResponsePayloadRT = rt.type({ + data: rt.array(findInventoryViewResponseRT), +}); + +export type FindInventoryViewResponsePayload = rt.TypeOf; diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/get_inventory_view.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/get_inventory_view.ts index cce3f4849c6f4..e2127d7b88121 100644 --- a/x-pack/plugins/infra/common/http_api/inventory_views/v1/get_inventory_view.ts +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/get_inventory_view.ts @@ -6,13 +6,9 @@ */ import * as rt from 'io-ts'; -// import { logViewRT } from '../../log_views'; -export const getInventoryViewRequestParamsRT = rt.type({ - // the id of the log view - logViewId: rt.string, +export const getInventoryViewRequestQueryRT = rt.partial({ + sourceId: rt.string, }); -// export const getInventoryViewResponsePayloadRT = rt.type({ -// data: logViewRT, -// }); +export type GetInventoryViewRequestQuery = rt.TypeOf; diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/index.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/index.ts index 8b5e7b95c62d7..74f0d3b6962a1 100644 --- a/x-pack/plugins/infra/common/http_api/inventory_views/v1/index.ts +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/index.ts @@ -5,6 +5,8 @@ * 2.0. */ -export { getInventoryViewUrl, INVENTORY_VIEW_URL } from './common'; +export * from './common'; export * from './get_inventory_view'; -export * from './put_inventory_view'; +export * from './find_inventory_view'; +export * from './create_inventory_view'; +export * from './update_inventory_view'; diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/put_inventory_view.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/put_inventory_view.ts deleted file mode 100644 index d694d2d985bee..0000000000000 --- a/x-pack/plugins/infra/common/http_api/inventory_views/v1/put_inventory_view.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 * as rt from 'io-ts'; -// import { logViewAttributesRT, logViewRT } from '../../log_views'; - -export const putLogViewRequestParamsRT = rt.type({ - logViewId: rt.string, -}); - -// export const putLogViewRequestPayloadRT = rt.type({ -// attributes: rt.partial(logViewAttributesRT.type.props), -// }); -// export type PutLogViewRequestPayload = rt.TypeOf; - -// export const putLogViewResponsePayloadRT = rt.type({ -// data: logViewRT, -// }); diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/update_inventory_view.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/update_inventory_view.ts new file mode 100644 index 0000000000000..6ee0d8c57da06 --- /dev/null +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/update_inventory_view.ts @@ -0,0 +1,28 @@ +/* + * 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 { nonEmptyStringRt } from '@kbn/io-ts-utils'; +import * as rt from 'io-ts'; + +export const updateInventoryViewAttributesRequestPayloadRT = rt.intersection([ + rt.type({ + name: nonEmptyStringRt, + }), + rt.UnknownRecord, +]); + +export type UpdateInventoryViewAttributesRequestPayload = rt.TypeOf< + typeof updateInventoryViewAttributesRequestPayloadRT +>; + +export const updateInventoryViewRequestPayloadRT = rt.type({ + attributes: updateInventoryViewAttributesRequestPayloadRT, +}); + +export type UpdateInventoryViewRequestPayload = rt.TypeOf< + typeof updateInventoryViewRequestPayloadRT +>; diff --git a/x-pack/plugins/infra/common/inventory_views/types.ts b/x-pack/plugins/infra/common/inventory_views/types.ts index 59cb6a6cca6f7..99881bd3cf452 100644 --- a/x-pack/plugins/infra/common/inventory_views/types.ts +++ b/x-pack/plugins/infra/common/inventory_views/types.ts @@ -5,29 +5,30 @@ * 2.0. */ +import { nonEmptyStringRt } from '@kbn/io-ts-utils'; import * as rt from 'io-ts'; export const inventoryViewAttributesRT = rt.intersection([ rt.strict({ - name: rt.string, + name: nonEmptyStringRt, + isDefault: rt.boolean, }), rt.UnknownRecord, ]); export type InventoryViewAttributes = rt.TypeOf; -// export const inventoryViewRT = rt.exact( -// rt.intersection([ -// rt.type({ -// id: rt.string, -// origin: logViewOriginRT, -// attributes: logViewAttributesRT, -// }), -// rt.partial({ -// updatedAt: rt.number, -// version: rt.string, -// }), -// ]) -// ); +export const inventoryViewRT = rt.exact( + rt.intersection([ + rt.type({ + id: rt.string, + attributes: inventoryViewAttributesRT, + }), + rt.partial({ + updatedAt: rt.number, + version: rt.string, + }), + ]) +); -// export type LogView = rt.TypeOf; +export type InventoryView = rt.TypeOf; diff --git a/x-pack/plugins/infra/server/infra_server.ts b/x-pack/plugins/infra/server/infra_server.ts index 18f6c943f234b..f2db13eab3ecd 100644 --- a/x-pack/plugins/infra/server/infra_server.ts +++ b/x-pack/plugins/infra/server/infra_server.ts @@ -8,6 +8,7 @@ import { InfraBackendLibs } from './lib/infra_types'; import { initGetHostsAnomaliesRoute, initGetK8sAnomaliesRoute } from './routes/infra_ml'; import { initInventoryMetaRoute } from './routes/inventory_metadata'; +import { initInventoryViewRoutes } from './routes/inventory_views'; import { initIpToHostName } from './routes/ip_to_hostname'; import { initGetLogAlertsChartPreviewDataRoute } from './routes/log_alerts'; import { @@ -60,6 +61,7 @@ export const initInfraServer = (libs: InfraBackendLibs) => { initMetricsAPIRoute(libs); initMetadataRoute(libs); initInventoryMetaRoute(libs); + initInventoryViewRoutes(libs); initGetLogAlertsChartPreviewDataRoute(libs); initProcessListRoute(libs); initOverviewRoute(libs); diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index c23065076cc2e..4b8afcf79b5b6 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -46,6 +46,7 @@ import { logViewSavedObjectType, metricsExplorerViewSavedObjectType, } from './saved_objects'; +import { InventoryViewsService } from './services/inventory_views'; import { LogEntriesService } from './services/log_entries'; import { LogViewsService } from './services/log_views'; import { RulesService } from './services/rules'; @@ -114,6 +115,7 @@ export class InfraServerPlugin private logsRules: RulesService; private metricsRules: RulesService; + private inventoryViews: InventoryViewsService; private logViews: LogViewsService; constructor(context: PluginInitializerContext) { @@ -131,6 +133,7 @@ export class InfraServerPlugin this.logger.get('metricsRules') ); + this.inventoryViews = new InventoryViewsService(this.logger.get('inventoryViews')); this.logViews = new LogViewsService(this.logger.get('logViews')); } @@ -145,6 +148,7 @@ export class InfraServerPlugin sources, } ); + const inventoryViews = this.inventoryViews.setup(); const logViews = this.logViews.setup(); // register saved object types @@ -226,11 +230,17 @@ export class InfraServerPlugin return { defineInternalSourceConfiguration: sources.defineInternalSourceConfiguration.bind(sources), + inventoryViews, logViews, } as InfraPluginSetup; } start(core: CoreStart, plugins: InfraServerPluginStartDeps) { + const inventoryViews = this.inventoryViews.start({ + infraSources: this.libs.sources, + savedObjects: core.savedObjects, + }); + const logViews = this.logViews.start({ infraSources: this.libs.sources, savedObjects: core.savedObjects, @@ -244,6 +254,7 @@ export class InfraServerPlugin }); return { + inventoryViews, logViews, getMetricIndices: makeGetMetricIndices(this.libs.sources), }; diff --git a/x-pack/plugins/infra/server/routes/inventory_views/create_inventory_view.ts b/x-pack/plugins/infra/server/routes/inventory_views/create_inventory_view.ts new file mode 100644 index 0000000000000..c3e7a03acec5e --- /dev/null +++ b/x-pack/plugins/infra/server/routes/inventory_views/create_inventory_view.ts @@ -0,0 +1,57 @@ +/* + * 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 { isBoom } from '@hapi/boom'; +import { createValidationFunction } from '../../../common/runtime_types'; +import { + createInventoryViewRequestPayloadRT, + inventoryViewResponsePayloadRT, + INVENTORY_VIEW_URL, +} from '../../../common/http_api/latest'; +import type { InfraBackendLibs } from '../../lib/infra_types'; + +export const initCreateInventoryViewRoute = ({ + framework, + getStartServices, +}: Pick) => { + framework.registerRoute( + { + method: 'post', + path: INVENTORY_VIEW_URL, + validate: { + body: createValidationFunction(createInventoryViewRequestPayloadRT), + }, + }, + async (_requestContext, request, response) => { + const { body } = request; + const { inventoryViews } = (await getStartServices())[2]; + const inventoryViewsClient = inventoryViews.getScopedClient(request); + + try { + const inventoryView = await inventoryViewsClient.create(body.attributes); + + return response.ok({ + body: inventoryViewResponsePayloadRT.encode({ data: inventoryView }), + }); + } catch (error) { + if (isBoom(error)) { + return response.customError({ + statusCode: error.output.statusCode, + body: { message: error.output.payload.message }, + }); + } + + return response.customError({ + statusCode: error.statusCode ?? 500, + body: { + message: error.message ?? 'An unexpected error occurred', + }, + }); + } + } + ); +}; diff --git a/x-pack/plugins/infra/server/routes/inventory_views/delete_inventory_view.ts b/x-pack/plugins/infra/server/routes/inventory_views/delete_inventory_view.ts index e69de29bb2d1d..83ad61fc46c52 100644 --- a/x-pack/plugins/infra/server/routes/inventory_views/delete_inventory_view.ts +++ b/x-pack/plugins/infra/server/routes/inventory_views/delete_inventory_view.ts @@ -0,0 +1,54 @@ +/* + * 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 { isBoom } from '@hapi/boom'; +import { createValidationFunction } from '../../../common/runtime_types'; +import { + inventoryViewRequestParamsRT, + INVENTORY_VIEW_URL_ENTITY, +} from '../../../common/http_api/latest'; +import type { InfraBackendLibs } from '../../lib/infra_types'; + +export const initDeleteInventoryViewRoute = ({ + framework, + getStartServices, +}: Pick) => { + framework.registerRoute( + { + method: 'delete', + path: INVENTORY_VIEW_URL_ENTITY, + validate: { + params: createValidationFunction(inventoryViewRequestParamsRT), + }, + }, + async (_requestContext, request, response) => { + const { params } = request; + const { inventoryViews } = (await getStartServices())[2]; + const inventoryViewsClient = inventoryViews.getScopedClient(request); + + try { + await inventoryViewsClient.delete(params.inventoryViewId); + + return response.noContent(); + } catch (error) { + if (isBoom(error)) { + return response.customError({ + statusCode: error.output.statusCode, + body: { message: error.output.payload.message }, + }); + } + + return response.customError({ + statusCode: error.statusCode ?? 500, + body: { + message: error.message ?? 'An unexpected error occurred', + }, + }); + } + } + ); +}; diff --git a/x-pack/plugins/infra/server/routes/inventory_views/find_inventory_view.ts b/x-pack/plugins/infra/server/routes/inventory_views/find_inventory_view.ts index e69de29bb2d1d..abdfc2f8749e4 100644 --- a/x-pack/plugins/infra/server/routes/inventory_views/find_inventory_view.ts +++ b/x-pack/plugins/infra/server/routes/inventory_views/find_inventory_view.ts @@ -0,0 +1,49 @@ +/* + * 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 { createValidationFunction } from '../../../common/runtime_types'; +import { + findInventoryViewResponsePayloadRT, + inventoryViewRequestQueryRT, + INVENTORY_VIEW_URL, +} from '../../../common/http_api/latest'; +import type { InfraBackendLibs } from '../../lib/infra_types'; + +export const initFindInventoryViewRoute = ({ + framework, + getStartServices, +}: Pick) => { + framework.registerRoute( + { + method: 'get', + path: INVENTORY_VIEW_URL, + validate: { + query: createValidationFunction(inventoryViewRequestQueryRT), + }, + }, + async (_requestContext, request, response) => { + const { query } = request; + const { inventoryViews } = (await getStartServices())[2]; + const inventoryViewsClient = inventoryViews.getScopedClient(request); + + try { + const inventoryViewsList = await inventoryViewsClient.find(query); + + return response.ok({ + body: findInventoryViewResponsePayloadRT.encode({ data: inventoryViewsList }), + }); + } catch (error) { + return response.customError({ + statusCode: error.statusCode ?? 500, + body: { + message: error.message ?? 'An unexpected error occurred', + }, + }); + } + } + ); +}; diff --git a/x-pack/plugins/infra/server/routes/inventory_views/get_inventory_view.ts b/x-pack/plugins/infra/server/routes/inventory_views/get_inventory_view.ts index e69de29bb2d1d..87f5feb97f061 100644 --- a/x-pack/plugins/infra/server/routes/inventory_views/get_inventory_view.ts +++ b/x-pack/plugins/infra/server/routes/inventory_views/get_inventory_view.ts @@ -0,0 +1,59 @@ +/* + * 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 { isBoom } from '@hapi/boom'; +import { createValidationFunction } from '../../../common/runtime_types'; +import { + inventoryViewResponsePayloadRT, + inventoryViewRequestParamsRT, + inventoryViewRequestQueryRT, + INVENTORY_VIEW_URL_ENTITY, +} from '../../../common/http_api/latest'; +import type { InfraBackendLibs } from '../../lib/infra_types'; + +export const initGetInventoryViewRoute = ({ + framework, + getStartServices, +}: Pick) => { + framework.registerRoute( + { + method: 'get', + path: INVENTORY_VIEW_URL_ENTITY, + validate: { + params: createValidationFunction(inventoryViewRequestParamsRT), + query: createValidationFunction(inventoryViewRequestQueryRT), + }, + }, + async (_requestContext, request, response) => { + const { params, query } = request; + const { inventoryViews } = (await getStartServices())[2]; + const inventoryViewsClient = inventoryViews.getScopedClient(request); + + try { + const inventoryView = await inventoryViewsClient.get(params.inventoryViewId, query); + + return response.ok({ + body: inventoryViewResponsePayloadRT.encode({ data: inventoryView }), + }); + } catch (error) { + if (isBoom(error)) { + return response.customError({ + statusCode: error.output.statusCode, + body: { message: error.output.payload.message }, + }); + } + + return response.customError({ + statusCode: error.statusCode ?? 500, + body: { + message: error.message ?? 'An unexpected error occurred', + }, + }); + } + } + ); +}; diff --git a/x-pack/plugins/infra/server/routes/inventory_views/index.ts b/x-pack/plugins/infra/server/routes/inventory_views/index.ts index 8c55857c05b5c..55cee58a8a464 100644 --- a/x-pack/plugins/infra/server/routes/inventory_views/index.ts +++ b/x-pack/plugins/infra/server/routes/inventory_views/index.ts @@ -5,19 +5,19 @@ * 2.0. */ -import { KibanaFramework } from '../../lib/adapters/framework/kibana_framework_adapter'; -import { InfraPluginStartServicesAccessor } from '../../types'; +import { InfraBackendLibs } from '../../lib/infra_types'; +import { initCreateInventoryViewRoute } from './create_inventory_view'; import { initDeleteInventoryViewRoute } from './delete_inventory_view'; import { initFindInventoryViewRoute } from './find_inventory_view'; import { initGetInventoryViewRoute } from './get_inventory_view'; -import { initPutInventoryViewRoute } from './put_inventory_view'; +import { initUpdateInventoryViewRoute } from './update_inventory_view'; -export const initInventoryViewRoutes = (dependencies: { - framework: KibanaFramework; - getStartServices: InfraPluginStartServicesAccessor; -}) => { +export const initInventoryViewRoutes = ( + dependencies: Pick +) => { + initCreateInventoryViewRoute(dependencies); initDeleteInventoryViewRoute(dependencies); initFindInventoryViewRoute(dependencies); initGetInventoryViewRoute(dependencies); - initPutInventoryViewRoute(dependencies); + initUpdateInventoryViewRoute(dependencies); }; diff --git a/x-pack/plugins/infra/server/routes/inventory_views/put_inventory_view.ts b/x-pack/plugins/infra/server/routes/inventory_views/put_inventory_view.ts deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/x-pack/plugins/infra/server/routes/inventory_views/update_inventory_view.ts b/x-pack/plugins/infra/server/routes/inventory_views/update_inventory_view.ts new file mode 100644 index 0000000000000..d2b583437d177 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/inventory_views/update_inventory_view.ts @@ -0,0 +1,65 @@ +/* + * 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 { isBoom } from '@hapi/boom'; +import { createValidationFunction } from '../../../common/runtime_types'; +import { + inventoryViewRequestParamsRT, + inventoryViewRequestQueryRT, + inventoryViewResponsePayloadRT, + INVENTORY_VIEW_URL_ENTITY, + updateInventoryViewRequestPayloadRT, +} from '../../../common/http_api/latest'; +import type { InfraBackendLibs } from '../../lib/infra_types'; + +export const initUpdateInventoryViewRoute = ({ + framework, + getStartServices, +}: Pick) => { + framework.registerRoute( + { + method: 'put', + path: INVENTORY_VIEW_URL_ENTITY, + validate: { + params: createValidationFunction(inventoryViewRequestParamsRT), + query: createValidationFunction(inventoryViewRequestQueryRT), + body: createValidationFunction(updateInventoryViewRequestPayloadRT), + }, + }, + async (_requestContext, request, response) => { + const { body, params, query } = request; + const { inventoryViews } = (await getStartServices())[2]; + const inventoryViewsClient = inventoryViews.getScopedClient(request); + + try { + const inventoryView = await inventoryViewsClient.update( + params.inventoryViewId, + body.attributes, + query + ); + + return response.ok({ + body: inventoryViewResponsePayloadRT.encode({ data: inventoryView }), + }); + } catch (error) { + if (isBoom(error)) { + return response.customError({ + statusCode: error.output.statusCode, + body: { message: error.output.payload.message }, + }); + } + + return response.customError({ + statusCode: error.statusCode ?? 500, + body: { + message: error.message ?? 'An unexpected error occurred', + }, + }); + } + } + ); +}; diff --git a/x-pack/plugins/infra/server/saved_objects/inventory_view/types.ts b/x-pack/plugins/infra/server/saved_objects/inventory_view/types.ts index 540b91ee740dd..083bac3e1f683 100644 --- a/x-pack/plugins/infra/server/saved_objects/inventory_view/types.ts +++ b/x-pack/plugins/infra/server/saved_objects/inventory_view/types.ts @@ -7,12 +7,18 @@ import { isoToEpochRt } from '@kbn/io-ts-utils'; import * as rt from 'io-ts'; -import { inventoryViewAttributesRT } from '../../../common/inventory_views'; + +export const inventoryViewSavedObjectAttributesRT = rt.intersection([ + rt.strict({ + name: rt.string, + }), + rt.UnknownRecord, +]); export const inventoryViewSavedObjectRT = rt.intersection([ rt.type({ id: rt.string, - attributes: inventoryViewAttributesRT, + attributes: inventoryViewSavedObjectAttributesRT, }), rt.partial({ version: rt.string, diff --git a/x-pack/plugins/infra/server/services/inventory_views/errors.ts b/x-pack/plugins/infra/server/services/inventory_views/errors.ts deleted file mode 100644 index fb0dc3b031511..0000000000000 --- a/x-pack/plugins/infra/server/services/inventory_views/errors.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * 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. - */ - -export class NotFoundError extends Error { - constructor(message?: string) { - super(message); - Object.setPrototypeOf(this, new.target.prototype); - } -} diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts index 0e116c52a4db0..5be7ae42746d4 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts @@ -5,15 +5,12 @@ * 2.0. */ -import { InventoryViewReference } from '../../../common/inventory_views'; -import { createResolvedInventoryViewMock } from '../../../common/inventory_views/resolved_Inventory_view.mock'; import { IInventoryViewsClient } from './types'; export const createInventoryViewsClientMock = (): jest.Mocked => ({ - getInventoryView: jest.fn(), - getResolvedInventoryView: jest.fn((inventoryViewReference: InventoryViewReference) => - Promise.resolve(createResolvedInventoryViewMock()) - ), - putInventoryView: jest.fn(), - resolveInventoryView: jest.fn(), + delete: jest.fn(), + find: jest.fn(), + get: jest.fn(), + create: jest.fn(), + update: jest.fn(), }); diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts index 328445b148331..4aec4a3273661 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts @@ -10,235 +10,146 @@ import { Logger, SavedObject, SavedObjectsClientContract, - SavedObjectsUtils, - SavedObjectsErrorHelpers, + SavedObjectsFindResponse, + SavedObjectsFindResult, + SavedObjectsUpdateResponse, } from '@kbn/core/server'; +import Boom from '@hapi/boom'; import { - defaultInventoryViewAttributes, - defaultInventoryViewId, - LogIndexReference, - InventoryView, - InventoryViewAttributes, - InventoryViewReference, - InventoryViewsStaticConfig, - persistedInventoryViewReferenceRT, - ResolvedInventoryView, - resolveInventoryView, -} from '../../../common/inventory_views'; + CreateInventoryViewAttributesRequestPayload, + InventoryViewRequestQuery, +} from '../../../common/http_api/latest'; +import { InventoryView, InventoryViewAttributes } from '../../../common/inventory_views'; import { decodeOrThrow } from '../../../common/runtime_types'; -import { LogIndexReference as SourceConfigurationLogIndexReference } from '../../../common/source_configuration/source_configuration'; -import type { IInfraSources, InfraSource } from '../../lib/sources'; -import { - extractInventoryViewSavedObjectReferences, - inventoryViewSavedObjectName, - resolveInventoryViewSavedObjectReferences, -} from '../../saved_objects/inventory_view'; +import type { IInfraSources } from '../../lib/sources'; +import { inventoryViewSavedObjectName } from '../../saved_objects/inventory_view'; import { inventoryViewSavedObjectRT } from '../../saved_objects/inventory_view/types'; -import { NotFoundError } from './errors'; import { IInventoryViewsClient } from './types'; -type DataViewsService = ReturnType; - export class InventoryViewsClient implements IInventoryViewsClient { - static errors = { - NotFoundError, - }; - constructor( private readonly logger: Logger, - private readonly dataViews: DataViewsService, private readonly savedObjectsClient: SavedObjectsClientContract, - private readonly infraSources: IInfraSources, - private readonly config: InventoryViewsStaticConfig + private readonly infraSources: IInfraSources ) {} - public async get(inventoryViewId: string): Promise { - return await this.getSavedInventoryView(inventoryViewId) - .catch((err) => - SavedObjectsErrorHelpers.isNotFoundError(err) || err instanceof NotFoundError - ? this.getInternalInventoryView(inventoryViewId) - : Promise.reject(err) - ) - .catch((err) => - err instanceof NotFoundError - ? this.getInventoryViewFromInfraSourceConfiguration(inventoryViewId) - : Promise.reject(err) - ); - } + public async find(query: InventoryViewRequestQuery): Promise { + this.logger.debug('Trying to load inventory views ...'); - public async find() { - const savedObject = await this.savedObjectsClient.find({ - type: inventoryViewSavedObjectName, - perPage: 1000, // Fetch 1 page by default with a max of 1000 results - }); - } + const sourceId = query.sourceId ?? 'default'; + + const [sourceConfiguration, inventoryViewSavedObject] = await Promise.all([ + this.infraSources.getSourceConfiguration(this.savedObjectsClient, sourceId), + this.savedObjectsClient.find({ + type: inventoryViewSavedObjectName, + perPage: 1000, // Fetch 1 page by default with a max of 1000 results + }), + ]); - public async deleteInventoryView(inventoryViewId: string) {} - - public async getResolvedInventoryView( - inventoryViewReference: InventoryViewReference - ): Promise { - const inventoryView = persistedInventoryViewReferenceRT.is(inventoryViewReference) - ? await this.getInventoryView(inventoryViewReference.inventoryViewId) - : inventoryViewReference; - const resolvedInventoryView = await this.resolveInventoryView( - inventoryView.id, - inventoryView.attributes + return inventoryViewSavedObject.saved_objects.map((savedObject) => + this.mapSavedObjectToInventoryView( + savedObject, + sourceConfiguration.configuration.inventoryDefaultView + ) ); - return resolvedInventoryView; } - public async putInventoryView( + public async get( inventoryViewId: string, - inventoryViewAttributes: Partial + query: InventoryViewRequestQuery ): Promise { - const resolvedInventoryViewId = - (await this.resolveInventoryViewId(inventoryViewId)) ?? SavedObjectsUtils.generateId(); + this.logger.debug(`Trying to load inventory view with id ${inventoryViewId} ...`); - this.logger.debug( - `Trying to store inventory view "${inventoryViewId}" as "${resolvedInventoryViewId}"...` - ); + const sourceId = query.sourceId ?? 'default'; - const inventoryViewAttributesWithDefaults = { - ...defaultInventoryViewAttributes, - ...inventoryViewAttributes, - }; + const [sourceConfiguration, inventoryViewSavedObject] = await Promise.all([ + this.infraSources.getSourceConfiguration(this.savedObjectsClient, sourceId), + this.savedObjectsClient.get(inventoryViewSavedObjectName, inventoryViewId), + ]); - const { attributes, references } = extractInventoryViewSavedObjectReferences( - inventoryViewAttributesWithDefaults + return this.mapSavedObjectToInventoryView( + inventoryViewSavedObject, + sourceConfiguration.configuration.inventoryDefaultView ); + } - const savedObject = await this.savedObjectsClient.create( + public async create( + attributes: CreateInventoryViewAttributesRequestPayload + ): Promise { + this.logger.debug(`Trying to create inventory view ...`); + + // Validate there is not a view with the same name + await this.assertNameConflict(attributes.name); + + const inventoryViewSavedObject = await this.savedObjectsClient.create( inventoryViewSavedObjectName, - attributes, - { - id: resolvedInventoryViewId, - overwrite: true, - references, - } + attributes ); - return getInventoryViewFromSavedObject(savedObject); + return this.mapSavedObjectToInventoryView(inventoryViewSavedObject); } - public async resolveInventoryView( + public async update( inventoryViewId: string, - inventoryViewAttributes: InventoryViewAttributes - ): Promise { - return await resolveInventoryView( - inventoryViewId, - inventoryViewAttributes, - await this.dataViews, - this.config - ); - } + attributes: CreateInventoryViewAttributesRequestPayload, + query: InventoryViewRequestQuery + ): Promise { + this.logger.debug(`Trying to create inventory view ...`); - private async getSavedInventoryView(inventoryViewId: string): Promise { - this.logger.debug(`Trying to load stored Inventory view "${inventoryViewId}"...`); + // Validate there is not a view with the same name + await this.assertNameConflict(attributes.name, [inventoryViewId]); - const resolvedInventoryViewId = await this.resolveInventoryViewId(inventoryViewId); + const sourceId = query.sourceId ?? 'default'; - if (!resolvedInventoryViewId) { - throw new NotFoundError( - `Failed to load saved Inventory view: the Inventory view id "${inventoryViewId}" could not be resolved.` - ); - } + const [sourceConfiguration, inventoryViewSavedObject] = await Promise.all([ + this.infraSources.getSourceConfiguration(this.savedObjectsClient, sourceId), + this.savedObjectsClient.update(inventoryViewSavedObjectName, inventoryViewId, attributes), + ]); - const savedObject = await this.savedObjectsClient.get( - inventoryViewSavedObjectName, - resolvedInventoryViewId + return this.mapSavedObjectToInventoryView( + inventoryViewSavedObject, + sourceConfiguration.configuration.inventoryDefaultView ); - - return getInventoryViewFromSavedObject(savedObject); } - private async getInternalInventoryView(inventoryViewId: string): Promise { - this.logger.debug(`Trying to load internal Inventory view "${inventoryViewId}"...`); - - const internalInventoryView = this.internalInventoryViews.get(inventoryViewId); + public delete(inventoryViewId: string): Promise<{}> { + this.logger.debug(`Trying to delete inventory view with id ${inventoryViewId} ...`); - if (!internalInventoryView) { - throw new NotFoundError( - `Failed to load internal Inventory view: no view with id "${inventoryViewId}" found.` - ); - } - - return internalInventoryView; + return this.savedObjectsClient.delete(inventoryViewSavedObjectName, inventoryViewId); } - private async getInventoryViewFromInfraSourceConfiguration( - sourceId: string - ): Promise { - this.logger.debug(`Trying to load Inventory view from source configuration "${sourceId}"...`); - - const sourceConfiguration = await this.infraSources.getSourceConfiguration( - this.savedObjectsClient, - sourceId - ); + private mapSavedObjectToInventoryView( + savedObject: SavedObject | SavedObjectsUpdateResponse, + defaultViewId?: string + ) { + const inventoryViewSavedObject = decodeOrThrow(inventoryViewSavedObjectRT)(savedObject); return { - id: sourceConfiguration.id, - version: sourceConfiguration.version, - updatedAt: sourceConfiguration.updatedAt, - origin: `infra-source-${sourceConfiguration.origin}`, - attributes: getAttributesFromSourceConfiguration(sourceConfiguration), + id: inventoryViewSavedObject.id, + version: inventoryViewSavedObject.version, + updatedAt: inventoryViewSavedObject.updated_at, + attributes: { + ...inventoryViewSavedObject.attributes, + isDefault: inventoryViewSavedObject.id === defaultViewId, + }, }; } - private async resolveInventoryViewId(inventoryViewId: string): Promise { - // only the default id needs to be transformed - if (inventoryViewId !== defaultInventoryViewId) { - return inventoryViewId; - } - - return await this.getNewestSavedInventoryViewId(); - } - - private async getNewestSavedInventoryViewId(): Promise { - const response = await this.savedObjectsClient.find({ + /** + * We want to control conflicting names on the views + */ + private async assertNameConflict(name: string, whitelist: string[] = []) { + const results = await this.savedObjectsClient.find({ type: inventoryViewSavedObjectName, - sortField: 'updated_at', - sortOrder: 'desc', - perPage: 1, - fields: [], + perPage: 1000, }); - const [newestSavedInventoryView] = response.saved_objects; + const hasConflict = results.saved_objects.some( + (obj) => !whitelist.includes(obj.id) && obj.attributes.name === name + ); - return newestSavedInventoryView?.id ?? null; + if (hasConflict) { + throw Boom.conflict('A view with that name already exists.'); + } } } - -const getInventoryViewFromSavedObject = (savedObject: SavedObject): InventoryView => { - const inventoryViewSavedObject = decodeOrThrow(inventoryViewSavedObjectRT)(savedObject); - - return { - id: inventoryViewSavedObject.id, - version: inventoryViewSavedObject.version, - updatedAt: inventoryViewSavedObject.updated_at, - origin: 'stored', - attributes: resolveInventoryViewSavedObjectReferences( - inventoryViewSavedObject.attributes, - savedObject.references - ), - }; -}; - -export const getAttributesFromSourceConfiguration = ({ - configuration: { name, description, InventoryIndices, InventoryColumns }, -}: InfraSource): InventoryViewAttributes => ({ - name, - description, - InventoryIndices: getLogIndicesFromSourceConfigurationLogIndices(InventoryIndices), - InventoryColumns, -}); - -const getLogIndicesFromSourceConfigurationLogIndices = ( - InventoryIndices: SourceConfigurationLogIndexReference -): LogIndexReference => - InventoryIndices.type === 'index_pattern' - ? { - type: 'data_view', - dataViewId: InventoryIndices.indexPatternId, - } - : InventoryIndices; diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts index 79c21dca7b195..f2cb8bb130bd3 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts @@ -13,8 +13,6 @@ export const createInventoryViewsServiceSetupMock = export const createInventoryViewsServiceStartMock = (): jest.Mocked => ({ - getClient: jest.fn((_savedObjectsClient: any, _elasticsearchClient: any) => - createInventoryViewsClientMock() - ), + getClient: jest.fn((_savedObjectsClient: any) => createInventoryViewsClientMock()), getScopedClient: jest.fn((_request: any) => createInventoryViewsClientMock()), }); diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts index 4cb132bc55a09..16fe09ba6cdcb 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts @@ -5,17 +5,7 @@ * 2.0. */ -import { - ElasticsearchClient, - KibanaRequest, - Logger, - SavedObjectsClientContract, -} from '@kbn/core/server'; -import { - defaultInventoryViewAttributes, - InventoryView, - InventoryViewAttributes, -} from '../../../common/inventory_views'; +import { KibanaRequest, Logger, SavedObjectsClientContract } from '@kbn/core/server'; import { InventoryViewsClient } from './inventory_views_client'; import { InventoryViewsServiceSetup, @@ -29,34 +19,20 @@ export class InventoryViewsService { public setup(): InventoryViewsServiceSetup {} public start({ - config, - dataViews, - elasticsearch, infraSources, savedObjects, }: InventoryViewsServiceStartDeps): InventoryViewsServiceStart { const { logger } = this; return { - getClient( - savedObjectsClient: SavedObjectsClientContract, - elasticsearchClient: ElasticsearchClient, - request?: KibanaRequest - ) { - return new InventoryViewsClient( - logger, - dataViews.dataViewsServiceFactory(savedObjectsClient, elasticsearchClient, request), - savedObjectsClient, - infraSources, - config - ); + getClient(savedObjectsClient: SavedObjectsClientContract) { + return new InventoryViewsClient(logger, savedObjectsClient, infraSources); }, getScopedClient(request: KibanaRequest) { const savedObjectsClient = savedObjects.getScopedClient(request); - const elasticsearchClient = elasticsearch.client.asScoped(request).asCurrentUser; - return this.getClient(savedObjectsClient, elasticsearchClient, request); + return this.getClient(savedObjectsClient); }, }; } diff --git a/x-pack/plugins/infra/server/services/inventory_views/types.ts b/x-pack/plugins/infra/server/services/inventory_views/types.ts index a689f784cec42..0e3b72e763dcc 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/types.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/types.ts @@ -6,26 +6,19 @@ */ import { - ElasticsearchClient, - ElasticsearchServiceStart, KibanaRequest, SavedObjectsClientContract, SavedObjectsServiceStart, } from '@kbn/core/server'; -import { PluginStart as DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; import { - InventoryView, - InventoryViewAttributes, - InventoryViewReference, - InventoryViewsStaticConfig, - ResolvedInventoryView, -} from '../../../common/inventory_views'; + CreateInventoryViewAttributesRequestPayload, + InventoryViewRequestQuery, + UpdateInventoryViewAttributesRequestPayload, +} from '../../../common/http_api/latest'; +import { InventoryView } from '../../../common/inventory_views'; import { InfraSources } from '../../lib/sources'; export interface InventoryViewsServiceStartDeps { - config: InventoryViewsStaticConfig; - dataViews: DataViewsServerPluginStart; - elasticsearch: ElasticsearchServiceStart; infraSources: InfraSources; savedObjects: SavedObjectsServiceStart; } @@ -33,20 +26,20 @@ export interface InventoryViewsServiceStartDeps { export type InventoryViewsServiceSetup = void; export interface InventoryViewsServiceStart { - getClient( - savedObjectsClient: SavedObjectsClientContract, - elasticsearchClient: ElasticsearchClient, - request?: KibanaRequest - ): IInventoryViewsClient; + getClient(savedObjectsClient: SavedObjectsClientContract): IInventoryViewsClient; getScopedClient(request: KibanaRequest): IInventoryViewsClient; } export interface IInventoryViewsClient { - findInventoryView(inventoryViewId: string): Promise; - getInventoryView(inventoryViewId: string): Promise; - putInventoryView( + delete(inventoryViewId: string): Promise<{}>; + find(query: InventoryViewRequestQuery): Promise; + get(inventoryViewId: string, query: InventoryViewRequestQuery): Promise; + create( + inventoryViewAttributes: CreateInventoryViewAttributesRequestPayload + ): Promise; + update( inventoryViewId: string, - inventoryViewAttributes: Partial + inventoryViewAttributes: UpdateInventoryViewAttributesRequestPayload, + query: InventoryViewRequestQuery ): Promise; - deleteInventoryView(inventoryViewId: string): Promise; } diff --git a/x-pack/plugins/infra/server/types.ts b/x-pack/plugins/infra/server/types.ts index 108575c0f8324..c415103d2256d 100644 --- a/x-pack/plugins/infra/server/types.ts +++ b/x-pack/plugins/infra/server/types.ts @@ -14,6 +14,7 @@ import type { SearchRequestHandlerContext } from '@kbn/data-plugin/server'; import type { MlPluginSetup } from '@kbn/ml-plugin/server'; import type { InfraStaticSourceConfiguration } from '../common/source_configuration/source_configuration'; import { InfraServerPluginStartDeps } from './lib/adapters/framework'; +import { InventoryViewsServiceStart } from './services/inventory_views'; import { LogViewsServiceSetup, LogViewsServiceStart } from './services/log_views/types'; export type { InfraConfig } from '../common/plugin_config_types'; @@ -30,6 +31,7 @@ export interface InfraPluginSetup { } export interface InfraPluginStart { + inventoryViews: InventoryViewsServiceStart; logViews: LogViewsServiceStart; getMetricIndices: ( savedObjectsClient: SavedObjectsClientContract, From 6df39b13bce9dcfce095aa665d006002a048898f Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 13 Apr 2023 10:36:16 +0000 Subject: [PATCH 06/20] [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' --- .../server/services/inventory_views/inventory_views_client.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts index 4aec4a3273661..60cf58bbfd068 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts @@ -5,13 +5,10 @@ * 2.0. */ -import type { PluginStart as DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; import { Logger, SavedObject, SavedObjectsClientContract, - SavedObjectsFindResponse, - SavedObjectsFindResult, SavedObjectsUpdateResponse, } from '@kbn/core/server'; import Boom from '@hapi/boom'; From a6d9262bfaa6d4f67aab645df953312227b8e048 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Thu, 13 Apr 2023 12:37:15 +0200 Subject: [PATCH 07/20] fix(infra): update saved object runtime type --- .../infra/server/saved_objects/inventory_view/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/infra/server/saved_objects/inventory_view/types.ts b/x-pack/plugins/infra/server/saved_objects/inventory_view/types.ts index 083bac3e1f683..45e738f3920f1 100644 --- a/x-pack/plugins/infra/server/saved_objects/inventory_view/types.ts +++ b/x-pack/plugins/infra/server/saved_objects/inventory_view/types.ts @@ -5,12 +5,12 @@ * 2.0. */ -import { isoToEpochRt } from '@kbn/io-ts-utils'; +import { isoToEpochRt, nonEmptyStringRt } from '@kbn/io-ts-utils'; import * as rt from 'io-ts'; export const inventoryViewSavedObjectAttributesRT = rt.intersection([ rt.strict({ - name: rt.string, + name: nonEmptyStringRt, }), rt.UnknownRecord, ]); From 70a6f5f6173b14361fd7ed065833de11c34e7195 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Thu, 13 Apr 2023 13:52:05 +0200 Subject: [PATCH 08/20] feat(infra): add static view --- .../inventory_views/inventory_views_client.ts | 65 ++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts index 60cf58bbfd068..1419ad6bcac96 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts @@ -12,6 +12,7 @@ import { SavedObjectsUpdateResponse, } from '@kbn/core/server'; import Boom from '@hapi/boom'; +import { i18n } from '@kbn/i18n'; import { CreateInventoryViewAttributesRequestPayload, InventoryViewRequestQuery, @@ -30,6 +31,8 @@ export class InventoryViewsClient implements IInventoryViewsClient { private readonly infraSources: IInfraSources ) {} + static STATIC_VIEW_ID = 'static'; + public async find(query: InventoryViewRequestQuery): Promise { this.logger.debug('Trying to load inventory views ...'); @@ -43,12 +46,17 @@ export class InventoryViewsClient implements IInventoryViewsClient { }), ]); - return inventoryViewSavedObject.saved_objects.map((savedObject) => + const defaultView = this.createStaticView( + sourceConfiguration.configuration.inventoryDefaultView + ); + const views = inventoryViewSavedObject.saved_objects.map((savedObject) => this.mapSavedObjectToInventoryView( savedObject, sourceConfiguration.configuration.inventoryDefaultView ) ); + + return [defaultView, ...views]; } public async get( @@ -59,6 +67,16 @@ export class InventoryViewsClient implements IInventoryViewsClient { const sourceId = query.sourceId ?? 'default'; + // Handle the case where the requested resource is the static inventory view + if (inventoryViewId === InventoryViewsClient.STATIC_VIEW_ID) { + const sourceConfiguration = await this.infraSources.getSourceConfiguration( + this.savedObjectsClient, + sourceId + ); + + return this.createStaticView(sourceConfiguration.configuration.inventoryDefaultView); + } + const [sourceConfiguration, inventoryViewSavedObject] = await Promise.all([ this.infraSources.getSourceConfiguration(this.savedObjectsClient, sourceId), this.savedObjectsClient.get(inventoryViewSavedObjectName, inventoryViewId), @@ -141,7 +159,7 @@ export class InventoryViewsClient implements IInventoryViewsClient { perPage: 1000, }); - const hasConflict = results.saved_objects.some( + const hasConflict = [this.createStaticView(), ...results.saved_objects].some( (obj) => !whitelist.includes(obj.id) && obj.attributes.name === name ); @@ -149,4 +167,47 @@ export class InventoryViewsClient implements IInventoryViewsClient { throw Boom.conflict('A view with that name already exists.'); } } + + private createStaticView = (defaultViewId?: string): InventoryView => ({ + id: InventoryViewsClient.STATIC_VIEW_ID, + attributes: { + name: i18n.translate('xpack.infra.savedView.defaultViewNameHosts', { + defaultMessage: 'Default view', + }), + isDefault: defaultViewId === InventoryViewsClient.STATIC_VIEW_ID, + isStatic: true, + metric: { + type: 'cpu', + }, + groupBy: [], + nodeType: 'host', + view: 'map', + customOptions: [], + boundsOverride: { + max: 1, + min: 0, + }, + autoBounds: true, + accountId: '', + region: '', + customMetrics: [], + legend: { + palette: 'cool', + steps: 10, + reverseColors: false, + }, + source: 'default', + sort: { + by: 'name', + direction: 'desc', + }, + timelineOpen: false, + filterQuery: { + kind: 'kuery', + expression: '', + }, + time: Date.now(), + autoReload: false, + }, + }); } From e71d8683d756bddb0bbf0604754e19292e831f21 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Thu, 13 Apr 2023 17:39:16 +0200 Subject: [PATCH 09/20] docs(infra): add doc about endpoints --- .../http_api/inventory_views/v1/common.ts | 1 + .../inventory_views/v1/find_inventory_view.ts | 1 + .../infra/common/inventory_views/types.ts | 1 + .../server/routes/inventory_views/README.md | 348 ++++++++++++++++++ .../inventory_views/create_inventory_view.ts | 3 +- .../inventory_views/inventory_views_client.ts | 1 + 6 files changed, 354 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/infra/server/routes/inventory_views/README.md diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts index 190e26588b4a0..37911135711c2 100644 --- a/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts @@ -28,6 +28,7 @@ const inventoryViewAttributesResponseRT = rt.intersection([ rt.strict({ name: nonEmptyStringRt, isDefault: rt.boolean, + isStatic: rt.boolean, }), rt.UnknownRecord, ]); diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/find_inventory_view.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/find_inventory_view.ts index 56c6b989bb734..24812ccb43585 100644 --- a/x-pack/plugins/infra/common/http_api/inventory_views/v1/find_inventory_view.ts +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/find_inventory_view.ts @@ -11,6 +11,7 @@ import * as rt from 'io-ts'; export const findInventoryViewAttributesResponseRT = rt.strict({ name: nonEmptyStringRt, isDefault: rt.boolean, + isStatic: rt.boolean, }); const findInventoryViewResponseRT = rt.exact( diff --git a/x-pack/plugins/infra/common/inventory_views/types.ts b/x-pack/plugins/infra/common/inventory_views/types.ts index 99881bd3cf452..49979c1063efa 100644 --- a/x-pack/plugins/infra/common/inventory_views/types.ts +++ b/x-pack/plugins/infra/common/inventory_views/types.ts @@ -12,6 +12,7 @@ export const inventoryViewAttributesRT = rt.intersection([ rt.strict({ name: nonEmptyStringRt, isDefault: rt.boolean, + isStatic: rt.boolean, }), rt.UnknownRecord, ]); diff --git a/x-pack/plugins/infra/server/routes/inventory_views/README.md b/x-pack/plugins/infra/server/routes/inventory_views/README.md new file mode 100644 index 0000000000000..701d768a36b75 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/inventory_views/README.md @@ -0,0 +1,348 @@ +# Inventory Views CRUD api + +## Find all: `GET /api/infra/inventory_views` + +Retrieves all inventory views in a reduced version. + +### Request + +- **Method**: GET +- **Path**: /api/infra/inventory_views +- **Query params**: + - `sourceId` _(optional)_: Specify a source id related to the inventory views. Default value: `default`. + +### Response + +```json +GET /api/infra/inventory_views + +Status code: 200 + +{ + "data": [ + { + "id": "static", + "attributes": { + "name": "Default view", + "isDefault": false, + "isStatic": true + } + }, + { + "id": "927ad6a0-da0c-11ed-9487-41e9b90f96b9", + "version": "WzQwMiwxXQ==", + "updatedAt": 1681398305034, + "attributes": { + "name": "Ad-hoc", + "isDefault": true, + "isStatic": false + } + }, + { + "id": "c301ef20-da0c-11ed-aac0-77131228e6f1", + "version": "WzQxMCwxXQ==", + "updatedAt": 1681398386450, + "attributes": { + "name": "Custom", + "isDefault": false, + "isStatic": false + } + } + ] +} +``` + +## Get one: `GET /api/infra/inventory_views/{inventoryViewId}` + +Retrieves a single inventory view by ID + +### Request + +- **Method**: GET +- **Path**: /api/infra/inventory_views/{inventoryViewId} +- **Query params**: + - `sourceId` _(optional)_: Specify a source id related to the inventory view. Default value: `default`. + +### Response + +```json +GET /api/infra/inventory_views/927ad6a0-da0c-11ed-9487-41e9b90f96b9 + +Status code: 200 + +{ + "data": { + "id": "927ad6a0-da0c-11ed-9487-41e9b90f96b9", + "version": "WzQwMiwxXQ==", + "updatedAt": 1681398305034, + "attributes": { + "name": "Ad-hoc", + "isDefault": true, + "isStatic": false, + "metric": { + "type": "cpu" + }, + "sort": { + "by": "name", + "direction": "desc" + }, + "groupBy": [], + "nodeType": "host", + "view": "map", + "customOptions": [], + "customMetrics": [], + "boundsOverride": { + "max": 1, + "min": 0 + }, + "autoBounds": true, + "accountId": "", + "region": "", + "autoReload": false, + "filterQuery": { + "expression": "", + "kind": "kuery" + }, + "legend": { + "palette": "cool", + "reverseColors": false, + "steps": 10 + }, + "timelineOpen": false + } + } +} +``` + +```json +GET /api/infra/inventory_views/random-id + +Status code: 404 + +{ + "statusCode": 404, + "error": "Not Found", + "message": "Saved object [inventory-view/random-id] not found" +} +``` + +## Create one: `POST /api/infra/inventory_views` + +Creates a new inventory view. + +### Request + +- **Method**: POST +- **Path**: /api/infra/inventory_views +- **Request body**: + ```json + { + "attributes": { + "name": "View name", + "metric": { + "type": "cpu" + }, + "sort": { + "by": "name", + "direction": "desc" + }, + //... + } + } + ``` + +### Response + +```json +POST /api/infra/inventory_views + +Status code: 201 + +{ + "data": { + "id": "927ad6a0-da0c-11ed-9487-41e9b90f96b9", + "version": "WzQwMiwxXQ==", + "updatedAt": 1681398305034, + "attributes": { + "name": "View name", + "isDefault": false, + "isStatic": false, + "metric": { + "type": "cpu" + }, + "sort": { + "by": "name", + "direction": "desc" + }, + "groupBy": [], + "nodeType": "host", + "view": "map", + "customOptions": [], + "customMetrics": [], + "boundsOverride": { + "max": 1, + "min": 0 + }, + "autoBounds": true, + "accountId": "", + "region": "", + "autoReload": false, + "filterQuery": { + "expression": "", + "kind": "kuery" + }, + "legend": { + "palette": "cool", + "reverseColors": false, + "steps": 10 + }, + "timelineOpen": false + } + } +} +``` + +Send in the payload a `name` attribute already held by another view: +```json +POST /api/infra/inventory_views + +Status code: 409 + +{ + "statusCode": 409, + "error": "Conflict", + "message": "A view with that name already exists." +} +``` + +## Update one: `PUT /api/infra/inventory_views/{inventoryViewId}` + +Updates an inventory view. + +### Request + +- **Method**: PUT +- **Path**: /api/infra/inventory_views/{inventoryViewId} +- **Query params**: + - `sourceId` _(optional)_: Specify a source id related to the inventory view. Default value: `default`. +- **Request body**: + ```json + { + "attributes": { + "name": "View name", + "metric": { + "type": "cpu" + }, + "sort": { + "by": "name", + "direction": "desc" + }, + //... + } + } + ``` + +### Response + +```json +PUT /api/infra/inventory_views/927ad6a0-da0c-11ed-9487-41e9b90f96b9 + +Status code: 200 + +{ + "data": { + "id": "927ad6a0-da0c-11ed-9487-41e9b90f96b9", + "version": "WzQwMiwxXQ==", + "updatedAt": 1681398305034, + "attributes": { + "name": "View name", + "isDefault": false, + "isStatic": false, + "metric": { + "type": "cpu" + }, + "sort": { + "by": "name", + "direction": "desc" + }, + "groupBy": [], + "nodeType": "host", + "view": "map", + "customOptions": [], + "customMetrics": [], + "boundsOverride": { + "max": 1, + "min": 0 + }, + "autoBounds": true, + "accountId": "", + "region": "", + "autoReload": false, + "filterQuery": { + "expression": "", + "kind": "kuery" + }, + "legend": { + "palette": "cool", + "reverseColors": false, + "steps": 10 + }, + "timelineOpen": false + } + } +} +``` + +```json +PUT /api/infra/inventory_views/random-id + +Status code: 404 + +{ + "statusCode": 404, + "error": "Not Found", + "message": "Saved object [inventory-view/random-id] not found" +} +``` + +Send in the payload a `name` attribute already held by another view: +```json +PUT /api/infra/inventory_views/927ad6a0-da0c-11ed-9487-41e9b90f96b9 + +Status code: 409 + +{ + "statusCode": 409, + "error": "Conflict", + "message": "A view with that name already exists." +} +``` + +## Delete one: `DELETE /api/infra/inventory_views/{inventoryViewId}` + +Deletes an inventory view. + +### Request + +- **Method**: DELETE +- **Path**: /api/infra/inventory_views/{inventoryViewId} + +### Response + +```json +DELETE /api/infra/inventory_views/927ad6a0-da0c-11ed-9487-41e9b90f96b9 + +Status code: 204 No content +``` + +```json +DELETE /api/infra/inventory_views/random-id + +Status code: 404 + +{ + "statusCode": 404, + "error": "Not Found", + "message": "Saved object [inventory-view/random-id] not found" +} +``` diff --git a/x-pack/plugins/infra/server/routes/inventory_views/create_inventory_view.ts b/x-pack/plugins/infra/server/routes/inventory_views/create_inventory_view.ts index c3e7a03acec5e..8f3d52db7a6dd 100644 --- a/x-pack/plugins/infra/server/routes/inventory_views/create_inventory_view.ts +++ b/x-pack/plugins/infra/server/routes/inventory_views/create_inventory_view.ts @@ -34,7 +34,8 @@ export const initCreateInventoryViewRoute = ({ try { const inventoryView = await inventoryViewsClient.create(body.attributes); - return response.ok({ + return response.custom({ + statusCode: 201, body: inventoryViewResponsePayloadRT.encode({ data: inventoryView }), }); } catch (error) { diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts index 1419ad6bcac96..c5a88b20f7a08 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts @@ -146,6 +146,7 @@ export class InventoryViewsClient implements IInventoryViewsClient { attributes: { ...inventoryViewSavedObject.attributes, isDefault: inventoryViewSavedObject.id === defaultViewId, + isStatic: false, }, }; } From d21947a26d43c9a9bb295e4977906ca8c62e56b4 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Mon, 17 Apr 2023 10:07:08 +0200 Subject: [PATCH 10/20] refactor(infra): restore legacy saved view files until client is refactored --- .../common/saved_objects/inventory_view.ts | 23 +++++++++++++++++++ .../saved_objects/metrics_explorer_view.ts | 23 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 x-pack/plugins/infra/common/saved_objects/inventory_view.ts create mode 100644 x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts diff --git a/x-pack/plugins/infra/common/saved_objects/inventory_view.ts b/x-pack/plugins/infra/common/saved_objects/inventory_view.ts new file mode 100644 index 0000000000000..7e935086cb08a --- /dev/null +++ b/x-pack/plugins/infra/common/saved_objects/inventory_view.ts @@ -0,0 +1,23 @@ +/* + * 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 type { SavedObjectsType } from '@kbn/core/server'; + +export const inventoryViewSavedObjectName = 'inventory-view'; + +export const inventoryViewSavedObjectType: SavedObjectsType = { + name: inventoryViewSavedObjectName, + hidden: false, + namespaceType: 'single', + management: { + importableAndExportable: true, + }, + mappings: { + dynamic: false, + properties: {}, + }, +}; diff --git a/x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts b/x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts new file mode 100644 index 0000000000000..7f7ca7a932203 --- /dev/null +++ b/x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts @@ -0,0 +1,23 @@ +/* + * 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 type { SavedObjectsType } from '@kbn/core/server'; + +export const metricsExplorerViewSavedObjectName = 'metrics-explorer-view'; + +export const metricsExplorerViewSavedObjectType: SavedObjectsType = { + name: metricsExplorerViewSavedObjectName, + hidden: false, + namespaceType: 'single', + management: { + importableAndExportable: true, + }, + mappings: { + dynamic: false, + properties: {}, + }, +}; From 85881d3a2d8d9bf998e476d2c4559c1f9dcd29e9 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Mon, 17 Apr 2023 12:53:49 +0200 Subject: [PATCH 11/20] tests(infra): add inventoryViews test --- packages/kbn-io-ts-utils/index.ts | 2 +- .../infra/common/inventory_views/defaults.ts | 52 ++ .../inventory_views/inventory_view.mock.ts | 24 + x-pack/plugins/infra/server/mocks.ts | 2 + .../inventory_views_client.test.ts | 518 ++++++------------ .../inventory_views/inventory_views_client.ts | 56 +- 6 files changed, 260 insertions(+), 394 deletions(-) create mode 100644 x-pack/plugins/infra/common/inventory_views/defaults.ts create mode 100644 x-pack/plugins/infra/common/inventory_views/inventory_view.mock.ts diff --git a/packages/kbn-io-ts-utils/index.ts b/packages/kbn-io-ts-utils/index.ts index 4e3eaeb9af92b..a79adae375805 100644 --- a/packages/kbn-io-ts-utils/index.ts +++ b/packages/kbn-io-ts-utils/index.ts @@ -7,7 +7,7 @@ */ export type { IndexPatternType } from './src/index_pattern_rt'; -export type { NonEmptyStringBrand } from './src/non_empty_string_rt'; +export type { NonEmptyString, NonEmptyStringBrand } from './src/non_empty_string_rt'; export { deepExactRt } from './src/deep_exact_rt'; export { indexPatternRt } from './src/index_pattern_rt'; diff --git a/x-pack/plugins/infra/common/inventory_views/defaults.ts b/x-pack/plugins/infra/common/inventory_views/defaults.ts new file mode 100644 index 0000000000000..fa19b01193c74 --- /dev/null +++ b/x-pack/plugins/infra/common/inventory_views/defaults.ts @@ -0,0 +1,52 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { NonEmptyString } from '@kbn/io-ts-utils'; +import { InventoryViewAttributes } from './types'; + +export const staticInventoryViewId = 'static'; + +export const staticInventoryViewAttributes: InventoryViewAttributes = { + name: i18n.translate('xpack.infra.savedView.defaultViewNameHosts', { + defaultMessage: 'Default view', + }) as NonEmptyString, + isDefault: false, + isStatic: true, + metric: { + type: 'cpu', + }, + groupBy: [], + nodeType: 'host', + view: 'map', + customOptions: [], + boundsOverride: { + max: 1, + min: 0, + }, + autoBounds: true, + accountId: '', + region: '', + customMetrics: [], + legend: { + palette: 'cool', + steps: 10, + reverseColors: false, + }, + source: 'default', + sort: { + by: 'name', + direction: 'desc', + }, + timelineOpen: false, + filterQuery: { + kind: 'kuery', + expression: '', + }, + time: Date.now(), + autoReload: false, +}; diff --git a/x-pack/plugins/infra/common/inventory_views/inventory_view.mock.ts b/x-pack/plugins/infra/common/inventory_views/inventory_view.mock.ts new file mode 100644 index 0000000000000..0b5e952053035 --- /dev/null +++ b/x-pack/plugins/infra/common/inventory_views/inventory_view.mock.ts @@ -0,0 +1,24 @@ +/* + * 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 { staticInventoryViewAttributes } from './defaults'; +import { InventoryView, InventoryViewAttributes } from './types'; + +export const createInventoryViewMock = ( + id: string, + attributes: InventoryViewAttributes, + updatedAt?: number, + version?: string +): InventoryView => ({ + id, + attributes: { + ...staticInventoryViewAttributes, + ...attributes, + }, + updatedAt, + version, +}); diff --git a/x-pack/plugins/infra/server/mocks.ts b/x-pack/plugins/infra/server/mocks.ts index 5b587a1fe80d5..5a97f4a7d9a52 100644 --- a/x-pack/plugins/infra/server/mocks.ts +++ b/x-pack/plugins/infra/server/mocks.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { createInventoryViewsServiceStartMock } from './services/inventory_views/inventory_views_service.mock'; import { createLogViewsServiceSetupMock, createLogViewsServiceStartMock, @@ -23,6 +24,7 @@ const createInfraSetupMock = () => { const createInfraStartMock = () => { const infraStartMock: jest.Mocked = { getMetricIndices: jest.fn(), + inventoryViews: createInventoryViewsServiceStartMock(), logViews: createLogViewsServiceStartMock(), }; return infraStartMock; diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts index 03fbd042f6730..7ae01af1e6267 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts @@ -5,407 +5,225 @@ * 2.0. */ -import { LoggerMock } from '@kbn/logging-mocks'; -import { SavedObject, SavedObjectsUtils } from '@kbn/core/server'; +import { loggerMock } from '@kbn/logging-mocks'; +import { SavedObjectsClientContract } from '@kbn/core/server'; import { savedObjectsClientMock } from '@kbn/core/server/mocks'; -import { createStubDataView } from '@kbn/data-views-plugin/common/stubs'; -import { dataViewsService as dataViewsServiceMock } from '@kbn/data-views-plugin/server/mocks'; -import { - defaultInventoryViewId, - InventoryView, - InventoryViewAttributes, - InventoryViewsStaticConfig, -} from '../../../common/inventory_views'; -import { createInventoryViewMock } from '../../../common/inventory_views/inventory_view.mock'; +import { InventoryViewAttributes } from '../../../common/inventory_views'; + import { InfraSource } from '../../lib/sources'; import { createInfraSourcesMock } from '../../lib/sources/mocks'; -import { - extractInventoryViewSavedObjectReferences, - inventoryViewSavedObjectName, -} from '../../saved_objects/inventory_view'; -import { - getAttributesFromSourceConfiguration, - InventoryViewsClient, -} from './inventory_views_client'; - -describe('getAttributesFromSourceConfiguration function', () => { - it('converts the index_pattern Inventory indices type to data_view', () => { - const inventoryViewAttributes = getAttributesFromSourceConfiguration( - basicTestSourceConfiguration - ); - - expect(inventoryViewAttributes.InventoryIndices).toEqual({ - type: 'data_view', - dataViewId: 'INDEX_PATTERN_ID', - }); - }); +import { inventoryViewSavedObjectName } from '../../saved_objects/inventory_view'; +import { InventoryViewsClient } from './inventory_views_client'; +import { createInventoryViewMock } from '../../../common/inventory_views/inventory_view.mock'; - it('preserves the index_name Inventory indices type', () => { - const inventoryViewAttributes = getAttributesFromSourceConfiguration({ - ...basicTestSourceConfiguration, - configuration: { - ...basicTestSourceConfiguration.configuration, - InventoryIndices: { - type: 'index_name', - indexName: 'INDEX_NAME', - }, - }, - }); +describe('InventoryViewsClient class', () => { + const mockFindInventoryList = (savedObjectsClient: jest.Mocked) => { + const inventoryViewListMock = [ + createInventoryViewMock('static', { + isDefault: true, + } as InventoryViewAttributes), + createInventoryViewMock('default_id', { + name: 'Default view 2', + isStatic: false, + } as InventoryViewAttributes), + createInventoryViewMock('custom_id', { + name: 'Custom', + isStatic: false, + } as InventoryViewAttributes), + ]; - expect(inventoryViewAttributes.InventoryIndices).toEqual({ - type: 'index_name', - indexName: 'INDEX_NAME', + savedObjectsClient.find.mockResolvedValue({ + total: 2, + saved_objects: inventoryViewListMock.slice(1).map((view) => ({ + ...view, + type: inventoryViewSavedObjectName, + score: 0, + references: [], + })), + per_page: 1000, + page: 1, }); - }); -}); -describe('InventoryViewsClient class', () => { - it('getInventoryView resolves the default id to a real saved object id if it exists', async () => { - const { inventoryViewsClient, savedObjectsClient } = createInventoryViewsClient(); + return inventoryViewListMock; + }; - const inventoryViewMock = createInventoryViewMock('SAVED_OBJECT_ID'); - const inventoryViewSavedObject: SavedObject = { - ...extractInventoryViewSavedObjectReferences(inventoryViewMock.attributes), - id: inventoryViewMock.id, - type: inventoryViewSavedObjectName, - }; + describe('.find', () => { + it('resolves the list of existing inventory views', async () => { + const { inventoryViewsClient, infraSources, savedObjectsClient } = + createInventoryViewsClient(); - savedObjectsClient.get.mockResolvedValue(inventoryViewSavedObject); + infraSources.getSourceConfiguration.mockResolvedValue(basicTestSourceConfiguration); - savedObjectsClient.find.mockResolvedValue({ - total: 1, - saved_objects: [ - { - score: 0, - ...inventoryViewSavedObject, - }, - ], - per_page: 1, - page: 1, + const inventoryViewListMock = mockFindInventoryList(savedObjectsClient); + + const inventoryViewList = await inventoryViewsClient.find({}); + + expect(savedObjectsClient.find).toHaveBeenCalled(); + expect(inventoryViewList).toEqual(inventoryViewListMock); }); - const inventoryView = await inventoryViewsClient.getInventoryView(defaultInventoryViewId); + it('always resolves at least the static inventory view', async () => { + const { inventoryViewsClient, infraSources, savedObjectsClient } = + createInventoryViewsClient(); - expect(savedObjectsClient.get).toHaveBeenCalledWith( - inventoryViewSavedObjectName, - 'SAVED_OBJECT_ID' - ); - expect(inventoryView).toEqual(inventoryViewMock); + const inventoryViewListMock = [ + createInventoryViewMock('static', { + isDefault: true, + } as InventoryViewAttributes), + ]; + + infraSources.getSourceConfiguration.mockResolvedValue(basicTestSourceConfiguration); + + savedObjectsClient.find.mockResolvedValue({ + total: 2, + saved_objects: [], + per_page: 1000, + page: 1, + }); + + const inventoryViewList = await inventoryViewsClient.find({}); + + expect(savedObjectsClient.find).toHaveBeenCalled(); + expect(inventoryViewList).toEqual(inventoryViewListMock); + }); }); - it('getInventoryView preserves non-default ids', async () => { - const { inventoryViewsClient, savedObjectsClient } = createInventoryViewsClient(); + it('.get resolves the an inventory view by id', async () => { + const { inventoryViewsClient, infraSources, savedObjectsClient } = createInventoryViewsClient(); - const inventoryViewMock = createInventoryViewMock('SAVED_OBJECT_ID'); - const inventoryViewSavedObject: SavedObject = { - ...extractInventoryViewSavedObjectReferences(inventoryViewMock.attributes), - id: inventoryViewMock.id, - type: inventoryViewSavedObjectName, - }; + const inventoryViewMock = createInventoryViewMock('custom_id', { + name: 'Custom', + isDefault: false, + isStatic: false, + } as InventoryViewAttributes); - savedObjectsClient.get.mockResolvedValue(inventoryViewSavedObject); + infraSources.getSourceConfiguration.mockResolvedValue(basicTestSourceConfiguration); - savedObjectsClient.find.mockResolvedValue({ - total: 1, - saved_objects: [ - { - score: 0, - ...inventoryViewSavedObject, - }, - ], - per_page: 1, - page: 1, + savedObjectsClient.get.mockResolvedValue({ + ...inventoryViewMock, + type: inventoryViewSavedObjectName, + references: [], }); - const inventoryView = await inventoryViewsClient.getInventoryView('SAVED_OBJECT_ID'); + const inventoryView = await inventoryViewsClient.get('custom_id', {}); - expect(savedObjectsClient.get).toHaveBeenCalledWith( - inventoryViewSavedObjectName, - 'SAVED_OBJECT_ID' - ); + expect(savedObjectsClient.get).toHaveBeenCalled(); expect(inventoryView).toEqual(inventoryViewMock); }); - it('getInventoryView preserves the default id for fallback lookups', async () => { - const { infraSources, inventoryViewsClient, savedObjectsClient } = createInventoryViewsClient(); + describe('.create', () => { + it('generate a new inventory view', async () => { + const { inventoryViewsClient, savedObjectsClient } = createInventoryViewsClient(); - infraSources.getSourceConfiguration.mockResolvedValue(basicTestSourceConfiguration); + const inventoryViewMock = createInventoryViewMock('new_id', { + name: 'New view', + isStatic: false, + } as InventoryViewAttributes); - savedObjectsClient.find.mockResolvedValue({ - total: 0, - saved_objects: [], - per_page: 0, - page: 1, + mockFindInventoryList(savedObjectsClient); + + savedObjectsClient.create.mockResolvedValue({ + ...inventoryViewMock, + type: inventoryViewSavedObjectName, + references: [], + }); + + const inventoryView = await inventoryViewsClient.create({ + name: 'New view', + } as InventoryViewAttributes); + + expect(savedObjectsClient.create).toHaveBeenCalled(); + expect(inventoryView).toEqual(inventoryViewMock); }); - await inventoryViewsClient.getInventoryView(defaultInventoryViewId); + it('throws an error when a conflicting name is given', async () => { + const { inventoryViewsClient, savedObjectsClient } = createInventoryViewsClient(); - expect(infraSources.getSourceConfiguration).toHaveBeenCalledWith( - savedObjectsClient, - defaultInventoryViewId - ); + mockFindInventoryList(savedObjectsClient); + + await expect( + async () => + await inventoryViewsClient.create({ + name: 'Custom', + } as InventoryViewAttributes) + ).rejects.toThrow('A view with that name already exists.'); + }); }); - it('putInventoryView resolves the default id to a real saved object id if one exists', async () => { - const { inventoryViewsClient, savedObjectsClient } = createInventoryViewsClient(); + describe('.update', () => { + it('update an existing inventory view by id', async () => { + const { inventoryViewsClient, infraSources, savedObjectsClient } = + createInventoryViewsClient(); - const existingInventoryViewMock = createInventoryViewMock('SAVED_OBJECT_ID'); - const existingInventoryViewSavedObject: SavedObject = { - ...extractInventoryViewSavedObjectReferences(existingInventoryViewMock.attributes), - id: existingInventoryViewMock.id, - type: inventoryViewSavedObjectName, - }; + const inventoryViews = mockFindInventoryList(savedObjectsClient); - const newInventoryViewMock = createInventoryViewMock('SAVED_OBJECT_ID', 'stored', { - name: 'New Log View', - }); - const newInventoryViewSavedObject: SavedObject = { - ...extractInventoryViewSavedObjectReferences(newInventoryViewMock.attributes), - id: newInventoryViewMock.id, - type: inventoryViewSavedObjectName, - }; + const inventoryViewMock = { + ...inventoryViews[1], + attributes: { + ...inventoryViews[1].attributes, + name: 'New name', + }, + }; - savedObjectsClient.create.mockResolvedValue(newInventoryViewSavedObject); + infraSources.getSourceConfiguration.mockResolvedValue(basicTestSourceConfiguration); - savedObjectsClient.find.mockResolvedValue({ - total: 1, - saved_objects: [ + savedObjectsClient.update.mockResolvedValue({ + ...inventoryViewMock, + type: inventoryViewSavedObjectName, + references: [], + }); + + const inventoryView = await inventoryViewsClient.update( + 'default_id', { - score: 0, - ...existingInventoryViewSavedObject, - }, - ], - per_page: 1, - page: 1, + name: 'New name', + } as InventoryViewAttributes, + {} + ); + + expect(savedObjectsClient.update).toHaveBeenCalled(); + expect(inventoryView).toEqual(inventoryViewMock); }); - const inventoryView = await inventoryViewsClient.putInventoryView( - defaultInventoryViewId, - newInventoryViewMock.attributes - ); - - expect(savedObjectsClient.create).toHaveBeenCalledWith( - inventoryViewSavedObjectName, - newInventoryViewMock.attributes, - expect.objectContaining({ id: 'SAVED_OBJECT_ID' }) - ); - expect(inventoryView).toEqual(newInventoryViewMock); + it('throws an error when a conflicting name is given', async () => { + const { inventoryViewsClient, savedObjectsClient } = createInventoryViewsClient(); + + mockFindInventoryList(savedObjectsClient); + + await expect( + async () => + await inventoryViewsClient.update( + 'default_id', + { + name: 'Custom', + } as InventoryViewAttributes, + {} + ) + ).rejects.toThrow('A view with that name already exists.'); + }); }); - it('putInventoryView resolves the default id to a new uuid if no default exists', async () => { + it('.delete removes an inventory view by id', async () => { const { inventoryViewsClient, savedObjectsClient } = createInventoryViewsClient(); - const newInventoryViewMock = createInventoryViewMock('NOT_THE_FINAL_ID', 'stored', { - name: 'New Log View', - }); - const newInventoryViewSavedObject: SavedObject = { - ...extractInventoryViewSavedObjectReferences(newInventoryViewMock.attributes), - id: newInventoryViewMock.id, - type: inventoryViewSavedObjectName, - }; + savedObjectsClient.delete.mockResolvedValue({}); - savedObjectsClient.create.mockImplementation(async (_type, _attributes, { id = '' } = {}) => ({ - ...newInventoryViewSavedObject, - id, - })); + const inventoryView = await inventoryViewsClient.delete('custom_id'); - savedObjectsClient.find.mockResolvedValue({ - total: 0, - saved_objects: [], - per_page: 0, - page: 1, - }); - - const inventoryView = await inventoryViewsClient.putInventoryView( - defaultInventoryViewId, - newInventoryViewMock.attributes - ); - - expect(savedObjectsClient.create).toHaveBeenCalledWith( - inventoryViewSavedObjectName, - newInventoryViewMock.attributes, - expect.objectContaining({ - id: expect.any(String), // the id was generated - }) - ); - expect(inventoryView).toEqual( - expect.objectContaining({ - ...newInventoryViewMock, - id: expect.any(String), // the id was generated - }) - ); - expect(SavedObjectsUtils.isRandomId(inventoryView.id)).toBeTruthy(); - }); - - it('resolveInventoryView method resolves given InventoryViewAttributes with DataView reference', async () => { - const { inventoryViewsClient, dataViews } = createInventoryViewsClient(); - - dataViews.get.mockResolvedValue( - createStubDataView({ - spec: { - id: 'LOG_DATA_VIEW', - title: 'Inventory-indices-*', - timeFieldName: '@timestamp', - runtimeFieldMap: { - runtime_field: { - type: 'keyword', - script: { - source: 'emit("runtime value")', - }, - }, - }, - }, - }) - ); - - const resolvedInventoryView = await inventoryViewsClient.resolveInventoryView( - 'Inventory-view-id', - { - name: 'LOG VIEW', - description: 'LOG VIEW DESCRIPTION', - InventoryIndices: { - type: 'data_view', - dataViewId: 'LOG_DATA_VIEW', - }, - InventoryColumns: [ - { timestampColumn: { id: 'TIMESTAMP_COLUMN_ID' } }, - { - fieldColumn: { - id: 'DATASET_COLUMN_ID', - field: 'event.dataset', - }, - }, - { - messageColumn: { id: 'MESSAGE_COLUMN_ID' }, - }, - ], - } - ); - - expect(resolvedInventoryView).toMatchInlineSnapshot(` - Object { - "columns": Array [ - Object { - "timestampColumn": Object { - "id": "TIMESTAMP_COLUMN_ID", - }, - }, - Object { - "fieldColumn": Object { - "field": "event.dataset", - "id": "DATASET_COLUMN_ID", - }, - }, - Object { - "messageColumn": Object { - "id": "MESSAGE_COLUMN_ID", - }, - }, - ], - "dataViewReference": DataView { - "allowNoIndex": false, - "deleteFieldFormat": [Function], - "fieldAttrs": Object {}, - "fieldFormatMap": Object {}, - "fieldFormats": Object { - "deserialize": [MockFunction], - "getByFieldType": [MockFunction], - "getDefaultConfig": [MockFunction], - "getDefaultInstance": [MockFunction], - "getDefaultInstanceCacheResolver": [MockFunction], - "getDefaultInstancePlain": [MockFunction], - "getDefaultType": [MockFunction], - "getDefaultTypeName": [MockFunction], - "getInstance": [MockFunction], - "getType": [MockFunction], - "getTypeNameByEsTypes": [MockFunction], - "getTypeWithoutMetaParams": [MockFunction], - "has": [MockFunction], - "init": [MockFunction], - "parseDefaultTypeMap": [MockFunction], - "register": [MockFunction], - }, - "fields": FldList [], - "flattenHit": [Function], - "getFieldAttrs": [Function], - "getIndexPattern": [Function], - "getName": [Function], - "getOriginalSavedObjectBody": [Function], - "id": "LOG_DATA_VIEW", - "matchedIndices": Array [], - "metaFields": Array [ - "_id", - "_type", - "_source", - ], - "name": "", - "namespaces": Array [], - "originalSavedObjectBody": Object {}, - "resetOriginalSavedObjectBody": [Function], - "runtimeFieldMap": Object { - "runtime_field": Object { - "script": Object { - "source": "emit(\\"runtime value\\")", - }, - "type": "keyword", - }, - }, - "setFieldFormat": [Function], - "setIndexPattern": [Function], - "shortDotsEnable": false, - "sourceFilters": Array [], - "timeFieldName": "@timestamp", - "title": "Inventory-indices-*", - "type": undefined, - "typeMeta": undefined, - "version": "1", - }, - "description": "LOG VIEW DESCRIPTION", - "fields": FldList [], - "indices": "Inventory-indices-*", - "messageField": Array [ - "message", - ], - "name": "LOG VIEW", - "runtimeMappings": Object { - "runtime_field": Object { - "script": Object { - "source": "emit(\\"runtime value\\")", - }, - "type": "keyword", - }, - }, - "tiebreakerField": "_doc", - "timestampField": "@timestamp", - } - `); + expect(savedObjectsClient.delete).toHaveBeenCalled(); + expect(inventoryView).toEqual({}); }); }); const createInventoryViewsClient = () => { - const Inventoryger = LoggerMock.create(); - const dataViews = dataViewsServiceMock; + const logger = loggerMock.create(); const savedObjectsClient = savedObjectsClientMock.create(); const infraSources = createInfraSourcesMock(); - const internalInventoryViews = new Map(); - const inventoryViewStaticConfig: InventoryViewsStaticConfig = { - messageFields: ['message'], - }; - const inventoryViewsClient = new InventoryViewsClient( - Inventoryger, - Promise.resolve(dataViews), - savedObjectsClient, - infraSources, - internalInventoryViews, - inventoryViewStaticConfig - ); + const inventoryViewsClient = new InventoryViewsClient(logger, savedObjectsClient, infraSources); return { - dataViews, infraSources, - internalInventoryViews, - inventoryViewStaticConfig, inventoryViewsClient, savedObjectsClient, }; @@ -417,16 +235,16 @@ const basicTestSourceConfiguration: InfraSource = { configuration: { name: 'NAME', description: 'DESCRIPTION', - InventoryIndices: { + logIndices: { type: 'index_pattern', indexPatternId: 'INDEX_PATTERN_ID', }, - InventoryColumns: [], + logColumns: [], fields: { message: [], }, metricAlias: 'METRIC_ALIAS', - inventoryDefaultView: 'INVENTORY_DEFAULT_VIEW', + inventoryDefaultView: 'static', metricsExplorerDefaultView: 'METRICS_EXPLORER_DEFAULT_VIEW', anomalyThreshold: 0, }, diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts index c5a88b20f7a08..7a8757a078b17 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts @@ -12,7 +12,10 @@ import { SavedObjectsUpdateResponse, } from '@kbn/core/server'; import Boom from '@hapi/boom'; -import { i18n } from '@kbn/i18n'; +import { + staticInventoryViewAttributes, + staticInventoryViewId, +} from '../../../common/inventory_views/defaults'; import { CreateInventoryViewAttributesRequestPayload, InventoryViewRequestQuery, @@ -46,7 +49,7 @@ export class InventoryViewsClient implements IInventoryViewsClient { }), ]); - const defaultView = this.createStaticView( + const defaultView = InventoryViewsClient.createStaticView( sourceConfiguration.configuration.inventoryDefaultView ); const views = inventoryViewSavedObject.saved_objects.map((savedObject) => @@ -74,7 +77,9 @@ export class InventoryViewsClient implements IInventoryViewsClient { sourceId ); - return this.createStaticView(sourceConfiguration.configuration.inventoryDefaultView); + return InventoryViewsClient.createStaticView( + sourceConfiguration.configuration.inventoryDefaultView + ); } const [sourceConfiguration, inventoryViewSavedObject] = await Promise.all([ @@ -109,7 +114,7 @@ export class InventoryViewsClient implements IInventoryViewsClient { attributes: CreateInventoryViewAttributesRequestPayload, query: InventoryViewRequestQuery ): Promise { - this.logger.debug(`Trying to create inventory view ...`); + this.logger.debug(`Trying to update inventory view with id "${inventoryViewId}"...`); // Validate there is not a view with the same name await this.assertNameConflict(attributes.name, [inventoryViewId]); @@ -160,7 +165,7 @@ export class InventoryViewsClient implements IInventoryViewsClient { perPage: 1000, }); - const hasConflict = [this.createStaticView(), ...results.saved_objects].some( + const hasConflict = [InventoryViewsClient.createStaticView(), ...results.saved_objects].some( (obj) => !whitelist.includes(obj.id) && obj.attributes.name === name ); @@ -169,46 +174,11 @@ export class InventoryViewsClient implements IInventoryViewsClient { } } - private createStaticView = (defaultViewId?: string): InventoryView => ({ - id: InventoryViewsClient.STATIC_VIEW_ID, + public static createStaticView = (defaultViewId?: string): InventoryView => ({ + id: staticInventoryViewId, attributes: { - name: i18n.translate('xpack.infra.savedView.defaultViewNameHosts', { - defaultMessage: 'Default view', - }), + ...staticInventoryViewAttributes, isDefault: defaultViewId === InventoryViewsClient.STATIC_VIEW_ID, - isStatic: true, - metric: { - type: 'cpu', - }, - groupBy: [], - nodeType: 'host', - view: 'map', - customOptions: [], - boundsOverride: { - max: 1, - min: 0, - }, - autoBounds: true, - accountId: '', - region: '', - customMetrics: [], - legend: { - palette: 'cool', - steps: 10, - reverseColors: false, - }, - source: 'default', - sort: { - by: 'name', - direction: 'desc', - }, - timelineOpen: false, - filterQuery: { - kind: 'kuery', - expression: '', - }, - time: Date.now(), - autoReload: false, }, }); } From 418b3b18e1cd93ba1e467f47c98e97b4da22c7f3 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Mon, 17 Apr 2023 13:22:43 +0200 Subject: [PATCH 12/20] feat(infra): init metrics explorer view common --- .../common/metrics_explorer_views/defaults.ts | 51 +++++++++++++++++++ .../metric_explorer_view.mock.ts | 24 +++++++++ .../common/metrics_explorer_views/types.ts | 32 ++++++------ .../inventory_views/inventory_views_client.ts | 2 +- 4 files changed, 93 insertions(+), 16 deletions(-) create mode 100644 x-pack/plugins/infra/common/metrics_explorer_views/defaults.ts create mode 100644 x-pack/plugins/infra/common/metrics_explorer_views/metric_explorer_view.mock.ts diff --git a/x-pack/plugins/infra/common/metrics_explorer_views/defaults.ts b/x-pack/plugins/infra/common/metrics_explorer_views/defaults.ts new file mode 100644 index 0000000000000..88771d1a76fcb --- /dev/null +++ b/x-pack/plugins/infra/common/metrics_explorer_views/defaults.ts @@ -0,0 +1,51 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import type { NonEmptyString } from '@kbn/io-ts-utils'; +import type { MetricsExplorerViewAttributes } from './types'; + +export const staticMetricsExplorerViewId = 'static'; + +export const staticMetricsExplorerViewAttributes: MetricsExplorerViewAttributes = { + name: i18n.translate('xpack.infra.savedView.defaultViewNameHosts', { + defaultMessage: 'Default view', + }) as NonEmptyString, + isDefault: false, + isStatic: true, + options: { + aggregation: 'avg', + metrics: [ + { + aggregation: 'avg', + field: 'system.cpu.total.norm.pct', + color: 'color0', + }, + { + aggregation: 'avg', + field: 'kubernetes.pod.cpu.usage.node.pct', + color: 'color1', + }, + { + aggregation: 'avg', + field: 'docker.cpu.total.pct', + color: 'color2', + }, + ], + source: 'default', + }, + chartOptions: { + type: 'line', + yAxisMode: 'fromZero', + stack: false, + }, + currentTimerange: { + from: 'now-1h', + to: 'now', + interval: '>=10s', + }, +}; diff --git a/x-pack/plugins/infra/common/metrics_explorer_views/metric_explorer_view.mock.ts b/x-pack/plugins/infra/common/metrics_explorer_views/metric_explorer_view.mock.ts new file mode 100644 index 0000000000000..e921c37dd21f8 --- /dev/null +++ b/x-pack/plugins/infra/common/metrics_explorer_views/metric_explorer_view.mock.ts @@ -0,0 +1,24 @@ +/* + * 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 { staticMetricsExplorerViewAttributes } from './defaults'; +import type { MetricsExplorerView, MetricsExplorerViewAttributes } from './types'; + +export const createmetricsExplorerViewMock = ( + id: string, + attributes: MetricsExplorerViewAttributes, + updatedAt?: number, + version?: string +): MetricsExplorerView => ({ + id, + attributes: { + ...staticMetricsExplorerViewAttributes, + ...attributes, + }, + updatedAt, + version, +}); diff --git a/x-pack/plugins/infra/common/metrics_explorer_views/types.ts b/x-pack/plugins/infra/common/metrics_explorer_views/types.ts index 8c80e78136957..47ecb06ceace5 100644 --- a/x-pack/plugins/infra/common/metrics_explorer_views/types.ts +++ b/x-pack/plugins/infra/common/metrics_explorer_views/types.ts @@ -5,29 +5,31 @@ * 2.0. */ +import { nonEmptyStringRt } from '@kbn/io-ts-utils'; import * as rt from 'io-ts'; export const metricsExplorerViewAttributesRT = rt.intersection([ rt.strict({ - name: rt.string, + name: nonEmptyStringRt, + isDefault: rt.boolean, + isStatic: rt.boolean, }), rt.UnknownRecord, ]); export type MetricsExplorerViewAttributes = rt.TypeOf; -// export const inventoryViewRT = rt.exact( -// rt.intersection([ -// rt.type({ -// id: rt.string, -// origin: logViewOriginRT, -// attributes: logViewAttributesRT, -// }), -// rt.partial({ -// updatedAt: rt.number, -// version: rt.string, -// }), -// ]) -// ); +export const metricsExplorerViewRT = rt.exact( + rt.intersection([ + rt.type({ + id: rt.string, + attributes: metricsExplorerViewAttributesRT, + }), + rt.partial({ + updatedAt: rt.number, + version: rt.string, + }), + ]) +); -// export type LogView = rt.TypeOf; +export type MetricsExplorerView = rt.TypeOf; diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts index 7a8757a078b17..039ab5378d1a4 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts @@ -174,7 +174,7 @@ export class InventoryViewsClient implements IInventoryViewsClient { } } - public static createStaticView = (defaultViewId?: string): InventoryView => ({ + private static createStaticView = (defaultViewId?: string): InventoryView => ({ id: staticInventoryViewId, attributes: { ...staticInventoryViewAttributes, From 1af767285ed352902dab43b3e726feab1931b50c Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Tue, 18 Apr 2023 10:51:24 +0200 Subject: [PATCH 13/20] feat(infra): update type imports --- .../plugins/infra/common/inventory_views/defaults.ts | 4 ++-- x-pack/plugins/infra/common/inventory_views/index.ts | 1 + .../common/inventory_views/inventory_view.mock.ts | 2 +- .../inventory_view/inventory_view_saved_object.ts | 2 +- .../metrics_explorer_view_saved_object.ts | 2 +- .../inventory_views/inventory_views_client.mock.ts | 2 +- .../services/inventory_views/inventory_views_client.ts | 10 +++++----- .../inventory_views/inventory_views_service.mock.ts | 2 +- .../inventory_views/inventory_views_service.ts | 4 ++-- .../infra/server/services/inventory_views/types.ts | 8 ++++---- 10 files changed, 19 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/infra/common/inventory_views/defaults.ts b/x-pack/plugins/infra/common/inventory_views/defaults.ts index fa19b01193c74..340482ce840a3 100644 --- a/x-pack/plugins/infra/common/inventory_views/defaults.ts +++ b/x-pack/plugins/infra/common/inventory_views/defaults.ts @@ -6,8 +6,8 @@ */ import { i18n } from '@kbn/i18n'; -import { NonEmptyString } from '@kbn/io-ts-utils'; -import { InventoryViewAttributes } from './types'; +import type { NonEmptyString } from '@kbn/io-ts-utils'; +import type { InventoryViewAttributes } from './types'; export const staticInventoryViewId = 'static'; diff --git a/x-pack/plugins/infra/common/inventory_views/index.ts b/x-pack/plugins/infra/common/inventory_views/index.ts index 6cc0ccaa93a6d..ae809a6c7c615 100644 --- a/x-pack/plugins/infra/common/inventory_views/index.ts +++ b/x-pack/plugins/infra/common/inventory_views/index.ts @@ -5,4 +5,5 @@ * 2.0. */ +export * from './defaults'; export * from './types'; diff --git a/x-pack/plugins/infra/common/inventory_views/inventory_view.mock.ts b/x-pack/plugins/infra/common/inventory_views/inventory_view.mock.ts index 0b5e952053035..a8f5ef6ce181b 100644 --- a/x-pack/plugins/infra/common/inventory_views/inventory_view.mock.ts +++ b/x-pack/plugins/infra/common/inventory_views/inventory_view.mock.ts @@ -6,7 +6,7 @@ */ import { staticInventoryViewAttributes } from './defaults'; -import { InventoryView, InventoryViewAttributes } from './types'; +import type { InventoryView, InventoryViewAttributes } from './types'; export const createInventoryViewMock = ( id: string, diff --git a/x-pack/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.ts b/x-pack/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.ts index 7fe1dfec2195f..f9c4c4d354024 100644 --- a/x-pack/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.ts +++ b/x-pack/plugins/infra/server/saved_objects/inventory_view/inventory_view_saved_object.ts @@ -7,7 +7,7 @@ import { fold } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; -import { SavedObject, SavedObjectsType } from '@kbn/core/server'; +import type { SavedObject, SavedObjectsType } from '@kbn/core/server'; import { inventoryViewSavedObjectRT } from './types'; export const inventoryViewSavedObjectName = 'inventory-view'; diff --git a/x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/metrics_explorer_view_saved_object.ts b/x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/metrics_explorer_view_saved_object.ts index 7281a51f96fcd..ce47aa93951b6 100644 --- a/x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/metrics_explorer_view_saved_object.ts +++ b/x-pack/plugins/infra/server/saved_objects/metrics_explorer_view/metrics_explorer_view_saved_object.ts @@ -7,7 +7,7 @@ import { fold } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; -import { SavedObject, SavedObjectsType } from '@kbn/core/server'; +import type { SavedObject, SavedObjectsType } from '@kbn/core/server'; import { metricsExplorerViewSavedObjectRT } from './types'; export const metricsExplorerViewSavedObjectName = 'metrics-explorer-view'; diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts index 5be7ae42746d4..9d832f8502104 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.mock.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IInventoryViewsClient } from './types'; +import type { IInventoryViewsClient } from './types'; export const createInventoryViewsClientMock = (): jest.Mocked => ({ delete: jest.fn(), diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts index 039ab5378d1a4..b9d70a46f390a 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { +import type { Logger, SavedObject, SavedObjectsClientContract, @@ -15,17 +15,17 @@ import Boom from '@hapi/boom'; import { staticInventoryViewAttributes, staticInventoryViewId, -} from '../../../common/inventory_views/defaults'; -import { +} from '../../../common/inventory_views'; +import type { CreateInventoryViewAttributesRequestPayload, InventoryViewRequestQuery, } from '../../../common/http_api/latest'; -import { InventoryView, InventoryViewAttributes } from '../../../common/inventory_views'; +import type { InventoryView, InventoryViewAttributes } from '../../../common/inventory_views'; import { decodeOrThrow } from '../../../common/runtime_types'; import type { IInfraSources } from '../../lib/sources'; import { inventoryViewSavedObjectName } from '../../saved_objects/inventory_view'; import { inventoryViewSavedObjectRT } from '../../saved_objects/inventory_view/types'; -import { IInventoryViewsClient } from './types'; +import type { IInventoryViewsClient } from './types'; export class InventoryViewsClient implements IInventoryViewsClient { constructor( diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts index f2cb8bb130bd3..cb3e85643303c 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.mock.ts @@ -6,7 +6,7 @@ */ import { createInventoryViewsClientMock } from './inventory_views_client.mock'; -import { InventoryViewsServiceSetup, InventoryViewsServiceStart } from './types'; +import type { InventoryViewsServiceSetup, InventoryViewsServiceStart } from './types'; export const createInventoryViewsServiceSetupMock = (): jest.Mocked => {}; diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts index 16fe09ba6cdcb..a4311f016a464 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { KibanaRequest, Logger, SavedObjectsClientContract } from '@kbn/core/server'; +import typ e{ KibanaRequest, Logger, SavedObjectsClientContract } from '@kbn/core/server'; import { InventoryViewsClient } from './inventory_views_client'; -import { +import type { InventoryViewsServiceSetup, InventoryViewsServiceStart, InventoryViewsServiceStartDeps, diff --git a/x-pack/plugins/infra/server/services/inventory_views/types.ts b/x-pack/plugins/infra/server/services/inventory_views/types.ts index 0e3b72e763dcc..3e023b77af6c2 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/types.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/types.ts @@ -5,18 +5,18 @@ * 2.0. */ -import { +import type { KibanaRequest, SavedObjectsClientContract, SavedObjectsServiceStart, } from '@kbn/core/server'; -import { +import type { CreateInventoryViewAttributesRequestPayload, InventoryViewRequestQuery, UpdateInventoryViewAttributesRequestPayload, } from '../../../common/http_api/latest'; -import { InventoryView } from '../../../common/inventory_views'; -import { InfraSources } from '../../lib/sources'; +import type { InventoryView } from '../../../common/inventory_views'; +import type { InfraSources } from '../../lib/sources'; export interface InventoryViewsServiceStartDeps { infraSources: InfraSources; From 426f9243d111e97f7e363ba6aafcfe19c251a766 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Tue, 18 Apr 2023 10:56:03 +0200 Subject: [PATCH 14/20] fix(infra): typo --- .../server/services/inventory_views/inventory_views_service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts index a4311f016a464..3f51f0e65b29c 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_service.ts @@ -5,7 +5,7 @@ * 2.0. */ -import typ e{ KibanaRequest, Logger, SavedObjectsClientContract } from '@kbn/core/server'; +import type { KibanaRequest, Logger, SavedObjectsClientContract } from '@kbn/core/server'; import { InventoryViewsClient } from './inventory_views_client'; import type { InventoryViewsServiceSetup, From 2e3e5513c91c1ca0cfacaf12ca90c7e1655a61e2 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Wed, 19 Apr 2023 16:24:10 +0200 Subject: [PATCH 15/20] refactor(infra): sort inventory views with default on top --- .../inventory_views/inventory_views_client.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts index b9d70a46f390a..55a8df1024a6e 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.ts @@ -34,7 +34,7 @@ export class InventoryViewsClient implements IInventoryViewsClient { private readonly infraSources: IInfraSources ) {} - static STATIC_VIEW_ID = 'static'; + static STATIC_VIEW_ID = '0'; public async find(query: InventoryViewRequestQuery): Promise { this.logger.debug('Trying to load inventory views ...'); @@ -59,7 +59,11 @@ export class InventoryViewsClient implements IInventoryViewsClient { ) ); - return [defaultView, ...views]; + const inventoryViews = [defaultView, ...views]; + + const sortedInventoryViews = this.moveDefaultViewOnTop(inventoryViews); + + return sortedInventoryViews; } public async get( @@ -156,6 +160,17 @@ export class InventoryViewsClient implements IInventoryViewsClient { }; } + private moveDefaultViewOnTop(views: InventoryView[]) { + const defaultViewPosition = views.findIndex((view) => view.attributes.isDefault); + + if (defaultViewPosition !== -1) { + const element = views.splice(defaultViewPosition, 1)[0]; + views.unshift(element); + } + + return views; + } + /** * We want to control conflicting names on the views */ From 547963f3143ad74e749ed094ccd0d4f21dcdb133 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Wed, 19 Apr 2023 16:25:40 +0200 Subject: [PATCH 16/20] refactor(infra): switch back to old default id --- x-pack/plugins/infra/common/inventory_views/defaults.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/infra/common/inventory_views/defaults.ts b/x-pack/plugins/infra/common/inventory_views/defaults.ts index 340482ce840a3..ae78000968995 100644 --- a/x-pack/plugins/infra/common/inventory_views/defaults.ts +++ b/x-pack/plugins/infra/common/inventory_views/defaults.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { NonEmptyString } from '@kbn/io-ts-utils'; import type { InventoryViewAttributes } from './types'; -export const staticInventoryViewId = 'static'; +export const staticInventoryViewId = '0'; export const staticInventoryViewAttributes: InventoryViewAttributes = { name: i18n.translate('xpack.infra.savedView.defaultViewNameHosts', { From 5120167457b9aab262a43f3167698727bab1efa9 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Wed, 19 Apr 2023 17:33:21 +0200 Subject: [PATCH 17/20] test(infra): update broken test --- .../services/inventory_views/inventory_views_client.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts index 7ae01af1e6267..f11df3fe41893 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts @@ -19,7 +19,7 @@ import { createInventoryViewMock } from '../../../common/inventory_views/invento describe('InventoryViewsClient class', () => { const mockFindInventoryList = (savedObjectsClient: jest.Mocked) => { const inventoryViewListMock = [ - createInventoryViewMock('static', { + createInventoryViewMock('0', { isDefault: true, } as InventoryViewAttributes), createInventoryViewMock('default_id', { @@ -67,7 +67,7 @@ describe('InventoryViewsClient class', () => { createInventoryViewsClient(); const inventoryViewListMock = [ - createInventoryViewMock('static', { + createInventoryViewMock('0', { isDefault: true, } as InventoryViewAttributes), ]; @@ -244,7 +244,7 @@ const basicTestSourceConfiguration: InfraSource = { message: [], }, metricAlias: 'METRIC_ALIAS', - inventoryDefaultView: 'static', + inventoryDefaultView: '0', metricsExplorerDefaultView: 'METRICS_EXPLORER_DEFAULT_VIEW', anomalyThreshold: 0, }, From 72086f11e97d0c35537691718ea9420637567674 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 20 Apr 2023 20:52:17 +0000 Subject: [PATCH 18/20] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- x-pack/plugins/infra/common/http_api/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/infra/common/http_api/index.ts b/x-pack/plugins/infra/common/http_api/index.ts index 833d8e1c50392..355c5925702f7 100644 --- a/x-pack/plugins/infra/common/http_api/index.ts +++ b/x-pack/plugins/infra/common/http_api/index.ts @@ -19,4 +19,4 @@ export * from './infra'; * Exporting versioned APIs types */ export * from './latest'; -export * as inventoryViewsV1 from './inventory_views/v1'; \ No newline at end of file +export * as inventoryViewsV1 from './inventory_views/v1'; From ead011876791ffff645cfe8e0f4ae4dbc22c2bf0 Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Mon, 24 Apr 2023 10:35:44 +0200 Subject: [PATCH 19/20] refactor(infra): request changes --- .../common/http_api/inventory_views/v1/common.ts | 15 ++++++++++++++- .../inventory_views/v1/create_inventory_view.ts | 1 + .../inventory_views/v1/get_inventory_view.ts | 6 +++--- .../inventory_views/v1/update_inventory_view.ts | 1 + .../infra/server/routes/inventory_views/README.md | 2 ++ .../routes/inventory_views/get_inventory_view.ts | 4 ++-- 6 files changed, 23 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts index 37911135711c2..c229170b8007b 100644 --- a/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/common.ts @@ -6,14 +6,27 @@ */ import { nonEmptyStringRt } from '@kbn/io-ts-utils'; import * as rt from 'io-ts'; +import { either } from 'fp-ts/Either'; export const INVENTORY_VIEW_URL = '/api/infra/inventory_views'; export const INVENTORY_VIEW_URL_ENTITY = `${INVENTORY_VIEW_URL}/{inventoryViewId}`; export const getInventoryViewUrl = (inventoryViewId?: string) => [INVENTORY_VIEW_URL, inventoryViewId].filter(Boolean).join('/'); +const inventoryViewIdRT = new rt.Type( + 'InventoryViewId', + rt.string.is, + (u, c) => + either.chain(rt.string.validate(u, c), (id) => { + return id === '0' + ? rt.failure(u, c, `The inventory view with id ${id} is not configurable.`) + : rt.success(id); + }), + String +); + export const inventoryViewRequestParamsRT = rt.type({ - inventoryViewId: rt.string, + inventoryViewId: inventoryViewIdRT, }); export type InventoryViewRequestParams = rt.TypeOf; diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/create_inventory_view.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/create_inventory_view.ts index 9742348a6887f..99350daa358b0 100644 --- a/x-pack/plugins/infra/common/http_api/inventory_views/v1/create_inventory_view.ts +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/create_inventory_view.ts @@ -13,6 +13,7 @@ export const createInventoryViewAttributesRequestPayloadRT = rt.intersection([ name: nonEmptyStringRt, }), rt.UnknownRecord, + rt.exact(rt.partial({ isDefault: rt.undefined, isStatic: rt.undefined })), ]); export type CreateInventoryViewAttributesRequestPayload = rt.TypeOf< diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/get_inventory_view.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/get_inventory_view.ts index e2127d7b88121..3e862bdaa3388 100644 --- a/x-pack/plugins/infra/common/http_api/inventory_views/v1/get_inventory_view.ts +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/get_inventory_view.ts @@ -7,8 +7,8 @@ import * as rt from 'io-ts'; -export const getInventoryViewRequestQueryRT = rt.partial({ - sourceId: rt.string, +export const getInventoryViewRequestParamsRT = rt.type({ + inventoryViewId: rt.string, }); -export type GetInventoryViewRequestQuery = rt.TypeOf; +export type GetInventoryViewRequestParams = rt.TypeOf; diff --git a/x-pack/plugins/infra/common/http_api/inventory_views/v1/update_inventory_view.ts b/x-pack/plugins/infra/common/http_api/inventory_views/v1/update_inventory_view.ts index 6ee0d8c57da06..7a2d33ebd6138 100644 --- a/x-pack/plugins/infra/common/http_api/inventory_views/v1/update_inventory_view.ts +++ b/x-pack/plugins/infra/common/http_api/inventory_views/v1/update_inventory_view.ts @@ -13,6 +13,7 @@ export const updateInventoryViewAttributesRequestPayloadRT = rt.intersection([ name: nonEmptyStringRt, }), rt.UnknownRecord, + rt.exact(rt.partial({ isDefault: rt.undefined, isStatic: rt.undefined })), ]); export type UpdateInventoryViewAttributesRequestPayload = rt.TypeOf< diff --git a/x-pack/plugins/infra/server/routes/inventory_views/README.md b/x-pack/plugins/infra/server/routes/inventory_views/README.md index 701d768a36b75..8a09aedef1b75 100644 --- a/x-pack/plugins/infra/server/routes/inventory_views/README.md +++ b/x-pack/plugins/infra/server/routes/inventory_views/README.md @@ -219,6 +219,8 @@ Status code: 409 Updates an inventory view. +Any attribute can be updated except for `isDefault` and `isStatic`, which are derived by the source configuration preference set by the user. + ### Request - **Method**: PUT diff --git a/x-pack/plugins/infra/server/routes/inventory_views/get_inventory_view.ts b/x-pack/plugins/infra/server/routes/inventory_views/get_inventory_view.ts index 87f5feb97f061..1a5f5adec136d 100644 --- a/x-pack/plugins/infra/server/routes/inventory_views/get_inventory_view.ts +++ b/x-pack/plugins/infra/server/routes/inventory_views/get_inventory_view.ts @@ -9,9 +9,9 @@ import { isBoom } from '@hapi/boom'; import { createValidationFunction } from '../../../common/runtime_types'; import { inventoryViewResponsePayloadRT, - inventoryViewRequestParamsRT, inventoryViewRequestQueryRT, INVENTORY_VIEW_URL_ENTITY, + getInventoryViewRequestParamsRT, } from '../../../common/http_api/latest'; import type { InfraBackendLibs } from '../../lib/infra_types'; @@ -24,7 +24,7 @@ export const initGetInventoryViewRoute = ({ method: 'get', path: INVENTORY_VIEW_URL_ENTITY, validate: { - params: createValidationFunction(inventoryViewRequestParamsRT), + params: createValidationFunction(getInventoryViewRequestParamsRT), query: createValidationFunction(inventoryViewRequestQueryRT), }, }, From 88466a425bc907b19bc8a9a06e64b567df0c525f Mon Sep 17 00:00:00 2001 From: Marco Antonio Ghiani Date: Mon, 24 Apr 2023 11:04:48 +0200 Subject: [PATCH 20/20] fix(infra): update test types --- .../inventory_views/inventory_views_client.test.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts index f11df3fe41893..5d5b253045de4 100644 --- a/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts +++ b/x-pack/plugins/infra/server/services/inventory_views/inventory_views_client.test.ts @@ -15,6 +15,10 @@ import { createInfraSourcesMock } from '../../lib/sources/mocks'; import { inventoryViewSavedObjectName } from '../../saved_objects/inventory_view'; import { InventoryViewsClient } from './inventory_views_client'; import { createInventoryViewMock } from '../../../common/inventory_views/inventory_view.mock'; +import { + CreateInventoryViewAttributesRequestPayload, + UpdateInventoryViewAttributesRequestPayload, +} from '../../../common/http_api/latest'; describe('InventoryViewsClient class', () => { const mockFindInventoryList = (savedObjectsClient: jest.Mocked) => { @@ -130,7 +134,7 @@ describe('InventoryViewsClient class', () => { const inventoryView = await inventoryViewsClient.create({ name: 'New view', - } as InventoryViewAttributes); + } as CreateInventoryViewAttributesRequestPayload); expect(savedObjectsClient.create).toHaveBeenCalled(); expect(inventoryView).toEqual(inventoryViewMock); @@ -145,7 +149,7 @@ describe('InventoryViewsClient class', () => { async () => await inventoryViewsClient.create({ name: 'Custom', - } as InventoryViewAttributes) + } as CreateInventoryViewAttributesRequestPayload) ).rejects.toThrow('A view with that name already exists.'); }); }); @@ -177,7 +181,7 @@ describe('InventoryViewsClient class', () => { 'default_id', { name: 'New name', - } as InventoryViewAttributes, + } as UpdateInventoryViewAttributesRequestPayload, {} ); @@ -196,7 +200,7 @@ describe('InventoryViewsClient class', () => { 'default_id', { name: 'Custom', - } as InventoryViewAttributes, + } as UpdateInventoryViewAttributesRequestPayload, {} ) ).rejects.toThrow('A view with that name already exists.');