From 489119cbbed5317f48befe311e1cfdeb6ddbfc8f Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Mon, 17 Dec 2018 15:54:52 -0700 Subject: [PATCH] [Infra UI] Update links for containers to use ID instead of name (#27088) (#27324) * Adding id and name to metadata response * Adding name to response * update to types * Adding support for displayNames to waffle map * fixing a bug when _source is missing * Fixing tests * making the metadata response manditory * Fixes from PR review * Fixing typing errors related to displayName being required part of path * Changing 'Loading data for xxx' to 'Loading data' * Changing InfraNodePath.displayName to InfraNodePath.label * Change groups to use the label instead of value * Fixing merge changes --- .../infra/public/components/metrics/index.tsx | 16 ++-- .../components/waffle/group_of_nodes.tsx | 2 +- .../components/waffle/node_context_menu.tsx | 12 +-- .../containers/metadata/metadata.gql_query.ts | 7 +- .../containers/metadata/with_metadata.tsx | 6 +- .../containers/waffle/nodes_to_wafflemap.ts | 10 ++- .../waffle/waffle_nodes.gql_query.ts | 1 + .../infra/public/graphql/introspection.json | 75 ++++++++++++++++-- x-pack/plugins/infra/public/graphql/types.ts | 26 +++++- x-pack/plugins/infra/public/lib/lib.ts | 1 + .../infra/public/pages/link_to/link_to.tsx | 4 +- .../pages/link_to/redirect_to_node_detail.tsx | 12 +-- .../pages/link_to/redirect_to_node_logs.tsx | 12 +-- .../infra/public/pages/metrics/index.tsx | 79 ++++++++++--------- .../server/graphql/metadata/resolvers.ts | 2 +- .../server/graphql/metadata/schema.gql.ts | 8 +- .../infra/server/graphql/nodes/schema.gql.ts | 1 + x-pack/plugins/infra/server/graphql/types.ts | 57 +++++++++++-- .../lib/adapters/metadata/adapter_types.ts | 14 +++- .../elasticsearch_metadata_adapter.ts | 53 +++++++++---- .../server/lib/adapters/nodes/constants.ts | 6 ++ .../adapters/nodes/lib/create_node_item.ts | 6 +- .../adapters/nodes/lib/extract_group_paths.ts | 6 +- .../processors/common/group_by_processor.ts | 6 +- .../processors/common/nodes_processor.ts | 17 +++- .../sources/configuration_sources_adapter.ts | 6 +- .../metadata_domain/metadata_domain.ts | 14 ++-- .../api_integration/apis/infra/metadata.ts | 7 +- .../api_integration/apis/infra/sources.ts | 6 +- 29 files changed, 334 insertions(+), 138 deletions(-) diff --git a/x-pack/plugins/infra/public/components/metrics/index.tsx b/x-pack/plugins/infra/public/components/metrics/index.tsx index 8a0bdb8e8443..f2f0a634a3fe 100644 --- a/x-pack/plugins/infra/public/components/metrics/index.tsx +++ b/x-pack/plugins/infra/public/components/metrics/index.tsx @@ -18,7 +18,8 @@ interface Props { metrics: InfraMetricData[]; layouts: InfraMetricLayout[]; loading: boolean; - nodeName: string; + nodeId: string; + label: string; onChangeRangeTime?: (time: metricTimeActions.MetricRangeTimeState) => void; intl: InjectedIntl; } @@ -41,15 +42,10 @@ export const Metrics = injectI18n( ); } diff --git a/x-pack/plugins/infra/public/components/waffle/group_of_nodes.tsx b/x-pack/plugins/infra/public/components/waffle/group_of_nodes.tsx index f81203dfab4d..c84dc3934693 100644 --- a/x-pack/plugins/infra/public/components/waffle/group_of_nodes.tsx +++ b/x-pack/plugins/infra/public/components/waffle/group_of_nodes.tsx @@ -43,7 +43,7 @@ export const GroupOfNodes: React.SFC = ({ {group.nodes.map(node => ( { - const nodeName = node.path.length > 0 ? node.path[node.path.length - 1].value : undefined; - const nodeLogsUrl = nodeName + const nodeId = node.path.length > 0 ? node.path[node.path.length - 1].value : undefined; + const nodeLogsUrl = nodeId ? getNodeLogsUrl({ nodeType, - nodeName, + nodeId, time: timeRange.to, }) : undefined; - const nodeDetailUrl = nodeName + const nodeDetailUrl = nodeId ? getNodeDetailUrl({ nodeType, - nodeName, + nodeId, from: timeRange.from, to: timeRange.to, }) @@ -76,7 +76,7 @@ export const NodeContextMenu = injectI18n( return ( {({ data, error, loading }) => { const metadata = data && data.source && data.source.metadataByNode; - const filteredLayouts = getFilteredLayouts(layouts, metadata); + const filteredLayouts = (metadata && getFilteredLayouts(layouts, metadata.features)) || []; return children({ + name: (metadata && metadata.name) || '', filteredLayouts, error: error && error.message, loading, @@ -58,7 +60,7 @@ export const WithMetadata = ({ const getFilteredLayouts = ( layouts: InfraMetricLayout[], - metadata: Array | undefined + metadata: Array | undefined ): InfraMetricLayout[] => { if (!metadata) { return layouts; diff --git a/x-pack/plugins/infra/public/containers/waffle/nodes_to_wafflemap.ts b/x-pack/plugins/infra/public/containers/waffle/nodes_to_wafflemap.ts index 4b924afe27ac..56f2ffa0bc5d 100644 --- a/x-pack/plugins/infra/public/containers/waffle/nodes_to_wafflemap.ts +++ b/x-pack/plugins/infra/public/containers/waffle/nodes_to_wafflemap.ts @@ -51,7 +51,7 @@ function findOrCreateGroupWithNodes( ? i18n.translate('xpack.infra.nodesToWaffleMap.groupsWithNodes.allName', { defaultMessage: 'All', }) - : last(path).value, + : last(path).label, count: 0, width: 0, squareSize: 0, @@ -75,7 +75,7 @@ function findOrCreateGroupWithGroups( ? i18n.translate('xpack.infra.nodesToWaffleMap.groupsWithGroups.allName', { defaultMessage: 'All', }) - : last(path).value, + : last(path).label, count: 0, width: 0, squareSize: 0, @@ -84,10 +84,12 @@ function findOrCreateGroupWithGroups( } function createWaffleMapNode(node: InfraNode): InfraWaffleMapNode { + const nodePathItem = last(node.path); return { - id: node.path.map(p => p.value).join('/'), + pathId: node.path.map(p => p.value).join('/'), path: node.path, - name: last(node.path).value, + id: nodePathItem.value, + name: nodePathItem.label, metric: node.metric, }; } diff --git a/x-pack/plugins/infra/public/containers/waffle/waffle_nodes.gql_query.ts b/x-pack/plugins/infra/public/containers/waffle/waffle_nodes.gql_query.ts index 8da5b160603e..51b67086a4bf 100644 --- a/x-pack/plugins/infra/public/containers/waffle/waffle_nodes.gql_query.ts +++ b/x-pack/plugins/infra/public/containers/waffle/waffle_nodes.gql_query.ts @@ -20,6 +20,7 @@ export const waffleNodesQuery = gql` nodes(path: $path, metric: $metric) { path { value + label } metric { name diff --git a/x-pack/plugins/infra/public/graphql/introspection.json b/x-pack/plugins/infra/public/graphql/introspection.json index 7cb84b92bab9..328064987fa9 100644 --- a/x-pack/plugins/infra/public/graphql/introspection.json +++ b/x-pack/plugins/infra/public/graphql/introspection.json @@ -114,7 +114,7 @@ "description": "A hierarchy of metadata entries by node", "args": [ { - "name": "nodeName", + "name": "nodeId", "description": "", "type": { "kind": "NON_NULL", @@ -137,11 +137,7 @@ "type": { "kind": "NON_NULL", "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "OBJECT", "name": "InfraNodeMetadata", "ofType": null } - } + "ofType": { "kind": "OBJECT", "name": "InfraNodeMetadata", "ofType": null } }, "isDeprecated": false, "deprecationReason": null @@ -775,6 +771,61 @@ "kind": "OBJECT", "name": "InfraNodeMetadata", "description": "One metadata entry for a node.", + "fields": [ + { + "name": "id", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "features", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "InfraNodeFeature", "ofType": null } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "InfraNodeFeature", + "description": "", "fields": [ { "name": "name", @@ -1542,6 +1593,18 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "displayName", + "description": "", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, diff --git a/x-pack/plugins/infra/public/graphql/types.ts b/x-pack/plugins/infra/public/graphql/types.ts index 7c67f7963b74..343b8f0ae0ff 100644 --- a/x-pack/plugins/infra/public/graphql/types.ts +++ b/x-pack/plugins/infra/public/graphql/types.ts @@ -23,7 +23,7 @@ export interface InfraSource { /** The status of the source */ status: InfraSourceStatus; /** A hierarchy of metadata entries by node */ - metadataByNode: (InfraNodeMetadata | null)[]; + metadataByNode: InfraNodeMetadata; /** A consecutive span of log entries surrounding a point in time */ logEntriesAround: InfraLogEntryInterval; /** A consecutive span of log entries within an interval */ @@ -89,6 +89,14 @@ export interface InfraIndexField { } /** One metadata entry for a node. */ export interface InfraNodeMetadata { + id: string; + + name: string; + + features: InfraNodeFeature[]; +} + +export interface InfraNodeFeature { name: string; source: string; @@ -175,6 +183,8 @@ export interface InfraNode { export interface InfraNodePath { value: string; + + label: string; } export interface InfraNodeMetric { @@ -252,7 +262,7 @@ export interface SourceQueryArgs { id: string; } export interface MetadataByNodeInfraSourceArgs { - nodeName: string; + nodeId: string; nodeType: InfraNodeType; } @@ -416,7 +426,7 @@ export namespace MetadataQuery { id: string; - metadataByNode: (MetadataByNode | null)[]; + metadataByNode: MetadataByNode; }; export type MetadataByNode = { @@ -424,6 +434,14 @@ export namespace MetadataQuery { name: string; + features: Features[]; + }; + + export type Features = { + __typename?: 'InfraNodeFeature'; + + name: string; + source: string; }; } @@ -517,6 +535,8 @@ export namespace WaffleNodesQuery { __typename?: 'InfraNodePath'; value: string; + + label: string; }; export type Metric = { diff --git a/x-pack/plugins/infra/public/lib/lib.ts b/x-pack/plugins/infra/public/lib/lib.ts index 2ef59fbaeb6c..9d215247d116 100644 --- a/x-pack/plugins/infra/public/lib/lib.ts +++ b/x-pack/plugins/infra/public/lib/lib.ts @@ -100,6 +100,7 @@ export interface InfraField { export type InfraWaffleData = InfraWaffleMapGroup[]; export interface InfraWaffleMapNode { + pathId: string; id: string; name: string; path: InfraNodePath[]; diff --git a/x-pack/plugins/infra/public/pages/link_to/link_to.tsx b/x-pack/plugins/infra/public/pages/link_to/link_to.tsx index e00013a35474..073c335bd156 100644 --- a/x-pack/plugins/infra/public/pages/link_to/link_to.tsx +++ b/x-pack/plugins/infra/public/pages/link_to/link_to.tsx @@ -21,11 +21,11 @@ export class LinkToPage extends React.Component { return ( diff --git a/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_detail.tsx b/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_detail.tsx index bf70e06a629c..d9f62f48a8a8 100644 --- a/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_detail.tsx +++ b/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_detail.tsx @@ -12,13 +12,13 @@ import { InfraNodeType } from '../../graphql/types'; import { getFromFromLocation, getToFromLocation } from './query_params'; type RedirectToNodeDetailProps = RouteComponentProps<{ - nodeName: string; + nodeId: string; nodeType: InfraNodeType; }>; export const RedirectToNodeDetail = ({ match: { - params: { nodeName, nodeType }, + params: { nodeId, nodeType }, }, location, }: RedirectToNodeDetailProps) => { @@ -27,20 +27,20 @@ export const RedirectToNodeDetail = ({ getToFromLocation(location) )(''); - return ; + return ; }; export const getNodeDetailUrl = ({ nodeType, - nodeName, + nodeId, to, from, }: { nodeType: InfraNodeType; - nodeName: string; + nodeId: string; to?: number; from?: number; }) => { const args = to && from ? `?to=${to}&from=${from}` : ''; - return `#/link-to/${nodeType}-detail/${nodeName}${args}`; + return `#/link-to/${nodeType}-detail/${nodeId}${args}`; }; diff --git a/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx b/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx index 5f444e3afdd3..772a01fea485 100644 --- a/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx +++ b/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx @@ -17,7 +17,7 @@ import { InfraNodeType } from '../../graphql/types'; import { getTimeFromLocation } from './query_params'; type RedirectToNodeLogsType = RouteComponentProps<{ - nodeName: string; + nodeId: string; nodeType: InfraNodeType; }>; @@ -28,7 +28,7 @@ interface RedirectToNodeLogsProps extends RedirectToNodeLogsType { export const RedirectToNodeLogs = injectI18n( ({ match: { - params: { nodeName, nodeType }, + params: { nodeId, nodeType }, }, location, intl, @@ -52,7 +52,7 @@ export const RedirectToNodeLogs = injectI18n( } const searchString = compose( - replaceLogFilterInQueryString(`${configuredFields[nodeType]}: ${nodeName}`), + replaceLogFilterInQueryString(`${configuredFields[nodeType]}: ${nodeId}`), replaceLogPositionInQueryString(getTimeFromLocation(location)) )(''); @@ -63,11 +63,11 @@ export const RedirectToNodeLogs = injectI18n( ); export const getNodeLogsUrl = ({ - nodeName, + nodeId, nodeType, time, }: { - nodeName: string; + nodeId: string; nodeType: InfraNodeType; time?: number; -}) => [`#/link-to/${nodeType}-logs/`, nodeName, ...(time ? [`?time=${time}`] : [])].join(''); +}) => [`#/link-to/${nodeType}-logs/`, nodeId, ...(time ? [`?time=${time}`] : [])].join(''); diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index 7e1c138587d9..20e559f6e844 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -63,7 +63,7 @@ export const MetricDetail = withTheme( public render() { const { intl } = this.props; - const nodeName = this.props.match.params.node; + const nodeId = this.props.match.params.node; const nodeType = this.props.match.params.type as InfraNodeType; const layoutCreator = layoutCreators[nodeType]; if (!layoutCreator) { @@ -82,40 +82,40 @@ export const MetricDetail = withTheme( ); } const layouts = layoutCreator(this.props.theme); - const breadcrumbs = [{ text: nodeName }]; return ( - -
} - breadcrumbs={breadcrumbs} - /> - - - - {({ sourceId }) => ( - - {({ - currentTimeRange, - isAutoReloading, - setRangeTime, - startMetricsAutoReload, - stopMetricsAutoReload, - }) => ( - - {({ filteredLayouts, loading: metadataLoading }) => { - return ( + + {({ sourceId }) => ( + + {({ + currentTimeRange, + isAutoReloading, + setRangeTime, + startMetricsAutoReload, + stopMetricsAutoReload, + }) => ( + + {({ name, filteredLayouts, loading: metadataLoading }) => { + const breadcrumbs = [{ text: name }]; + return ( + +
} + breadcrumbs={breadcrumbs} + /> + + {({ metrics, error, loading }) => { if (error) { @@ -126,7 +126,7 @@ export const MetricDetail = withTheme( @@ -139,7 +139,7 @@ export const MetricDetail = withTheme( -

{nodeName}

+

{name}

- ); - }} - - )} - +
+ + ); + }} + )} - - - + + )} + ); } diff --git a/x-pack/plugins/infra/server/graphql/metadata/resolvers.ts b/x-pack/plugins/infra/server/graphql/metadata/resolvers.ts index 618932d6433e..8d1b386af548 100644 --- a/x-pack/plugins/infra/server/graphql/metadata/resolvers.ts +++ b/x-pack/plugins/infra/server/graphql/metadata/resolvers.ts @@ -23,7 +23,7 @@ export const createMetadataResolvers = (libs: { } => ({ InfraSource: { async metadataByNode(source, args, { req }) { - const result = await libs.metadata.getMetadata(req, source.id, args.nodeName, args.nodeType); + const result = await libs.metadata.getMetadata(req, source.id, args.nodeId, args.nodeType); return result; }, }, diff --git a/x-pack/plugins/infra/server/graphql/metadata/schema.gql.ts b/x-pack/plugins/infra/server/graphql/metadata/schema.gql.ts index 1a0e40d8f0b8..8944e309d463 100644 --- a/x-pack/plugins/infra/server/graphql/metadata/schema.gql.ts +++ b/x-pack/plugins/infra/server/graphql/metadata/schema.gql.ts @@ -9,12 +9,18 @@ import gql from 'graphql-tag'; export const metadataSchema = gql` "One metadata entry for a node." type InfraNodeMetadata { + id: ID! + name: String! + features: [InfraNodeFeature!]! + } + + type InfraNodeFeature { name: String! source: String! } extend type InfraSource { "A hierarchy of metadata entries by node" - metadataByNode(nodeName: String!, nodeType: InfraNodeType!): [InfraNodeMetadata]! + metadataByNode(nodeId: String!, nodeType: InfraNodeType!): InfraNodeMetadata! } `; diff --git a/x-pack/plugins/infra/server/graphql/nodes/schema.gql.ts b/x-pack/plugins/infra/server/graphql/nodes/schema.gql.ts index 33de32f10080..cbad4e93b158 100644 --- a/x-pack/plugins/infra/server/graphql/nodes/schema.gql.ts +++ b/x-pack/plugins/infra/server/graphql/nodes/schema.gql.ts @@ -14,6 +14,7 @@ export const nodesSchema: any = gql` type InfraNodePath { value: String! + label: String } type InfraNode { diff --git a/x-pack/plugins/infra/server/graphql/types.ts b/x-pack/plugins/infra/server/graphql/types.ts index 9747790fb17c..c7d974e7e512 100644 --- a/x-pack/plugins/infra/server/graphql/types.ts +++ b/x-pack/plugins/infra/server/graphql/types.ts @@ -51,7 +51,7 @@ export interface InfraSource { /** The status of the source */ status: InfraSourceStatus; /** A hierarchy of metadata entries by node */ - metadataByNode: (InfraNodeMetadata | null)[]; + metadataByNode: InfraNodeMetadata; /** A consecutive span of log entries surrounding a point in time */ logEntriesAround: InfraLogEntryInterval; /** A consecutive span of log entries within an interval */ @@ -117,6 +117,14 @@ export interface InfraIndexField { } /** One metadata entry for a node. */ export interface InfraNodeMetadata { + id: string; + + name: string; + + features: InfraNodeFeature[]; +} + +export interface InfraNodeFeature { name: string; source: string; @@ -203,6 +211,8 @@ export interface InfraNode { export interface InfraNodePath { value: string; + + label: string; } export interface InfraNodeMetric { @@ -280,7 +290,7 @@ export interface SourceQueryArgs { id: string; } export interface MetadataByNodeInfraSourceArgs { - nodeName: string; + nodeId: string; nodeType: InfraNodeType; } @@ -461,7 +471,7 @@ export namespace InfraSourceResolvers { /** The status of the source */ status?: StatusResolver; /** A hierarchy of metadata entries by node */ - metadataByNode?: MetadataByNodeResolver<(InfraNodeMetadata | null)[], TypeParent, Context>; + metadataByNode?: MetadataByNodeResolver; /** A consecutive span of log entries surrounding a point in time */ logEntriesAround?: LogEntriesAroundResolver; /** A consecutive span of log entries within an interval */ @@ -490,12 +500,12 @@ export namespace InfraSourceResolvers { Context = InfraContext > = Resolver; export type MetadataByNodeResolver< - R = (InfraNodeMetadata | null)[], + R = InfraNodeMetadata, Parent = InfraSource, Context = InfraContext > = Resolver; export interface MetadataByNodeArgs { - nodeName: string; + nodeId: string; nodeType: InfraNodeType; } @@ -746,6 +756,32 @@ export namespace InfraIndexFieldResolvers { /** One metadata entry for a node. */ export namespace InfraNodeMetadataResolvers { export interface Resolvers { + id?: IdResolver; + + name?: NameResolver; + + features?: FeaturesResolver; + } + + export type IdResolver = Resolver< + R, + Parent, + Context + >; + export type NameResolver< + R = string, + Parent = InfraNodeMetadata, + Context = InfraContext + > = Resolver; + export type FeaturesResolver< + R = InfraNodeFeature[], + Parent = InfraNodeMetadata, + Context = InfraContext + > = Resolver; +} + +export namespace InfraNodeFeatureResolvers { + export interface Resolvers { name?: NameResolver; source?: SourceResolver; @@ -753,12 +789,12 @@ export namespace InfraNodeMetadataResolvers { export type NameResolver< R = string, - Parent = InfraNodeMetadata, + Parent = InfraNodeFeature, Context = InfraContext > = Resolver; export type SourceResolver< R = string, - Parent = InfraNodeMetadata, + Parent = InfraNodeFeature, Context = InfraContext > = Resolver; } @@ -1012,6 +1048,8 @@ export namespace InfraNodeResolvers { export namespace InfraNodePathResolvers { export interface Resolvers { value?: ValueResolver; + + label?: DisplayNameResolver; } export type ValueResolver = Resolver< @@ -1019,6 +1057,11 @@ export namespace InfraNodePathResolvers { Parent, Context >; + export type DisplayNameResolver< + R = string, + Parent = InfraNodePath, + Context = InfraContext + > = Resolver; } export namespace InfraNodeMetricResolvers { diff --git a/x-pack/plugins/infra/server/lib/adapters/metadata/adapter_types.ts b/x-pack/plugins/infra/server/lib/adapters/metadata/adapter_types.ts index e7aece48c7cd..fed6589e8ba8 100644 --- a/x-pack/plugins/infra/server/lib/adapters/metadata/adapter_types.ts +++ b/x-pack/plugins/infra/server/lib/adapters/metadata/adapter_types.ts @@ -7,17 +7,23 @@ import { InfraSourceConfiguration } from '../../sources'; import { InfraFrameworkRequest, InfraMetadataAggregationBucket } from '../framework'; +export interface InfraMetricsAdapterResponse { + id: string; + name?: string; + buckets: InfraMetadataAggregationBucket[]; +} + export interface InfraMetadataAdapter { getMetricMetadata( req: InfraFrameworkRequest, sourceConfiguration: InfraSourceConfiguration, - nodeName: string, + nodeId: string, nodeType: string - ): Promise; + ): Promise; getLogMetadata( req: InfraFrameworkRequest, sourceConfiguration: InfraSourceConfiguration, - nodeName: string, + nodeId: string, nodeType: string - ): Promise; + ): Promise; } diff --git a/x-pack/plugins/infra/server/lib/adapters/metadata/elasticsearch_metadata_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/metadata/elasticsearch_metadata_adapter.ts index 7972154124ee..e35438e66376 100644 --- a/x-pack/plugins/infra/server/lib/adapters/metadata/elasticsearch_metadata_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/metadata/elasticsearch_metadata_adapter.ts @@ -4,14 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ +import { first, get } from 'lodash'; import { InfraSourceConfiguration } from '../../sources'; import { InfraBackendFrameworkAdapter, InfraFrameworkRequest, - InfraMetadataAggregationBucket, InfraMetadataAggregationResponse, } from '../framework'; -import { InfraMetadataAdapter } from './adapter_types'; +import { NAME_FIELDS } from '../nodes/constants'; +import { InfraMetadataAdapter, InfraMetricsAdapterResponse } from './adapter_types'; export class ElasticsearchMetadataAdapter implements InfraMetadataAdapter { private framework: InfraBackendFrameworkAdapter; @@ -22,9 +23,9 @@ export class ElasticsearchMetadataAdapter implements InfraMetadataAdapter { public async getMetricMetadata( req: InfraFrameworkRequest, sourceConfiguration: InfraSourceConfiguration, - nodeName: string, + nodeId: string, nodeType: 'host' | 'container' | 'pod' - ): Promise { + ): Promise { const idFieldName = getIdFieldName(sourceConfiguration, nodeType); const metricQuery = { index: sourceConfiguration.metricAlias, @@ -32,11 +33,12 @@ export class ElasticsearchMetadataAdapter implements InfraMetadataAdapter { query: { bool: { filter: { - term: { [idFieldName]: nodeName }, + term: { [idFieldName]: nodeId }, }, }, }, - size: 0, + size: 1, + _source: [NAME_FIELDS[nodeType]], aggs: { metrics: { terms: { @@ -61,17 +63,26 @@ export class ElasticsearchMetadataAdapter implements InfraMetadataAdapter { { metrics?: InfraMetadataAggregationResponse } >(req, 'search', metricQuery); - return response.aggregations && response.aggregations.metrics - ? response.aggregations.metrics.buckets - : []; + const buckets = + response.aggregations && response.aggregations.metrics + ? response.aggregations.metrics.buckets + : []; + + const sampleDoc = first(response.hits.hits); + + return { + id: nodeId, + name: get(sampleDoc, `_source.${NAME_FIELDS[nodeType]}`), + buckets, + }; } public async getLogMetadata( req: InfraFrameworkRequest, sourceConfiguration: InfraSourceConfiguration, - nodeName: string, + nodeId: string, nodeType: 'host' | 'container' | 'pod' - ): Promise { + ): Promise { const idFieldName = getIdFieldName(sourceConfiguration, nodeType); const logQuery = { index: sourceConfiguration.logAlias, @@ -79,11 +90,12 @@ export class ElasticsearchMetadataAdapter implements InfraMetadataAdapter { query: { bool: { filter: { - term: { [idFieldName]: nodeName }, + term: { [idFieldName]: nodeId }, }, }, }, - size: 0, + size: 1, + _source: [NAME_FIELDS[nodeType]], aggs: { metrics: { terms: { @@ -108,9 +120,18 @@ export class ElasticsearchMetadataAdapter implements InfraMetadataAdapter { { metrics?: InfraMetadataAggregationResponse } >(req, 'search', logQuery); - return response.aggregations && response.aggregations.metrics - ? response.aggregations.metrics.buckets - : []; + const buckets = + response.aggregations && response.aggregations.metrics + ? response.aggregations.metrics.buckets + : []; + + const sampleDoc = first(response.hits.hits); + + return { + id: nodeId, + name: get(sampleDoc, `_source.${NAME_FIELDS[nodeType]}`), + buckets, + }; } } diff --git a/x-pack/plugins/infra/server/lib/adapters/nodes/constants.ts b/x-pack/plugins/infra/server/lib/adapters/nodes/constants.ts index 75d8464e8efe..53adf25a8b06 100644 --- a/x-pack/plugins/infra/server/lib/adapters/nodes/constants.ts +++ b/x-pack/plugins/infra/server/lib/adapters/nodes/constants.ts @@ -4,6 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ +import { InfraNodeType } from '../../../graphql/types'; // TODO: Make NODE_REQUEST_PARTITION_SIZE configurable from kibana.yml export const NODE_REQUEST_PARTITION_SIZE = 75; export const NODE_REQUEST_PARTITION_FACTOR = 1.2; +export const NAME_FIELDS = { + [InfraNodeType.host]: 'host.name', + [InfraNodeType.pod]: 'kubernetes.pod.name', + [InfraNodeType.container]: 'docker.container.name', +}; diff --git a/x-pack/plugins/infra/server/lib/adapters/nodes/lib/create_node_item.ts b/x-pack/plugins/infra/server/lib/adapters/nodes/lib/create_node_item.ts index 41c24ed13407..5a5bdabdfded 100644 --- a/x-pack/plugins/infra/server/lib/adapters/nodes/lib/create_node_item.ts +++ b/x-pack/plugins/infra/server/lib/adapters/nodes/lib/create_node_item.ts @@ -4,12 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { last } from 'lodash'; +import { get, last } from 'lodash'; import { isNumber } from 'lodash'; import moment from 'moment'; import { InfraNode, InfraNodeMetric } from '../../../../graphql/types'; import { InfraBucket, InfraNodeRequestOptions } from '../adapter_types'; +import { NAME_FIELDS } from '../constants'; import { getBucketSizeInSeconds } from './get_bucket_size_in_seconds'; // TODO: Break these function into seperate files and expand beyond just documnet count @@ -57,8 +58,9 @@ export function createNodeItem( node: InfraBucket, bucket: InfraBucket ): InfraNode { + const nodeDoc = get(node, ['nodeDetails', 'hits', 'hits', 0]); return { metric: createNodeMetrics(options, node, bucket), - path: [{ value: node.key }], + path: [{ value: node.key, label: get(nodeDoc, `_source.${NAME_FIELDS[options.nodeType]}`) }], } as InfraNode; } diff --git a/x-pack/plugins/infra/server/lib/adapters/nodes/lib/extract_group_paths.ts b/x-pack/plugins/infra/server/lib/adapters/nodes/lib/extract_group_paths.ts index 924687ac0e86..1ea42536b86a 100644 --- a/x-pack/plugins/infra/server/lib/adapters/nodes/lib/extract_group_paths.ts +++ b/x-pack/plugins/infra/server/lib/adapters/nodes/lib/extract_group_paths.ts @@ -28,8 +28,8 @@ export function extractGroupPaths( (b: InfraBucket): InfraNode => { const innerNode = createNodeItem(options, node, b); const nodePath = [ - { value: bucket.key.toString() }, - { value: b.key.toString() }, + { value: bucket.key.toString(), label: bucket.key.toString() }, + { value: b.key.toString(), label: b.key.toString() }, ].concat(innerNode.path); return { ...innerNode, @@ -40,7 +40,7 @@ export function extractGroupPaths( ); } const nodeItem = createNodeItem(options, node, bucket); - const path = [{ value: key }].concat(nodeItem.path); + const path = [{ value: key, label: key }].concat(nodeItem.path); return acc.concat({ ...nodeItem, path, diff --git a/x-pack/plugins/infra/server/lib/adapters/nodes/processors/common/group_by_processor.ts b/x-pack/plugins/infra/server/lib/adapters/nodes/processors/common/group_by_processor.ts index a1196b15f121..38d489a15199 100644 --- a/x-pack/plugins/infra/server/lib/adapters/nodes/processors/common/group_by_processor.ts +++ b/x-pack/plugins/infra/server/lib/adapters/nodes/processors/common/group_by_processor.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { cloneDeep, set } from 'lodash'; +import { cloneDeep, get, set } from 'lodash'; import { InfraPathFilterInput, InfraPathInput } from '../../../../../graphql/types'; import { @@ -18,7 +18,7 @@ export const groupByProcessor = (options: InfraProcesorRequestOptions) => { return (doc: InfraESSearchBody) => { const result = cloneDeep(doc); const { groupBy } = options.nodeOptions; - let aggs = {}; + let aggs = get(result, 'aggs.waffle.aggs.nodes.aggs', {}); set(result, 'aggs.waffle.aggs.nodes.aggs', aggs); groupBy.forEach((grouping: InfraPathInput, index: number) => { if (isGroupByTerms(grouping)) { @@ -49,7 +49,7 @@ export const groupByProcessor = (options: InfraProcesorRequestOptions) => { ), }, }; - set(aggs, `${grouping.id}`, filtersAgg); + set(aggs, `path_${index}`, filtersAgg); aggs = filtersAgg.aggs; } }); diff --git a/x-pack/plugins/infra/server/lib/adapters/nodes/processors/common/nodes_processor.ts b/x-pack/plugins/infra/server/lib/adapters/nodes/processors/common/nodes_processor.ts index b161e4b04b50..cf416346df28 100644 --- a/x-pack/plugins/infra/server/lib/adapters/nodes/processors/common/nodes_processor.ts +++ b/x-pack/plugins/infra/server/lib/adapters/nodes/processors/common/nodes_processor.ts @@ -7,7 +7,11 @@ import { cloneDeep, set } from 'lodash'; import { InfraESSearchBody, InfraNodeType, InfraProcesorRequestOptions } from '../../adapter_types'; -import { NODE_REQUEST_PARTITION_FACTOR, NODE_REQUEST_PARTITION_SIZE } from '../../constants'; +import { + NAME_FIELDS, + NODE_REQUEST_PARTITION_FACTOR, + NODE_REQUEST_PARTITION_SIZE, +} from '../../constants'; const nodeTypeToField = (options: InfraProcesorRequestOptions): string => { const { fields } = options.nodeOptions.sourceConfiguration; @@ -22,6 +26,7 @@ const nodeTypeToField = (options: InfraProcesorRequestOptions): string => { }; export const nodesProcessor = (options: InfraProcesorRequestOptions) => { + const { fields } = options.nodeOptions.sourceConfiguration; return (doc: InfraESSearchBody) => { const result = cloneDeep(doc); const field = nodeTypeToField(options); @@ -35,6 +40,16 @@ export const nodesProcessor = (options: InfraProcesorRequestOptions) => { order: { _key: 'asc' }, size: NODE_REQUEST_PARTITION_SIZE * NODE_REQUEST_PARTITION_FACTOR, }); + + set(result, 'aggs.waffle.aggs.nodes.aggs', { + nodeDetails: { + top_hits: { + size: 1, + _source: { includes: [NAME_FIELDS[options.nodeType]] }, + sort: [{ [fields.timestamp]: { order: 'desc' } }], + }, + }, + }); return result; }; }; diff --git a/x-pack/plugins/infra/server/lib/adapters/sources/configuration_sources_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/sources/configuration_sources_adapter.ts index 4b8956b5f998..4870def3a87d 100644 --- a/x-pack/plugins/infra/server/lib/adapters/sources/configuration_sources_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/sources/configuration_sources_adapter.ts @@ -49,10 +49,10 @@ export class InfraConfigurationSourcesAdapter implements InfraSourcesAdapter { } const DEFAULT_FIELDS = { - container: 'docker.container.name', - host: 'beat.hostname', + container: 'docker.container.id', + host: 'host.name', message: ['message', '@message'], - pod: 'kubernetes.pod.name', + pod: 'kubernetes.pod.uid', tiebreaker: '_doc', timestamp: '@timestamp', }; diff --git a/x-pack/plugins/infra/server/lib/domains/metadata_domain/metadata_domain.ts b/x-pack/plugins/infra/server/lib/domains/metadata_domain/metadata_domain.ts index 9453061f590e..5c30a7189a8b 100644 --- a/x-pack/plugins/infra/server/lib/domains/metadata_domain/metadata_domain.ts +++ b/x-pack/plugins/infra/server/lib/domains/metadata_domain/metadata_domain.ts @@ -17,30 +17,32 @@ export class InfraMetadataDomain { public async getMetadata( req: InfraFrameworkRequest, sourceId: string, - nodeName: string, + nodeId: string, nodeType: string ) { const sourceConfiguration = await this.libs.sources.getConfiguration(sourceId); const metricsPromise = this.adapter.getMetricMetadata( req, sourceConfiguration, - nodeName, + nodeId, nodeType ); - const logsPromise = this.adapter.getLogMetadata(req, sourceConfiguration, nodeName, nodeType); + const logsPromise = this.adapter.getLogMetadata(req, sourceConfiguration, nodeId, nodeType); const metrics = await metricsPromise; const logs = await logsPromise; - const metricMetadata = pickMetadata(metrics).map(entry => { + const metricMetadata = pickMetadata(metrics.buckets).map(entry => { return { name: entry, source: 'metrics' }; }); - const logMetadata = pickMetadata(logs).map(entry => { + const logMetadata = pickMetadata(logs.buckets).map(entry => { return { name: entry, source: 'logs' }; }); - return metricMetadata.concat(logMetadata); + const id = metrics.id || logs.id; + const name = metrics.name || logs.name || id; + return { id, name, features: metricMetadata.concat(logMetadata) }; } } diff --git a/x-pack/test/api_integration/apis/infra/metadata.ts b/x-pack/test/api_integration/apis/infra/metadata.ts index 4714fd7f60b0..15289a15b700 100644 --- a/x-pack/test/api_integration/apis/infra/metadata.ts +++ b/x-pack/test/api_integration/apis/infra/metadata.ts @@ -30,7 +30,12 @@ const metadataTests: KbnTestProvider = ({ getService }) => { }) .then(resp => { const metadata = resp.data.source.metadataByNode; - expect(metadata.length).to.be(14); + if (metadata) { + expect(metadata.features.length).to.be(14); + expect(metadata.name).to.equal('demo-stack-nginx-01'); + } else { + throw new Error('Metadata should never be empty'); + } }); }); }); diff --git a/x-pack/test/api_integration/apis/infra/sources.ts b/x-pack/test/api_integration/apis/infra/sources.ts index a3822c6b72ff..2c7820e8a277 100644 --- a/x-pack/test/api_integration/apis/infra/sources.ts +++ b/x-pack/test/api_integration/apis/infra/sources.ts @@ -33,9 +33,9 @@ const sourcesTests: KbnTestProvider = ({ getService }) => { // shipped default values expect(sourceConfiguration.metricAlias).to.be('metricbeat-*'); expect(sourceConfiguration.logAlias).to.be('filebeat-*'); - expect(sourceConfiguration.fields.container).to.be('docker.container.name'); - expect(sourceConfiguration.fields.host).to.be('beat.hostname'); - expect(sourceConfiguration.fields.pod).to.be('kubernetes.pod.name'); + expect(sourceConfiguration.fields.container).to.be('docker.container.id'); + expect(sourceConfiguration.fields.host).to.be('host.name'); + expect(sourceConfiguration.fields.pod).to.be('kubernetes.pod.uid'); // test data in x-pack/test/functional/es_archives/infra/data.json.gz expect(sourceStatus.indexFields.length).to.be(1765);