Skip to content

Commit

Permalink
[Index Patterns] Use deprecation api for scripted fields (#100781)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dosant committed Jul 7, 2021
1 parent 186b936 commit 44d4d23
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/plugins/data/server/index_patterns/deprecations/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export { createScriptedFieldsDeprecationsConfig } from './scripted_fields';
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { hasScriptedField } from './scripted_fields';

describe('hasScriptedField', () => {
test('valid index pattern object with a scripted field', () => {
expect(
hasScriptedField({
title: 'kibana_sample_data_logs*',
fields:
'[{"count":0,"script":"return 5;","lang":"painless","name":"test","type":"number","scripted":true,"searchable":true,"aggregatable":true,"readFromDocValues":false,"customLabel":""}]',
})
).toBe(true);
});

test('valid index pattern object without a scripted field', () => {
expect(
hasScriptedField({
title: 'kibana_sample_data_logs*',
fields: '[]',
})
).toBe(false);
});

test('invalid index pattern object', () => {
expect(
hasScriptedField({
title: 'kibana_sample_data_logs*',
fields: '[...]',
})
).toBe(false);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import {
CoreSetup,
DeprecationsDetails,
GetDeprecationsContext,
RegisterDeprecationsConfig,
} from 'kibana/server';
import { IndexPatternAttributes } from '../../../common';

type IndexPatternAttributesWithFields = Pick<IndexPatternAttributes, 'title' | 'fields'>;

export const createScriptedFieldsDeprecationsConfig: (
core: CoreSetup
) => RegisterDeprecationsConfig = (core: CoreSetup) => ({
getDeprecations: async (context: GetDeprecationsContext): Promise<DeprecationsDetails[]> => {
const finder = context.savedObjectsClient.createPointInTimeFinder<IndexPatternAttributesWithFields>(
{
type: 'index-pattern',
perPage: 1000,
fields: ['title', 'fields'],
}
);

const indexPatternsWithScriptedFields: IndexPatternAttributesWithFields[] = [];
for await (const response of finder.find()) {
indexPatternsWithScriptedFields.push(
...response.saved_objects.map((so) => so.attributes).filter(hasScriptedField)
);
}

if (indexPatternsWithScriptedFields.length > 0) {
const PREVIEW_LIMIT = 3;
const indexPatternTitles = indexPatternsWithScriptedFields.map((ip) => ip.title);
const titlesPreview = indexPatternTitles.slice(0, PREVIEW_LIMIT).join('; ');
const allTitles = indexPatternTitles.join('; ');

return [
{
message: `You have ${indexPatternsWithScriptedFields.length} index patterns (${titlesPreview}...) that use scripted fields. Scripted fields are deprecated and will be removed in future. Use runtime fields instead.`,
documentationUrl:
'https://www.elastic.co/guide/en/elasticsearch/reference/7.x/runtime.html', // TODO: documentation service is not available serverside https://github.com/elastic/kibana/issues/95389
level: 'warning', // warning because it is not set in stone WHEN we remove scripted fields, hence this deprecation is not a blocker for 8.0 upgrade
correctiveActions: {
manualSteps: [
'Navigate to Stack Management > Kibana > Index Patterns.',
`Update ${indexPatternsWithScriptedFields.length} index patterns that have scripted fields to use runtime fields instead. In most cases, to migrate existing scripts, you'll need to change "return <value>;" to "emit(<value>);". Index patterns with at least one scripted field: ${allTitles}`,
],
},
},
];
} else {
return [];
}
},
});

export function hasScriptedField(indexPattern: IndexPatternAttributesWithFields) {
if (indexPattern.fields) {
try {
return JSON.parse(indexPattern.fields).some(
(field: { scripted?: boolean }) => field?.scripted
);
} catch (e) {
return false;
}
} else {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { UiSettingsServerToCommon } from './ui_settings_wrapper';
import { IndexPatternsApiServer } from './index_patterns_api_client';
import { SavedObjectsClientServerToCommon } from './saved_objects_client_wrapper';
import { registerIndexPatternsUsageCollector } from './register_index_pattern_usage_collection';
import { createScriptedFieldsDeprecationsConfig } from './deprecations';

export interface IndexPatternsServiceStart {
indexPatternsServiceFactory: (
Expand Down Expand Up @@ -88,6 +89,7 @@ export class IndexPatternsServiceProvider implements Plugin<void, IndexPatternsS

expressions.registerFunction(getIndexPatternLoad({ getStartServices: core.getStartServices }));
registerIndexPatternsUsageCollector(core.getStartServices, usageCollection);
core.deprecations.registerDeprecations(createScriptedFieldsDeprecationsConfig(core));
}

public start(core: CoreStart, { fieldFormats, logger }: IndexPatternsServiceStartDeps) {
Expand Down
15 changes: 15 additions & 0 deletions test/api_integration/apis/index_patterns/deprecations/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { FtrProviderContext } from '../../../ftr_provider_context';

export default function ({ loadTestFile }: FtrProviderContext) {
describe('scripted_fields_deprecations', () => {
loadTestFile(require.resolve('./scripted_fields'));
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import expect from '@kbn/expect';
import type { DeprecationsGetResponse } from 'src/core/server/types';
import { FtrProviderContext } from '../../../ftr_provider_context';

export default function ({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');

describe('scripted field deprecations', () => {
before(async () => {
await esArchiver.emptyKibanaIndex();
await esArchiver.load('test/api_integration/fixtures/es_archiver/index_patterns/basic_index');
});

after(async () => {
await esArchiver.unload(
'test/api_integration/fixtures/es_archiver/index_patterns/basic_index'
);
});

it('no scripted fields deprecations', async () => {
const { body } = await supertest.get('/api/deprecations/');

const { deprecations } = body as DeprecationsGetResponse;
const dataPluginDeprecations = deprecations.filter(({ domainId }) => domainId === 'data');

expect(dataPluginDeprecations.length).to.be(0);
});

it('scripted field deprecation', async () => {
const title = `basic_index`;
await supertest.post('/api/index_patterns/index_pattern').send({
index_pattern: {
title,
fields: {
foo: {
name: 'foo',
type: 'string',
scripted: true,
script: "doc['field_name'].value",
},
bar: {
name: 'bar',
type: 'number',
scripted: true,
script: "doc['field_name'].value",
},
},
},
});

const { body } = await supertest.get('/api/deprecations/');
const { deprecations } = body as DeprecationsGetResponse;
const dataPluginDeprecations = deprecations.filter(({ domainId }) => domainId === 'data');

expect(dataPluginDeprecations.length).to.be(1);
expect(dataPluginDeprecations[0].message).to.contain(title);
});
});
}
1 change: 1 addition & 0 deletions test/api_integration/apis/index_patterns/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ export default function ({ loadTestFile }) {
loadTestFile(require.resolve('./default_index_pattern'));
loadTestFile(require.resolve('./runtime_fields_crud'));
loadTestFile(require.resolve('./integration'));
loadTestFile(require.resolve('./deprecations'));
});
}

0 comments on commit 44d4d23

Please sign in to comment.