diff --git a/x-pack/plugins/infra/common/inventory_views/errors.ts b/x-pack/plugins/infra/common/inventory_views/errors.ts new file mode 100644 index 0000000000000..711245c5e45c9 --- /dev/null +++ b/x-pack/plugins/infra/common/inventory_views/errors.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ + +/* eslint-disable max-classes-per-file */ + +export class FetchInventoryViewError extends Error { + constructor(message: string, public cause?: Error) { + super(message); + Object.setPrototypeOf(this, new.target.prototype); + this.name = 'FetchInventoryViewError'; + } +} + +export class UpsertInventoryViewError extends Error { + constructor(message: string, public cause?: Error) { + super(message); + Object.setPrototypeOf(this, new.target.prototype); + this.name = 'UpsertInventoryViewError'; + } +} + +export class DeleteInventoryViewError extends Error { + constructor(message: string, public cause?: Error) { + super(message); + Object.setPrototypeOf(this, new.target.prototype); + this.name = 'DeleteInventoryViewError'; + } +} diff --git a/x-pack/plugins/infra/common/inventory_views/index.ts b/x-pack/plugins/infra/common/inventory_views/index.ts index ae809a6c7c615..e64ab6b8ff3d5 100644 --- a/x-pack/plugins/infra/common/inventory_views/index.ts +++ b/x-pack/plugins/infra/common/inventory_views/index.ts @@ -4,6 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - export * from './defaults'; +export * from './errors'; export * from './types'; diff --git a/x-pack/plugins/infra/public/mocks.tsx b/x-pack/plugins/infra/public/mocks.tsx index a3182c176da4b..40209529fa837 100644 --- a/x-pack/plugins/infra/public/mocks.tsx +++ b/x-pack/plugins/infra/public/mocks.tsx @@ -6,11 +6,13 @@ */ import React from 'react'; +import { createInventoryViewsServiceStartMock } from './services/inventory_views/inventory_views_service.mock'; import { createLogViewsServiceStartMock } from './services/log_views/log_views_service.mock'; import { createTelemetryServiceMock } from './services/telemetry/telemetry_service.mock'; import { InfraClientStartExports } from './types'; export const createInfraPluginStartMock = () => ({ + inventoryViews: createInventoryViewsServiceStartMock(), logViews: createLogViewsServiceStartMock(), telemetry: createTelemetryServiceMock(), ContainerMetricsTable: () =>
, diff --git a/x-pack/plugins/infra/public/plugin.ts b/x-pack/plugins/infra/public/plugin.ts index 8931a6fd32cb7..5aecffde99da9 100644 --- a/x-pack/plugins/infra/public/plugin.ts +++ b/x-pack/plugins/infra/public/plugin.ts @@ -29,6 +29,7 @@ import { LOG_STREAM_EMBEDDABLE } from './components/log_stream/log_stream_embedd import { LogStreamEmbeddableFactoryDefinition } from './components/log_stream/log_stream_embeddable_factory'; import { createMetricsFetchData, createMetricsHasData } from './metrics_overview_fetchers'; import { registerFeatures } from './register_feature'; +import { InventoryViewsService } from './services/inventory_views'; import { LogViewsService } from './services/log_views'; import { TelemetryService } from './services/telemetry'; import { @@ -44,12 +45,14 @@ import { getLogsHasDataFetcher, getLogsOverviewDataFetcher } from './utils/logs_ export class Plugin implements InfraClientPluginClass { public config: InfraPublicConfig; + private inventoryViews: InventoryViewsService; private logViews: LogViewsService; private telemetry: TelemetryService; private readonly appUpdater$ = new BehaviorSubject(() => ({})); constructor(context: PluginInitializerContext) { this.config = context.config.get(); + this.inventoryViews = new InventoryViewsService(); this.logViews = new LogViewsService({ messageFields: this.config.sources?.default?.fields?.message ?? defaultLogViewsStaticConfig.messageFields, @@ -285,6 +288,10 @@ export class Plugin implements InfraClientPluginClass { start(core: InfraClientCoreStart, plugins: InfraClientStartDeps) { const getStartServices = (): InfraClientStartServices => [core, plugins, startContract]; + const inventoryViews = this.inventoryViews.start({ + http: core.http, + }); + const logViews = this.logViews.start({ http: core.http, dataViews: plugins.dataViews, @@ -294,6 +301,7 @@ export class Plugin implements InfraClientPluginClass { const telemetry = this.telemetry.start(); const startContract: InfraClientStartExports = { + inventoryViews, logViews, telemetry, ContainerMetricsTable: createLazyContainerMetricsTable(getStartServices), diff --git a/x-pack/plugins/infra/public/services/inventory_views/index.ts b/x-pack/plugins/infra/public/services/inventory_views/index.ts new file mode 100644 index 0000000000000..b40aea33b4946 --- /dev/null +++ b/x-pack/plugins/infra/public/services/inventory_views/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 * from './inventory_views_client'; +export * from './inventory_views_service'; +export * from './types'; diff --git a/x-pack/plugins/infra/public/services/inventory_views/inventory_views_client.mock.ts b/x-pack/plugins/infra/public/services/inventory_views/inventory_views_client.mock.ts new file mode 100644 index 0000000000000..9f483c9834b02 --- /dev/null +++ b/x-pack/plugins/infra/public/services/inventory_views/inventory_views_client.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 { IInventoryViewsClient } from './types'; + +export const createInventoryViewsClientMock = (): jest.Mocked => ({ + findInventoryViews: jest.fn(), + getInventoryView: jest.fn(), + createInventoryView: jest.fn(), + updateInventoryView: jest.fn(), + deleteInventoryView: jest.fn(), +}); diff --git a/x-pack/plugins/infra/public/services/inventory_views/inventory_views_client.ts b/x-pack/plugins/infra/public/services/inventory_views/inventory_views_client.ts new file mode 100644 index 0000000000000..a72dd8c7fefbd --- /dev/null +++ b/x-pack/plugins/infra/public/services/inventory_views/inventory_views_client.ts @@ -0,0 +1,120 @@ +/* + * 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 { HttpStart } from '@kbn/core/public'; +import { + CreateInventoryViewAttributesRequestPayload, + createInventoryViewRequestPayloadRT, + findInventoryViewResponsePayloadRT, + getInventoryViewUrl, + inventoryViewResponsePayloadRT, + UpdateInventoryViewAttributesRequestPayload, +} from '../../../common/http_api/latest'; +import { + DeleteInventoryViewError, + FetchInventoryViewError, + InventoryView, + UpsertInventoryViewError, +} from '../../../common/inventory_views'; +import { decodeOrThrow } from '../../../common/runtime_types'; +import { IInventoryViewsClient } from './types'; + +export class InventoryViewsClient implements IInventoryViewsClient { + constructor(private readonly http: HttpStart) {} + + async findInventoryViews(): Promise { + const response = await this.http.get(getInventoryViewUrl()).catch((error) => { + throw new FetchInventoryViewError(`Failed to fetch inventory views: ${error}`); + }); + + const { data } = decodeOrThrow( + findInventoryViewResponsePayloadRT, + (message: string) => + new FetchInventoryViewError(`Failed to decode inventory views: ${message}"`) + )(response); + + return data; + } + + async getInventoryView(inventoryViewId: string): Promise { + const response = await this.http.get(getInventoryViewUrl(inventoryViewId)).catch((error) => { + throw new FetchInventoryViewError( + `Failed to fetch inventory view "${inventoryViewId}": ${error}` + ); + }); + + const { data } = decodeOrThrow( + inventoryViewResponsePayloadRT, + (message: string) => + new FetchInventoryViewError( + `Failed to decode inventory view "${inventoryViewId}": ${message}"` + ) + )(response); + + return data; + } + + async createInventoryView( + inventoryViewAttributes: CreateInventoryViewAttributesRequestPayload + ): Promise { + const response = await this.http + .post(getInventoryViewUrl(), { + body: JSON.stringify( + createInventoryViewRequestPayloadRT.encode({ attributes: inventoryViewAttributes }) + ), + }) + .catch((error) => { + throw new UpsertInventoryViewError(`Failed to create new inventory view : ${error}`); + }); + + const { data } = decodeOrThrow( + inventoryViewResponsePayloadRT, + (message: string) => + new UpsertInventoryViewError(`Failed to decode newly written inventory view: ${message}"`) + )(response); + + return data; + } + + async updateInventoryView( + inventoryViewId: string, + inventoryViewAttributes: UpdateInventoryViewAttributesRequestPayload + ): Promise { + const response = await this.http + .put(getInventoryViewUrl(inventoryViewId), { + body: JSON.stringify( + createInventoryViewRequestPayloadRT.encode({ attributes: inventoryViewAttributes }) + ), + }) + .catch((error) => { + throw new UpsertInventoryViewError( + `Failed to update inventory view "${inventoryViewId}": ${error}` + ); + }); + + const { data } = decodeOrThrow( + inventoryViewResponsePayloadRT, + (message: string) => + new UpsertInventoryViewError( + `Failed to decode updated inventory view "${inventoryViewId}": ${message}"` + ) + )(response); + + return data; + } + + deleteInventoryView(inventoryViewId: string): Promise { + return this.http + .delete(getInventoryViewUrl(inventoryViewId)) + .then(() => null) + .catch((error) => { + throw new DeleteInventoryViewError( + `Failed to delete inventory view "${inventoryViewId}": ${error}` + ); + }); + } +} diff --git a/x-pack/plugins/infra/public/services/inventory_views/inventory_views_service.mock.ts b/x-pack/plugins/infra/public/services/inventory_views/inventory_views_service.mock.ts new file mode 100644 index 0000000000000..f9c139ceb2857 --- /dev/null +++ b/x-pack/plugins/infra/public/services/inventory_views/inventory_views_service.mock.ts @@ -0,0 +1,16 @@ +/* + * 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 './inventory_views_client.mock'; +import { InventoryViewsServiceStart } from './types'; + +export const createInventoryViewsServiceStartMock = () => ({ + client: createInventoryViewsClientMock(), +}); + +export const _ensureTypeCompatibility = (): InventoryViewsServiceStart => + createInventoryViewsServiceStartMock(); diff --git a/x-pack/plugins/infra/public/services/inventory_views/inventory_views_service.ts b/x-pack/plugins/infra/public/services/inventory_views/inventory_views_service.ts new file mode 100644 index 0000000000000..bf5be3825adc5 --- /dev/null +++ b/x-pack/plugins/infra/public/services/inventory_views/inventory_views_service.ts @@ -0,0 +1,25 @@ +/* + * 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 { InventoryViewsClient } from './inventory_views_client'; +import { + InventoryViewsServiceStartDeps, + InventoryViewsServiceSetup, + InventoryViewsServiceStart, +} from './types'; + +export class InventoryViewsService { + public setup(): InventoryViewsServiceSetup {} + + public start({ http }: InventoryViewsServiceStartDeps): InventoryViewsServiceStart { + const client = new InventoryViewsClient(http); + + return { + client, + }; + } +} diff --git a/x-pack/plugins/infra/public/services/inventory_views/types.ts b/x-pack/plugins/infra/public/services/inventory_views/types.ts new file mode 100644 index 0000000000000..2a690c4cc6c2e --- /dev/null +++ b/x-pack/plugins/infra/public/services/inventory_views/types.ts @@ -0,0 +1,32 @@ +/* + * 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 { HttpStart } from '@kbn/core/public'; +import { InventoryView, InventoryViewAttributes } from '../../../common/inventory_views'; + +export type InventoryViewsServiceSetup = void; + +export interface InventoryViewsServiceStart { + client: IInventoryViewsClient; +} + +export interface InventoryViewsServiceStartDeps { + http: HttpStart; +} + +export interface IInventoryViewsClient { + findInventoryViews(): Promise; + getInventoryView(inventoryViewId: string): Promise; + createInventoryView( + inventoryViewAttributes: Partial + ): Promise; + updateInventoryView( + inventoryViewId: string, + inventoryViewAttributes: Partial + ): Promise; + deleteInventoryView(inventoryViewId: string): Promise; +} diff --git a/x-pack/plugins/infra/public/types.ts b/x-pack/plugins/infra/public/types.ts index 9d5cc8abbfbe1..7a41cbb3a85d3 100644 --- a/x-pack/plugins/infra/public/types.ts +++ b/x-pack/plugins/infra/public/types.ts @@ -43,6 +43,7 @@ import type { SourceProviderProps, UseNodeMetricsTableOptions, } from './components/infrastructure_node_metrics_tables/shared'; +import { InventoryViewsServiceStart } from './services/inventory_views'; import { LogViewsServiceStart } from './services/log_views'; import { ITelemetryClient } from './services/telemetry'; @@ -50,6 +51,7 @@ import { ITelemetryClient } from './services/telemetry'; export type InfraClientSetupExports = void; export interface InfraClientStartExports { + inventoryViews: InventoryViewsServiceStart; logViews: LogViewsServiceStart; telemetry: ITelemetryClient; ContainerMetricsTable: (