Skip to content

Commit

Permalink
[Infra UI] Add cloud metrics and cloud/host info to metadata endpoint (
Browse files Browse the repository at this point in the history
…elastic#41836)

* [Infra UI] Add cloud metrics and cloud/host info to metadata endpoint

* Adding cloud metrics

* Correcting the pod host/cloud info

* Adding tests to metadata for new cloud/host info

* Fixing test to include machine.type

* Adding aws test data

* Refactor metadata container into hook

* Functionally complete

* updating tests

* Removing Metadata GraphQL endpoint and supporting files

* Moving types under common/http_api and prefixing with Infra

* adding filter for aws.ec2 dataset

* move away from fetch to useHTTPRequest

* Add decode function to useHTTPRequest; rename data to response;

* Changing from Typescript types to IO-TS types and adding checks at client and server
  • Loading branch information
simianhacker committed Aug 2, 2019
1 parent 2355162 commit c143403
Show file tree
Hide file tree
Showing 40 changed files with 18,105 additions and 937 deletions.
59 changes: 0 additions & 59 deletions x-pack/legacy/plugins/infra/common/graphql/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ export interface InfraSource {
configuration: InfraSourceConfiguration;
/** The status of the source */
status: InfraSourceStatus;
/** A hierarchy of metadata entries by node */
metadataByNode: InfraNodeMetadata;
/** A consecutive span of log entries surrounding a point in time */
logEntriesAround: InfraLogEntryInterval;
/** A consecutive span of log entries within an interval */
Expand Down Expand Up @@ -132,20 +130,6 @@ export interface InfraIndexField {
/** Whether the field's values can be aggregated */
aggregatable: boolean;
}
/** One metadata entry for a node. */
export interface InfraNodeMetadata {
id: string;

name: string;

features: InfraNodeFeature[];
}

export interface InfraNodeFeature {
name: string;

source: string;
}
/** A consecutive sequence of log entries */
export interface InfraLogEntryInterval {
/** The key corresponding to the start of the interval covered by the entries */
Expand Down Expand Up @@ -424,11 +408,6 @@ export interface SourceQueryArgs {
/** The id of the source */
id: string;
}
export interface MetadataByNodeInfraSourceArgs {
nodeId: string;

nodeType: InfraNodeType;
}
export interface LogEntriesAroundInfraSourceArgs {
/** The sort key that corresponds to the point in time */
key: InfraTimeKeyInput;
Expand Down Expand Up @@ -722,44 +701,6 @@ export namespace LogSummary {
};
}

export namespace MetadataQuery {
export type Variables = {
sourceId: string;
nodeId: string;
nodeType: InfraNodeType;
};

export type Query = {
__typename?: 'Query';

source: Source;
};

export type Source = {
__typename?: 'InfraSource';

id: string;

metadataByNode: MetadataByNode;
};

export type MetadataByNode = {
__typename?: 'InfraNodeMetadata';

name: string;

features: Features[];
};

export type Features = {
__typename?: 'InfraNodeFeature';

name: string;

source: string;
};
}

export namespace MetricsQuery {
export type Variables = {
sourceId: string;
Expand Down
2 changes: 2 additions & 0 deletions x-pack/legacy/plugins/infra/common/http_api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@

export * from './search_results_api';
export * from './search_summary_api';
export * from './metadata_api';
export * from './timed_api';
100 changes: 100 additions & 0 deletions x-pack/legacy/plugins/infra/common/http_api/metadata_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import * as rt from 'io-ts';
import { InfraWrappableRequest } from '../../server/lib/adapters/framework';

export const InfraMetadataNodeTypeRT = rt.keyof({
host: null,
pod: null,
container: null,
});

export const InfraMetadataRequestRT = rt.type({
nodeId: rt.string,
nodeType: InfraMetadataNodeTypeRT,
sourceId: rt.string,
});

export const InfraMetadataFeatureRT = rt.type({
name: rt.string,
source: rt.string,
});

export const InfraMetadataOSRT = rt.partial({
codename: rt.string,
family: rt.string,
kernel: rt.string,
name: rt.string,
platform: rt.string,
version: rt.string,
});

export const InfraMetadataHostRT = rt.partial({
name: rt.string,
os: InfraMetadataOSRT,
architecture: rt.string,
containerized: rt.boolean,
});

export const InfraMetadataInstanceRT = rt.partial({
id: rt.string,
name: rt.string,
});

export const InfraMetadataProjectRT = rt.partial({
id: rt.string,
});

export const InfraMetadataMachineRT = rt.partial({
interface: rt.string,
});

export const InfraMetadataCloudRT = rt.partial({
instance: InfraMetadataInstanceRT,
provider: rt.string,
availability_zone: rt.string,
project: InfraMetadataProjectRT,
machine: InfraMetadataMachineRT,
});

export const InfraMetadataInfoRT = rt.partial({
cloud: InfraMetadataCloudRT,
host: InfraMetadataHostRT,
});

const InfraMetadataRequiredRT = rt.type({
name: rt.string,
features: rt.array(InfraMetadataFeatureRT),
});

const InfraMetadataOptionalRT = rt.partial({
info: InfraMetadataInfoRT,
});

export const InfraMetadataRT = rt.intersection([InfraMetadataRequiredRT, InfraMetadataOptionalRT]);

export type InfraMetadata = rt.TypeOf<typeof InfraMetadataRT>;

export type InfraMetadataRequest = rt.TypeOf<typeof InfraMetadataRequestRT>;

export type InfraMetadataWrappedRequest = InfraWrappableRequest<InfraMetadataRequest>;

export type InfraMetadataFeature = rt.TypeOf<typeof InfraMetadataFeatureRT>;

export type InfraMetadataInfo = rt.TypeOf<typeof InfraMetadataInfoRT>;

export type InfraMetadataCloud = rt.TypeOf<typeof InfraMetadataCloudRT>;

export type InfraMetadataInstance = rt.TypeOf<typeof InfraMetadataInstanceRT>;

export type InfraMetadataProject = rt.TypeOf<typeof InfraMetadataProjectRT>;

export type InfraMetadataMachine = rt.TypeOf<typeof InfraMetadataMachineRT>;

export type InfraMetadataHost = rt.TypeOf<typeof InfraMetadataHostRT>;

export type InfraMEtadataOS = rt.TypeOf<typeof InfraMetadataOSRT>;
14 changes: 14 additions & 0 deletions x-pack/legacy/plugins/infra/common/runtime_types.ts
Original file line number Diff line number Diff line change
@@ -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;
* you may not use this file except in compliance with the Elastic License.
*/

import { Errors } from 'io-ts';
import { failure } from 'io-ts/lib/PathReporter';

export const createPlainError = (message: string) => new Error(message);

export const throwErrors = (createError: (message: string) => Error) => (errors: Errors) => {
throw createError(failure(errors).join('\n'));
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
import { EuiButton, EuiComboBox, EuiForm, EuiFormRow } from '@elastic/eui';
import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
import React from 'react';
import { InfraIndexField } from '../../../server/graphql/types';
import { FieldType } from 'ui/index_patterns';
interface Props {
onSubmit: (field: string) => void;
fields: InfraIndexField[];
fields: FieldType[];
intl: InjectedIntl;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import {
} from '@elastic/eui';
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
import React from 'react';
import { InfraIndexField, InfraNodeType, InfraSnapshotGroupbyInput } from '../../graphql/types';
import { FieldType } from 'ui/index_patterns';
import { InfraNodeType, InfraSnapshotGroupbyInput } from '../../graphql/types';
import { InfraGroupByOptions } from '../../lib/lib';
import { CustomFieldPanel } from './custom_field_panel';
import { fieldToName } from './lib/field_to_display_name';
Expand All @@ -26,7 +27,7 @@ interface Props {
groupBy: InfraSnapshotGroupbyInput[];
onChange: (groupBy: InfraSnapshotGroupbyInput[]) => void;
onChangeCustomOptions: (options: InfraGroupByOptions[]) => void;
fields: InfraIndexField[];
fields: FieldType[];
intl: InjectedIntl;
customOptions: InfraGroupByOptions[];
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { InfraMetadataFeature } from '../../../../common/http_api/metadata_api';
import { InfraMetricLayout } from '../../../pages/metrics/layouts/types';

export const getFilteredLayouts = (
layouts: InfraMetricLayout[],
metadata: Array<InfraMetadataFeature | null> | undefined
): InfraMetricLayout[] => {
if (!metadata) {
return layouts;
}

const metricMetadata: Array<string | null> = metadata
.filter(data => data && data.source === 'metrics')
.map(data => data && data.name);

// After filtering out sections that can't be displayed, a layout may end up empty and can be removed.
const filteredLayouts = layouts
.map(layout => getFilteredLayout(layout, metricMetadata))
.filter(layout => layout.sections.length > 0);
return filteredLayouts;
};

export const getFilteredLayout = (
layout: InfraMetricLayout,
metricMetadata: Array<string | null>
): InfraMetricLayout => {
// A section is only displayed if at least one of its requirements is met
// All others are filtered out.
const filteredSections = layout.sections.filter(
section => _.intersection(section.requires, metricMetadata).length > 0
);
return { ...layout, sections: filteredSections };
};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { useEffect } from 'react';
import { InfraNodeType } from '../../graphql/types';
import { InfraMetricLayout } from '../../pages/metrics/layouts/types';
import { InfraMetadata, InfraMetadataRT } from '../../../common/http_api/metadata_api';
import { getFilteredLayouts } from './lib/get_filtered_layouts';
import { useHTTPRequest } from '../../hooks/use_http_request';
import { throwErrors, createPlainError } from '../../../common/runtime_types';

export function useMetadata(
nodeId: string,
nodeType: InfraNodeType,
layouts: InfraMetricLayout[],
sourceId: string
) {
const decodeResponse = (response: any) => {
return InfraMetadataRT.decode(response).getOrElseL(throwErrors(createPlainError));
};

const { error, loading, response, makeRequest } = useHTTPRequest<InfraMetadata>(
'/api/infra/metadata',
'POST',
JSON.stringify({
nodeId,
nodeType,
sourceId,
decodeResponse,
})
);

useEffect(() => {
(async () => {
await makeRequest();
})();
}, [makeRequest]);

return {
name: (response && response.name) || '',
filteredLayouts: (response && getFilteredLayouts(layouts, response.features)) || [],
error: (error && error.message) || null,
loading,
};
}
Loading

0 comments on commit c143403

Please sign in to comment.