Skip to content

Commit

Permalink
[Infrastructure UI] Create MetricsExplorerViewsService and MetricsExp…
Browse files Browse the repository at this point in the history
…lorerViewsClient (#155878)

## 📓 Summary

Depends on #154900
Closes #155112  

This PR implements the `InventoryViewsService` and
`InventoryViewsClient`, injecting an instance of the client in the
KibanaContextForPlugin and exposing so a set of utilities to
retrieve/update inventory views:
- `findMetricsExplorerViews`
- `getMetricsExplorerView`
- `createMetricsExplorerView`
- `updateMetricsExplorerView`
- `deleteMetricsExplorerView`

## 👣 Next steps
- Implement #154725 to consume the service

---------

Co-authored-by: Marco Antonio Ghiani <[email protected]>
Co-authored-by: Carlos Crespo <[email protected]>
  • Loading branch information
3 people authored Apr 27, 2023
1 parent bf64874 commit 5422d08
Show file tree
Hide file tree
Showing 11 changed files with 278 additions and 0 deletions.
32 changes: 32 additions & 0 deletions x-pack/plugins/infra/common/metrics_explorer_views/errors.ts
Original file line number Diff line number Diff line change
@@ -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 FetchMetricsExplorerViewError extends Error {
constructor(message: string, public cause?: Error) {
super(message);
Object.setPrototypeOf(this, new.target.prototype);
this.name = 'FetchMetricsExplorerViewError';
}
}

export class UpsertMetricsExplorerViewError extends Error {
constructor(message: string, public cause?: Error) {
super(message);
Object.setPrototypeOf(this, new.target.prototype);
this.name = 'UpsertMetricsExplorerViewError';
}
}

export class DeleteMetricsExplorerViewError extends Error {
constructor(message: string, public cause?: Error) {
super(message);
Object.setPrototypeOf(this, new.target.prototype);
this.name = 'DeleteMetricsExplorerViewError';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
*/

export * from './defaults';
export * from './errors';
export * from './types';
2 changes: 2 additions & 0 deletions x-pack/plugins/infra/public/mocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
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 { createMetricsExplorerViewsServiceStartMock } from './services/metrics_explorer_views/metrics_explorer_views_service.mock';
import { createTelemetryServiceMock } from './services/telemetry/telemetry_service.mock';
import { InfraClientStartExports } from './types';

export const createInfraPluginStartMock = () => ({
inventoryViews: createInventoryViewsServiceStartMock(),
logViews: createLogViewsServiceStartMock(),
metricsExplorerViews: createMetricsExplorerViewsServiceStartMock(),
telemetry: createTelemetryServiceMock(),
ContainerMetricsTable: () => <div />,
HostMetricsTable: () => <div />,
Expand Down
8 changes: 8 additions & 0 deletions x-pack/plugins/infra/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { createMetricsFetchData, createMetricsHasData } from './metrics_overview
import { registerFeatures } from './register_feature';
import { InventoryViewsService } from './services/inventory_views';
import { LogViewsService } from './services/log_views';
import { MetricsExplorerViewsService } from './services/metrics_explorer_views';
import { TelemetryService } from './services/telemetry';
import {
InfraClientCoreSetup,
Expand All @@ -47,6 +48,7 @@ export class Plugin implements InfraClientPluginClass {
public config: InfraPublicConfig;
private inventoryViews: InventoryViewsService;
private logViews: LogViewsService;
private metricsExplorerViews: MetricsExplorerViewsService;
private telemetry: TelemetryService;
private readonly appUpdater$ = new BehaviorSubject<AppUpdater>(() => ({}));

Expand All @@ -57,6 +59,7 @@ export class Plugin implements InfraClientPluginClass {
messageFields:
this.config.sources?.default?.fields?.message ?? defaultLogViewsStaticConfig.messageFields,
});
this.metricsExplorerViews = new MetricsExplorerViewsService();
this.telemetry = new TelemetryService();
}

Expand Down Expand Up @@ -298,11 +301,16 @@ export class Plugin implements InfraClientPluginClass {
search: plugins.data.search,
});

const metricsExplorerViews = this.metricsExplorerViews.start({
http: core.http,
});

const telemetry = this.telemetry.start();

const startContract: InfraClientStartExports = {
inventoryViews,
logViews,
metricsExplorerViews,
telemetry,
ContainerMetricsTable: createLazyContainerMetricsTable(getStartServices),
HostMetricsTable: createLazyHostMetricsTable(getStartServices),
Expand Down
Original file line number Diff line number Diff line change
@@ -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 './metrics_explorer_views_client';
export * from './metrics_explorer_views_service';
export * from './types';
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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 { IMetricsExplorerViewsClient } from './types';

export const createMetricsExplorerViewsClientMock =
(): jest.Mocked<IMetricsExplorerViewsClient> => ({
findMetricsExplorerViews: jest.fn(),
getMetricsExplorerView: jest.fn(),
createMetricsExplorerView: jest.fn(),
updateMetricsExplorerView: jest.fn(),
deleteMetricsExplorerView: jest.fn(),
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* 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 {
CreateMetricsExplorerViewAttributesRequestPayload,
createMetricsExplorerViewRequestPayloadRT,
findMetricsExplorerViewResponsePayloadRT,
getMetricsExplorerViewUrl,
metricsExplorerViewResponsePayloadRT,
UpdateMetricsExplorerViewAttributesRequestPayload,
} from '../../../common/http_api/latest';
import {
DeleteMetricsExplorerViewError,
FetchMetricsExplorerViewError,
MetricsExplorerView,
UpsertMetricsExplorerViewError,
} from '../../../common/metrics_explorer_views';
import { decodeOrThrow } from '../../../common/runtime_types';
import { IMetricsExplorerViewsClient } from './types';

export class MetricsExplorerViewsClient implements IMetricsExplorerViewsClient {
constructor(private readonly http: HttpStart) {}

async findMetricsExplorerViews(): Promise<MetricsExplorerView[]> {
const response = await this.http.get(getMetricsExplorerViewUrl()).catch((error) => {
throw new FetchMetricsExplorerViewError(`Failed to fetch metrics explorer views: ${error}`);
});

const { data } = decodeOrThrow(
findMetricsExplorerViewResponsePayloadRT,
(message: string) =>
new FetchMetricsExplorerViewError(`Failed to decode metrics explorer views: ${message}"`)
)(response);

return data;
}

async getMetricsExplorerView(metricsExplorerViewId: string): Promise<MetricsExplorerView> {
const response = await this.http
.get(getMetricsExplorerViewUrl(metricsExplorerViewId))
.catch((error) => {
throw new FetchMetricsExplorerViewError(
`Failed to fetch metrics explorer view "${metricsExplorerViewId}": ${error}`
);
});

const { data } = decodeOrThrow(
metricsExplorerViewResponsePayloadRT,
(message: string) =>
new FetchMetricsExplorerViewError(
`Failed to decode metrics explorer view "${metricsExplorerViewId}": ${message}"`
)
)(response);

return data;
}

async createMetricsExplorerView(
metricsExplorerViewAttributes: CreateMetricsExplorerViewAttributesRequestPayload
): Promise<MetricsExplorerView> {
const response = await this.http
.post(getMetricsExplorerViewUrl(), {
body: JSON.stringify(
createMetricsExplorerViewRequestPayloadRT.encode({
attributes: metricsExplorerViewAttributes,
})
),
})
.catch((error) => {
throw new UpsertMetricsExplorerViewError(
`Failed to create new metrics explorer view: ${error}`
);
});

const { data } = decodeOrThrow(
metricsExplorerViewResponsePayloadRT,
(message: string) =>
new UpsertMetricsExplorerViewError(
`Failed to decode newly written metrics explorer view: ${message}"`
)
)(response);

return data;
}

async updateMetricsExplorerView(
metricsExplorerViewId: string,
metricsExplorerViewAttributes: UpdateMetricsExplorerViewAttributesRequestPayload
): Promise<MetricsExplorerView> {
const response = await this.http
.put(getMetricsExplorerViewUrl(metricsExplorerViewId), {
body: JSON.stringify(
createMetricsExplorerViewRequestPayloadRT.encode({
attributes: metricsExplorerViewAttributes,
})
),
})
.catch((error) => {
throw new UpsertMetricsExplorerViewError(
`Failed to update metrics explorer view "${metricsExplorerViewId}": ${error}`
);
});

const { data } = decodeOrThrow(
metricsExplorerViewResponsePayloadRT,
(message: string) =>
new UpsertMetricsExplorerViewError(
`Failed to decode updated metrics explorer view "${metricsExplorerViewId}": ${message}"`
)
)(response);

return data;
}

deleteMetricsExplorerView(metricsExplorerViewId: string): Promise<null> {
return this.http
.delete(getMetricsExplorerViewUrl(metricsExplorerViewId))
.then(() => null)
.catch((error) => {
throw new DeleteMetricsExplorerViewError(
`Failed to delete metrics explorer view "${metricsExplorerViewId}": ${error}`
);
});
}
}
Original file line number Diff line number Diff line change
@@ -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 { createMetricsExplorerViewsClientMock } from './metrics_explorer_views_client.mock';
import { MetricsExplorerViewsServiceStart } from './types';

export const createMetricsExplorerViewsServiceStartMock = () => ({
client: createMetricsExplorerViewsClientMock(),
});

export const _ensureTypeCompatibility = (): MetricsExplorerViewsServiceStart =>
createMetricsExplorerViewsServiceStartMock();
Original file line number Diff line number Diff line change
@@ -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 { MetricsExplorerViewsClient } from './metrics_explorer_views_client';
import {
MetricsExplorerViewsServiceStartDeps,
MetricsExplorerViewsServiceSetup,
MetricsExplorerViewsServiceStart,
} from './types';

export class MetricsExplorerViewsService {
public setup(): MetricsExplorerViewsServiceSetup {}

public start({ http }: MetricsExplorerViewsServiceStartDeps): MetricsExplorerViewsServiceStart {
const client = new MetricsExplorerViewsClient(http);

return {
client,
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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 {
MetricsExplorerView,
MetricsExplorerViewAttributes,
} from '../../../common/metrics_explorer_views';

export type MetricsExplorerViewsServiceSetup = void;

export interface MetricsExplorerViewsServiceStart {
client: IMetricsExplorerViewsClient;
}

export interface MetricsExplorerViewsServiceStartDeps {
http: HttpStart;
}

export interface IMetricsExplorerViewsClient {
findMetricsExplorerViews(): Promise<MetricsExplorerView[]>;
getMetricsExplorerView(metricsExplorerViewId: string): Promise<MetricsExplorerView>;
createMetricsExplorerView(
metricsExplorerViewAttributes: Partial<MetricsExplorerViewAttributes>
): Promise<MetricsExplorerView>;
updateMetricsExplorerView(
metricsExplorerViewId: string,
metricsExplorerViewAttributes: Partial<MetricsExplorerViewAttributes>
): Promise<MetricsExplorerView>;
deleteMetricsExplorerView(metricsExplorerViewId: string): Promise<null>;
}
2 changes: 2 additions & 0 deletions x-pack/plugins/infra/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import type {
} from './components/infrastructure_node_metrics_tables/shared';
import { InventoryViewsServiceStart } from './services/inventory_views';
import { LogViewsServiceStart } from './services/log_views';
import { MetricsExplorerViewsServiceStart } from './services/metrics_explorer_views';
import { ITelemetryClient } from './services/telemetry';

// Our own setup and start contract values
Expand All @@ -53,6 +54,7 @@ export type InfraClientSetupExports = void;
export interface InfraClientStartExports {
inventoryViews: InventoryViewsServiceStart;
logViews: LogViewsServiceStart;
metricsExplorerViews: MetricsExplorerViewsServiceStart;
telemetry: ITelemetryClient;
ContainerMetricsTable: (
props: UseNodeMetricsTableOptions & Partial<SourceProviderProps>
Expand Down

0 comments on commit 5422d08

Please sign in to comment.