Skip to content

Commit

Permalink
[Lens] Use index pattern through service instead of reading saved obj…
Browse files Browse the repository at this point in the history
…ect (#84432)
  • Loading branch information
flash1293 committed Dec 2, 2020
1 parent 8981d0e commit 44c436b
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,8 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({
'{availableFields} available {availableFields, plural, one {field} other {fields}}. {emptyFields} empty {emptyFields, plural, one {field} other {fields}}. {metaFields} meta {metaFields, plural, one {field} other {fields}}.',
values: {
availableFields: fieldGroups.AvailableFields.fields.length,
emptyFields: fieldGroups.EmptyFields.fields.length,
// empty fields can be undefined if there is no existence information to be fetched
emptyFields: fieldGroups.EmptyFields?.fields.length || 0,
metaFields: fieldGroups.MetaFields.fields.length,
},
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,6 @@ import { IndexPatternField } from './types';
import { FieldItemSharedProps, FieldsAccordion } from './fields_accordion';
const PAGINATION_SIZE = 50;

export interface FieldsGroup {
specialFields: IndexPatternField[];
availableFields: IndexPatternField[];
emptyFields: IndexPatternField[];
metaFields: IndexPatternField[];
}

export type FieldGroups = Record<
string,
{
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/lens/server/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { Plugin, CoreSetup, CoreStart, PluginInitializerContext, Logger } from 'src/core/server';
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
import { Observable } from 'rxjs';
import { PluginStart as DataPluginStart } from 'src/plugins/data/server';
import { TaskManagerSetupContract, TaskManagerStartContract } from '../../task_manager/server';
import { setupRoutes } from './routes';
import {
Expand All @@ -23,6 +24,7 @@ export interface PluginSetupContract {

export interface PluginStartContract {
taskManager?: TaskManagerStartContract;
data: DataPluginStart;
}

export class LensServerPlugin implements Plugin<{}, {}, {}, {}> {
Expand Down
30 changes: 13 additions & 17 deletions x-pack/plugins/lens/server/routes/existing_fields.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { IndexPattern } from 'src/plugins/data/common';
import { existingFields, Field, buildFieldList } from './existing_fields';

describe('existingFields', () => {
Expand Down Expand Up @@ -71,25 +72,20 @@ describe('existingFields', () => {

describe('buildFieldList', () => {
const indexPattern = {
id: '',
type: 'indexpattern',
attributes: {
title: 'testpattern',
type: 'type',
typeMeta: 'typemeta',
fields: JSON.stringify([
{ name: 'foo', scripted: true, lang: 'painless', script: '2+2' },
{ name: 'bar' },
{ name: '@bar' },
{ name: 'baz' },
{ name: '_mymeta' },
]),
},
references: [],
title: 'testpattern',
type: 'type',
typeMeta: 'typemeta',
fields: [
{ name: 'foo', scripted: true, lang: 'painless', script: '2+2' },
{ name: 'bar' },
{ name: '@bar' },
{ name: 'baz' },
{ name: '_mymeta' },
],
};

it('supports scripted fields', () => {
const fields = buildFieldList(indexPattern, []);
const fields = buildFieldList((indexPattern as unknown) as IndexPattern, []);
expect(fields.find((f) => f.isScript)).toMatchObject({
isScript: true,
name: 'foo',
Expand All @@ -99,7 +95,7 @@ describe('buildFieldList', () => {
});

it('supports meta fields', () => {
const fields = buildFieldList(indexPattern, ['_mymeta']);
const fields = buildFieldList((indexPattern as unknown) as IndexPattern, ['_mymeta']);
expect(fields.find((f) => f.isMeta)).toMatchObject({
isScript: false,
isMeta: true,
Expand Down
71 changes: 30 additions & 41 deletions x-pack/plugins/lens/server/routes/existing_fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

import Boom from '@hapi/boom';
import { schema } from '@kbn/config-schema';
import { ILegacyScopedClusterClient, SavedObject, RequestHandlerContext } from 'src/core/server';
import { ILegacyScopedClusterClient, RequestHandlerContext } from 'src/core/server';
import { CoreSetup, Logger } from 'src/core/server';
import { IndexPattern, IndexPatternsService } from 'src/plugins/data/common';
import { BASE_API_URL } from '../../common';
import { IndexPatternAttributes, UI_SETTINGS } from '../../../../../src/plugins/data/server';
import { UI_SETTINGS } from '../../../../../src/plugins/data/server';
import { PluginStartContract } from '../plugin';

export function isBoomError(error: { isBoom?: boolean }): error is Boom {
return error.isBoom === true;
Expand All @@ -28,7 +30,7 @@ export interface Field {
script?: string;
}

export async function existingFieldsRoute(setup: CoreSetup, logger: Logger) {
export async function existingFieldsRoute(setup: CoreSetup<PluginStartContract>, logger: Logger) {
const router = setup.http.createRouter();

router.post(
Expand All @@ -47,11 +49,18 @@ export async function existingFieldsRoute(setup: CoreSetup, logger: Logger) {
},
},
async (context, req, res) => {
const [{ savedObjects, elasticsearch }, { data }] = await setup.getStartServices();
const savedObjectsClient = savedObjects.getScopedClient(req);
const esClient = elasticsearch.client.asScoped(req).asCurrentUser;
try {
return res.ok({
body: await fetchFieldExistence({
...req.params,
...req.body,
indexPatternsService: await data.indexPatterns.indexPatternsServiceFactory(
savedObjectsClient,
esClient
),
context,
}),
});
Expand Down Expand Up @@ -80,75 +89,55 @@ export async function existingFieldsRoute(setup: CoreSetup, logger: Logger) {
async function fetchFieldExistence({
context,
indexPatternId,
indexPatternsService,
dslQuery = { match_all: {} },
fromDate,
toDate,
timeFieldName,
}: {
indexPatternId: string;
context: RequestHandlerContext;
indexPatternsService: IndexPatternsService;
dslQuery: object;
fromDate?: string;
toDate?: string;
timeFieldName?: string;
}) {
const metaFields: string[] = await context.core.uiSettings.client.get(UI_SETTINGS.META_FIELDS);
const { indexPattern, indexPatternTitle } = await fetchIndexPatternDefinition(
indexPatternId,
context
);
const indexPattern = await indexPatternsService.get(indexPatternId);

const fields = buildFieldList(indexPattern, metaFields);
const docs = await fetchIndexPatternStats({
fromDate,
toDate,
dslQuery,
client: context.core.elasticsearch.legacy.client,
index: indexPatternTitle,
timeFieldName: timeFieldName || indexPattern.attributes.timeFieldName,
index: indexPattern.title,
timeFieldName: timeFieldName || indexPattern.timeFieldName,
fields,
});

return {
indexPatternTitle,
indexPatternTitle: indexPattern.title,
existingFieldNames: existingFields(docs, fields),
};
}

async function fetchIndexPatternDefinition(indexPatternId: string, context: RequestHandlerContext) {
const savedObjectsClient = context.core.savedObjects.client;
const indexPattern = await savedObjectsClient.get<IndexPatternAttributes>(
'index-pattern',
indexPatternId
);
const indexPatternTitle = indexPattern.attributes.title;

return {
indexPattern,
indexPatternTitle,
};
}

/**
* Exported only for unit tests.
*/
export function buildFieldList(
indexPattern: SavedObject<IndexPatternAttributes>,
metaFields: string[]
): Field[] {
return JSON.parse(indexPattern.attributes.fields).map(
(field: { name: string; lang: string; scripted?: boolean; script?: string }) => {
return {
name: field.name,
isScript: !!field.scripted,
lang: field.lang,
script: field.script,
// id is a special case - it doesn't show up in the meta field list,
// but as it's not part of source, it has to be handled separately.
isMeta: metaFields.includes(field.name) || field.name === '_id',
};
}
);
export function buildFieldList(indexPattern: IndexPattern, metaFields: string[]): Field[] {
return indexPattern.fields.map((field) => {
return {
name: field.name,
isScript: !!field.scripted,
lang: field.lang,
script: field.script,
// id is a special case - it doesn't show up in the meta field list,
// but as it's not part of source, it has to be handled separately.
isMeta: metaFields.includes(field.name) || field.name === '_id',
};
});
}

async function fetchIndexPatternStats({
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/lens/server/routes/field_stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import { CoreSetup } from 'src/core/server';
import { IFieldType } from 'src/plugins/data/common';
import { ESSearchResponse } from '../../../../typings/elasticsearch';
import { FieldStatsResponse, BASE_API_URL } from '../../common';
import { PluginStartContract } from '../plugin';

const SHARD_SIZE = 5000;

export async function initFieldsRoute(setup: CoreSetup) {
export async function initFieldsRoute(setup: CoreSetup<PluginStartContract>) {
const router = setup.http.createRouter();
router.post(
{
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/lens/server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
*/

import { CoreSetup, Logger } from 'src/core/server';
import { PluginStartContract } from '../plugin';
import { existingFieldsRoute } from './existing_fields';
import { initFieldsRoute } from './field_stats';
import { initLensUsageRoute } from './telemetry';

export function setupRoutes(setup: CoreSetup, logger: Logger) {
export function setupRoutes(setup: CoreSetup<PluginStartContract>, logger: Logger) {
existingFieldsRoute(setup, logger);
initFieldsRoute(setup);
initLensUsageRoute(setup);
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/lens/server/routes/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import Boom from '@hapi/boom';
import { CoreSetup } from 'src/core/server';
import { schema } from '@kbn/config-schema';
import { BASE_API_URL } from '../../common';
import { PluginStartContract } from '../plugin';

// This route is responsible for taking a batch of click events from the browser
// and writing them to saved objects
export async function initLensUsageRoute(setup: CoreSetup) {
export async function initLensUsageRoute(setup: CoreSetup<PluginStartContract>) {
const router = setup.http.createRouter();
router.post(
{
Expand Down
20 changes: 20 additions & 0 deletions x-pack/test/api_integration/apis/lens/existing_fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,26 +102,46 @@ const metricBeatData = [
'_id',
'_index',
'agent.ephemeral_id',
'agent.ephemeral_id.keyword',
'agent.hostname',
'agent.hostname.keyword',
'agent.id',
'agent.id.keyword',
'agent.type',
'agent.type.keyword',
'agent.version',
'agent.version.keyword',
'ecs.version',
'ecs.version.keyword',
'event.dataset',
'event.dataset.keyword',
'event.duration',
'event.module',
'event.module.keyword',
'host.architecture',
'host.architecture.keyword',
'host.hostname',
'host.hostname.keyword',
'host.id',
'host.id.keyword',
'host.name',
'host.name.keyword',
'host.os.build',
'host.os.build.keyword',
'host.os.family',
'host.os.family.keyword',
'host.os.kernel',
'host.os.kernel.keyword',
'host.os.name',
'host.os.name.keyword',
'host.os.platform',
'host.os.platform.keyword',
'host.os.version',
'host.os.version.keyword',
'metricset.name',
'metricset.name.keyword',
'service.type',
'service.type.keyword',
'system.cpu.cores',
'system.cpu.idle.pct',
'system.cpu.iowait.pct',
Expand Down

0 comments on commit 44c436b

Please sign in to comment.