[data / data views] Disable rollup functionality when rollup plugin is disabled (#162674)

## Summary

Rollup functionality will be disabled on serverless instances. The
`rollup` plugin will be disabled. While it won't be possible to create
rollups on serverless, it will be possible to import data view saved
objects which may be configured for use with rollups. We will make a
'best effort' to improve functionality as to help users transition away
from rollups.

- In classic environments, the `rollup` plugin will enable `dataViews`
and `data` plugin rollup functionality.
- The data plugin will run an async search instead of a rollup search.
- The data views plugin will fetch normal fields, omitting a query for
rollup fields - which would fail anyway.

Closes https://github.com/elastic/kibana/issues/152708

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Matthew Kime 2023-08-08 11:25:13 -05:00 committed by GitHub
parent 874801bf7e
commit a69870b950
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 252 additions and 115 deletions

View file

@ -28,7 +28,6 @@
],
"optionalPlugins": [
"usageCollection",
"taskManager",
"security"
],
"requiredBundles": [

View file

@ -12,10 +12,6 @@ import { BfetchServerSetup } from '@kbn/bfetch-plugin/server';
import { PluginStart as DataViewsServerPluginStart } from '@kbn/data-views-plugin/server';
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
import { FieldFormatsSetup, FieldFormatsStart } from '@kbn/field-formats-plugin/server';
import type {
TaskManagerSetupContract,
TaskManagerStartContract,
} from '@kbn/task-manager-plugin/server';
import type { SecurityPluginSetup } from '@kbn/security-plugin/server';
import { ConfigSchema } from '../config';
import type { ISearchSetup, ISearchStart } from './search';
@ -55,7 +51,6 @@ export interface DataPluginSetupDependencies {
expressions: ExpressionsServerSetup;
usageCollection?: UsageCollectionSetup;
fieldFormats: FieldFormatsSetup;
taskManager?: TaskManagerSetupContract;
security?: SecurityPluginSetup;
}
@ -63,7 +58,6 @@ export interface DataPluginStartDependencies {
fieldFormats: FieldFormatsStart;
logger: Logger;
dataViews: DataViewsServerPluginStart;
taskManager?: TaskManagerStartContract;
}
export class DataServerPlugin
@ -90,14 +84,7 @@ export class DataServerPlugin
public setup(
core: CoreSetup<DataPluginStartDependencies, DataPluginStart>,
{
bfetch,
expressions,
usageCollection,
fieldFormats,
taskManager,
security,
}: DataPluginSetupDependencies
{ bfetch, expressions, usageCollection, fieldFormats, security }: DataPluginSetupDependencies
) {
this.scriptsService.setup(core);
const querySetup = this.queryService.setup(core);
@ -110,7 +97,6 @@ export class DataServerPlugin
expressions,
usageCollection,
security,
taskManager,
});
return {
@ -120,14 +106,10 @@ export class DataServerPlugin
};
}
public start(
core: CoreStart,
{ fieldFormats, dataViews, taskManager }: DataPluginStartDependencies
) {
public start(core: CoreStart, { fieldFormats, dataViews }: DataPluginStartDependencies) {
const search = this.searchService.start(core, {
fieldFormats,
indexPatterns: dataViews,
taskManager,
});
const datatableUtilities = new DatatableUtilitiesService(
search.aggs,

View file

@ -17,6 +17,7 @@ export function createSearchSetupMock(): jest.Mocked<ISearchSetup> {
aggs: searchAggsSetupMock(),
registerSearchStrategy: jest.fn(),
searchSource: searchSourceMock.createSetupContract(),
enableRollups: jest.fn(),
};
}

View file

@ -25,10 +25,6 @@ import { ExpressionsServerSetup } from '@kbn/expressions-plugin/server';
import { FieldFormatsStart } from '@kbn/field-formats-plugin/server';
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
import { KbnServerError } from '@kbn/kibana-utils-plugin/server';
import type {
TaskManagerSetupContract,
TaskManagerStartContract,
} from '@kbn/task-manager-plugin/server';
import type { SecurityPluginSetup } from '@kbn/security-plugin/server';
import type { DataViewsServerPluginStart } from '@kbn/data-views-plugin/server';
import type {
@ -107,7 +103,6 @@ export interface SearchServiceSetupDependencies {
bfetch: BfetchServerSetup;
expressions: ExpressionsServerSetup;
usageCollection?: UsageCollectionSetup;
taskManager?: TaskManagerSetupContract;
security?: SecurityPluginSetup;
}
@ -115,7 +110,6 @@ export interface SearchServiceSetupDependencies {
export interface SearchServiceStartDependencies {
fieldFormats: FieldFormatsStart;
indexPatterns: DataViewsServerPluginStart;
taskManager?: TaskManagerStartContract;
}
/** @internal */
@ -131,6 +125,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
private sessionService: SearchSessionService;
private asScoped!: ISearchStart['asScoped'];
private searchAsInternalUser!: ISearchStrategy;
private rollupsEnabled: boolean = false;
constructor(
private initializerContext: PluginInitializerContext<ConfigSchema>,
@ -145,7 +140,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
public setup(
core: CoreSetup<DataPluginStartDependencies, DataPluginStart>,
{ bfetch, expressions, usageCollection, taskManager, security }: SearchServiceSetupDependencies
{ bfetch, expressions, usageCollection, security }: SearchServiceSetupDependencies
): ISearchSetup {
core.savedObjects.registerType(searchSessionSavedObjectType);
const usage = usageCollection ? usageProvider(core) : undefined;
@ -261,12 +256,13 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
registerSearchStrategy: this.registerSearchStrategy,
usage,
searchSource: this.searchSourceService.setup(),
enableRollups: () => (this.rollupsEnabled = true),
};
}
public start(
core: CoreStart,
{ fieldFormats, indexPatterns, taskManager }: SearchServiceStartDependencies
{ fieldFormats, indexPatterns }: SearchServiceStartDependencies
): ISearchStart {
const { elasticsearch, savedObjects, uiSettings } = core;
@ -278,7 +274,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
indexPatterns,
});
this.asScoped = this.asScopedProvider(core);
this.asScoped = this.asScopedProvider(core, this.rollupsEnabled);
return {
aggs,
searchAsInternalUser: this.searchAsInternalUser,
@ -516,7 +512,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
return deps.searchSessionsClient.extend(sessionId, expires);
};
private asScopedProvider = (core: CoreStart) => {
private asScopedProvider = (core: CoreStart, rollupsEnabled: boolean = false) => {
const { elasticsearch, savedObjects, uiSettings } = core;
const getSessionAsScoped = this.sessionService.asScopedProvider(core);
return (request: KibanaRequest): IScopedSearchClient => {
@ -530,6 +526,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
uiSettings.asScopedToClient(savedObjectsClient)
),
request,
rollupsEnabled,
};
return {
search: <

View file

@ -64,6 +64,7 @@ describe('ES search strategy', () => {
},
},
searchSessionsClient: createSearchSessionsClientMock(),
rollupsEnabled: true,
} as unknown as SearchStrategyDependencies;
const mockLegacyConfig$ = new BehaviorSubject<any>({
elasticsearch: {
@ -233,6 +234,31 @@ describe('ES search strategy', () => {
expect(method).toBe('POST');
expect(path).toBe('/foo-%E7%A8%8B/_rollup_search');
});
it("doesn't call the rollup API if the index is a rollup type BUT rollups are disabled", async () => {
mockApiCaller.mockResolvedValueOnce(mockRollupResponse);
mockSubmitCaller.mockResolvedValueOnce(mockAsyncResponse);
const params = { index: 'foo-程', body: { query: {} } };
const esSearch = await enhancedEsSearchStrategyProvider(
mockLegacyConfig$,
mockSearchConfig,
mockLogger
);
await esSearch
.search(
{
indexType: 'rollup',
params,
},
{},
{ ...mockDeps, rollupsEnabled: false }
)
.toPromise();
expect(mockApiCaller).toBeCalledTimes(0);
});
});
describe('with sessionId', () => {

View file

@ -154,7 +154,7 @@ export const enhancedEsSearchStrategyProvider = (
throw new KbnServerError('Unknown indexType', 400);
}
if (request.indexType === undefined) {
if (request.indexType === undefined || !deps.rollupsEnabled) {
return asyncSearch(request, options, deps);
} else {
return from(rollupSearch(request, options, deps));

View file

@ -35,6 +35,7 @@ export interface SearchStrategyDependencies {
uiSettingsClient: Pick<IUiSettingsClient, 'get'>;
searchSessionsClient: IScopedSearchSessionsClient;
request: KibanaRequest;
rollupsEnabled?: boolean;
}
export interface ISearchSetup {
@ -55,7 +56,7 @@ export interface ISearchSetup {
* Used internally for telemetry
*/
usage?: SearchUsage;
enableRollups: () => void;
searchSource: ReturnType<SearchSourceService['setup']>;
}

View file

@ -25,7 +25,6 @@
"@kbn/field-formats-plugin",
"@kbn/data-views-plugin",
"@kbn/screenshot-mode-plugin",
"@kbn/task-manager-plugin",
"@kbn/security-plugin",
"@kbn/expressions-plugin",
"@kbn/field-types",

View file

@ -25,6 +25,7 @@ interface DataViewsServiceFactoryDeps {
uiSettings: UiSettingsServiceStart;
fieldFormats: FieldFormatsStart;
capabilities: CoreStart['capabilities'];
rollupsEnabled: boolean;
}
/**
@ -38,14 +39,18 @@ export const dataViewsServiceFactory = (deps: DataViewsServiceFactoryDeps) =>
request?: KibanaRequest,
byPassCapabilities?: boolean
) {
const { logger, uiSettings, fieldFormats, capabilities } = deps;
const { logger, uiSettings, fieldFormats, capabilities, rollupsEnabled } = deps;
const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient);
const formats = await fieldFormats.fieldFormatServiceFactory(uiSettingsClient);
return new DataViewsService({
uiSettings: new UiSettingsServerToCommon(uiSettingsClient),
savedObjectsClient: new SavedObjectsClientWrapper(savedObjectsClient),
apiClient: new IndexPatternsApiServer(elasticsearchClient, savedObjectsClient),
apiClient: new IndexPatternsApiServer(
elasticsearchClient,
savedObjectsClient,
rollupsEnabled
),
fieldFormats: formats,
onError: (error) => {
logger.error(error);

View file

@ -10,6 +10,19 @@ import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { IndexPatternsFetcher } from '.';
import { elasticsearchServiceMock } from '@kbn/core/server/mocks';
const rollupResponse = {
foo: {
rollup_jobs: [
{
index_pattern: 'foo',
job_id: '123',
rollup_index: 'foo',
fields: [],
},
],
},
};
describe('Index Pattern Fetcher - server', () => {
let indexPatterns: IndexPatternsFetcher;
let esClient: ReturnType<typeof elasticsearchServiceMock.createElasticsearchClient>;
@ -21,12 +34,40 @@ describe('Index Pattern Fetcher - server', () => {
beforeEach(() => {
jest.clearAllMocks();
esClient = elasticsearchServiceMock.createElasticsearchClient();
indexPatterns = new IndexPatternsFetcher(esClient);
indexPatterns = new IndexPatternsFetcher(esClient, false, true);
});
it('calls fieldcaps once', async () => {
esClient.fieldCaps.mockResponse(response as unknown as estypes.FieldCapsResponse);
indexPatterns = new IndexPatternsFetcher(esClient, true);
indexPatterns = new IndexPatternsFetcher(esClient, true, true);
await indexPatterns.getFieldsForWildcard({ pattern: patternList });
expect(esClient.fieldCaps).toHaveBeenCalledTimes(1);
});
it('calls rollup api when given rollup data view', async () => {
esClient.fieldCaps.mockResponse(response as unknown as estypes.FieldCapsResponse);
esClient.rollup.getRollupIndexCaps.mockResponse(
rollupResponse as unknown as estypes.RollupGetRollupIndexCapsResponse
);
indexPatterns = new IndexPatternsFetcher(esClient, true, true);
await indexPatterns.getFieldsForWildcard({
pattern: patternList,
type: 'rollup',
rollupIndex: 'foo',
});
expect(esClient.rollup.getRollupIndexCaps).toHaveBeenCalledTimes(1);
});
it("doesn't call rollup api when given rollup data view and rollups are disabled", async () => {
esClient.fieldCaps.mockResponse(response as unknown as estypes.FieldCapsResponse);
esClient.rollup.getRollupIndexCaps.mockResponse(
rollupResponse as unknown as estypes.RollupGetRollupIndexCapsResponse
);
indexPatterns = new IndexPatternsFetcher(esClient, true, false);
await indexPatterns.getFieldsForWildcard({
pattern: patternList,
type: 'rollup',
rollupIndex: 'foo',
});
expect(esClient.rollup.getRollupIndexCaps).toHaveBeenCalledTimes(0);
});
});

View file

@ -40,10 +40,16 @@ interface FieldSubType {
export class IndexPatternsFetcher {
private elasticsearchClient: ElasticsearchClient;
private allowNoIndices: boolean;
private rollupsEnabled: boolean;
constructor(elasticsearchClient: ElasticsearchClient, allowNoIndices: boolean = false) {
constructor(
elasticsearchClient: ElasticsearchClient,
allowNoIndices: boolean = false,
rollupsEnabled: boolean = false
) {
this.elasticsearchClient = elasticsearchClient;
this.allowNoIndices = allowNoIndices;
this.rollupsEnabled = rollupsEnabled;
}
/**
@ -81,7 +87,7 @@ export class IndexPatternsFetcher {
fields: options.fields || ['*'],
});
if (type === 'rollup' && rollupIndex) {
if (this.rollupsEnabled && type === 'rollup' && rollupIndex) {
const rollupFields: FieldDescriptor[] = [];
const capabilityCheck = getCapabilitiesForRollupIndices(
await this.elasticsearchClient.rollup.getRollupIndexCaps({

View file

@ -10,6 +10,7 @@ export { getFieldByName, findIndexPatternById } from './utils';
export type { FieldDescriptor, RollupIndexCapability } from './fetcher';
export { IndexPatternsFetcher, getCapabilitiesForRollupIndices } from './fetcher';
export type {
DataViewsServerPluginSetup,
DataViewsServerPluginStart,
DataViewsServerPluginSetupDependencies,
DataViewsServerPluginStartDependencies,

View file

@ -16,7 +16,8 @@ export class IndexPatternsApiServer implements IDataViewsApiClient {
esClient: ElasticsearchClient;
constructor(
elasticsearchClient: ElasticsearchClient,
private readonly savedObjectsClient: SavedObjectsClientContract
private readonly savedObjectsClient: SavedObjectsClientContract,
private readonly rollupsEnabled: boolean
) {
this.esClient = elasticsearchClient;
}
@ -29,7 +30,11 @@ export class IndexPatternsApiServer implements IDataViewsApiClient {
indexFilter,
fields,
}: GetFieldsOptions) {
const indexPatterns = new IndexPatternsFetcher(this.esClient, allowNoIndex);
const indexPatterns = new IndexPatternsFetcher(
this.esClient,
allowNoIndex,
this.rollupsEnabled
);
return await indexPatterns
.getFieldsForWildcard({
pattern,

View file

@ -33,6 +33,7 @@ export class DataViewsServerPlugin
>
{
private readonly logger: Logger;
private rollupsEnabled: boolean = false;
constructor(initializerContext: PluginInitializerContext) {
this.logger = initializerContext.logger.get('dataView');
@ -46,7 +47,12 @@ export class DataViewsServerPlugin
core.capabilities.registerProvider(capabilitiesProvider);
const dataViewRestCounter = usageCollection?.createUsageCounter('dataViewsRestApi');
registerRoutes(core.http, core.getStartServices, dataViewRestCounter);
registerRoutes(
core.http,
core.getStartServices,
() => this.rollupsEnabled,
dataViewRestCounter
);
expressions.registerFunction(getIndexPatternLoad({ getStartServices: core.getStartServices }));
registerIndexPatternsUsageCollector(core.getStartServices, usageCollection);
@ -60,7 +66,9 @@ export class DataViewsServerPlugin
},
});
return {};
return {
enableRollups: () => (this.rollupsEnabled = true),
};
}
public start(
@ -72,6 +80,7 @@ export class DataViewsServerPlugin
uiSettings,
fieldFormats,
capabilities,
rollupsEnabled: this.rollupsEnabled,
});
return {

View file

@ -111,86 +111,93 @@ const validate: FullValidationConfig<any, any, any> = {
},
};
const handler: RequestHandler<{}, IQuery, IBody> = async (context, request, response) => {
const { asCurrentUser } = (await context.core).elasticsearch.client;
const indexPatterns = new IndexPatternsFetcher(asCurrentUser);
const {
pattern,
meta_fields: metaFields,
type,
rollup_index: rollupIndex,
allow_no_index: allowNoIndex,
include_unmapped: includeUnmapped,
} = request.query;
// not available to get request
const indexFilter = request.body?.index_filter;
let parsedFields: string[] = [];
let parsedMetaFields: string[] = [];
try {
parsedMetaFields = parseFields(metaFields);
parsedFields = parseFields(request.query.fields ?? []);
} catch (error) {
return response.badRequest();
}
try {
const { fields, indices } = await indexPatterns.getFieldsForWildcard({
const handler: (isRollupsEnabled: () => boolean) => RequestHandler<{}, IQuery, IBody> =
(isRollupsEnabled) => async (context, request, response) => {
const { asCurrentUser } = (await context.core).elasticsearch.client;
const indexPatterns = new IndexPatternsFetcher(asCurrentUser, undefined, isRollupsEnabled());
const {
pattern,
metaFields: parsedMetaFields,
meta_fields: metaFields,
type,
rollupIndex,
fieldCapsOptions: {
allow_no_indices: allowNoIndex || false,
includeUnmapped,
},
indexFilter,
...(parsedFields.length > 0 ? { fields: parsedFields } : {}),
});
rollup_index: rollupIndex,
allow_no_index: allowNoIndex,
include_unmapped: includeUnmapped,
} = request.query;
const body: { fields: FieldDescriptorRestResponse[]; indices: string[] } = { fields, indices };
// not available to get request
const indexFilter = request.body?.index_filter;
return response.ok({
body,
headers: {
'content-type': 'application/json',
},
});
} catch (error) {
if (
typeof error === 'object' &&
!!error?.isBoom &&
!!error?.output?.payload &&
typeof error?.output?.payload === 'object'
) {
const payload = error?.output?.payload;
return response.notFound({
body: {
message: payload.message,
attributes: payload,
let parsedFields: string[] = [];
let parsedMetaFields: string[] = [];
try {
parsedMetaFields = parseFields(metaFields);
parsedFields = parseFields(request.query.fields ?? []);
} catch (error) {
return response.badRequest();
}
try {
const { fields, indices } = await indexPatterns.getFieldsForWildcard({
pattern,
metaFields: parsedMetaFields,
type,
rollupIndex,
fieldCapsOptions: {
allow_no_indices: allowNoIndex || false,
includeUnmapped,
},
indexFilter,
...(parsedFields.length > 0 ? { fields: parsedFields } : {}),
});
const body: { fields: FieldDescriptorRestResponse[]; indices: string[] } = {
fields,
indices,
};
return response.ok({
body,
headers: {
'content-type': 'application/json',
},
});
} else {
return response.notFound();
} catch (error) {
if (
typeof error === 'object' &&
!!error?.isBoom &&
!!error?.output?.payload &&
typeof error?.output?.payload === 'object'
) {
const payload = error?.output?.payload;
return response.notFound({
body: {
message: payload.message,
attributes: payload,
},
});
} else {
return response.notFound();
}
}
}
};
};
export const registerFieldForWildcard = (
export const registerFieldForWildcard = async (
router: IRouter,
getStartServices: StartServicesAccessor<
DataViewsServerPluginStartDependencies,
DataViewsServerPluginStart
>
>,
isRollupsEnabled: () => boolean
) => {
const configuredHandler = handler(isRollupsEnabled);
// handler
router.versioned.put({ path, access }).addVersion({ version, validate }, handler);
router.versioned.post({ path, access }).addVersion({ version, validate }, handler);
router.versioned.put({ path, access }).addVersion({ version, validate }, configuredHandler);
router.versioned.post({ path, access }).addVersion({ version, validate }, configuredHandler);
router.versioned
.get({ path, access })
.addVersion(
{ version, validate: { request: { query: querySchema }, response: validate.response } },
handler
configuredHandler
);
};

View file

@ -20,12 +20,13 @@ export function registerRoutes(
DataViewsServerPluginStartDependencies,
DataViewsServerPluginStart
>,
isRollupsEnabled: () => boolean,
dataViewRestCounter?: UsageCounter
) {
const router = http.createRouter();
routes.forEach((route) => route(router, getStartServices, dataViewRestCounter));
registerFieldForWildcard(router, getStartServices);
registerFieldForWildcard(router, getStartServices, isRollupsEnabled);
registerHasDataViewsRoute(router);
}

View file

@ -53,8 +53,9 @@ export interface DataViewsServerPluginStart {
/**
* DataViews server plugin setup api
*/
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface DataViewsServerPluginSetup {}
export interface DataViewsServerPluginSetup {
enableRollups: () => void;
}
/**
* Data Views server setup dependencies

View file

@ -298,6 +298,7 @@ const createSearchStrategyDependenciesMock = (): SearchStrategyDependencies => (
savedObjectsClient: savedObjectsClientMock.create(),
searchSessionsClient: createSearchSessionsClientMock(),
request: httpServerMock.createKibanaRequest(),
rollupsEnabled: true,
});
// using the official data mock from within x-pack doesn't type-check successfully,

View file

@ -13,13 +13,14 @@
"requiredPlugins": [
"management",
"licensing",
"features"
"features",
"dataViews",
"data"
],
"optionalPlugins": [
"home",
"indexManagement",
"usageCollection",
"visTypeTimeseries"
"usageCollection"
],
"requiredBundles": [
"kibanaUtils",

View file

@ -30,8 +30,8 @@ export class RollupPlugin implements Plugin<void, void, any, any> {
}
public setup(
{ http, uiSettings, savedObjects, getStartServices }: CoreSetup,
{ features, licensing, indexManagement, visTypeTimeseries, usageCollection }: Dependencies
{ http, uiSettings, getStartServices }: CoreSetup,
{ features, licensing, indexManagement, usageCollection, dataViews, data }: Dependencies
) {
this.license.setup(
{
@ -103,6 +103,8 @@ export class RollupPlugin implements Plugin<void, void, any, any> {
if (indexManagement && indexManagement.indexDataEnricher) {
indexManagement.indexDataEnricher.add(rollupDataEnricher);
}
dataViews.enableRollups();
data.search.enableRollups();
}
start() {}

View file

@ -12,6 +12,8 @@ import { VisTypeTimeseriesSetup } from '@kbn/vis-type-timeseries-plugin/server';
import { getCapabilitiesForRollupIndices } from '@kbn/data-plugin/server';
import { IndexManagementPluginSetup } from '@kbn/index-management-plugin/server';
import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server';
import { DataViewsServerPluginSetup } from '@kbn/data-views-plugin/server';
import { PluginSetup as DataPluginSetup } from '@kbn/data-plugin/server';
import { LicensingPluginSetup } from '@kbn/licensing-plugin/server';
import { License } from './services';
import { IndexPatternsFetcher } from './shared_imports';
@ -24,6 +26,8 @@ export interface Dependencies {
usageCollection?: UsageCollectionSetup;
licensing: LicensingPluginSetup;
features: FeaturesPluginSetup;
dataViews: DataViewsServerPluginSetup;
data: DataPluginSetup;
}
export interface RouteDependencies {

View file

@ -32,6 +32,7 @@
"@kbn/i18n-react",
"@kbn/config-schema",
"@kbn/shared-ux-router",
"@kbn/data-views-plugin",
],
"exclude": [

View file

@ -12,5 +12,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./security_users'));
loadTestFile(require.resolve('./spaces'));
loadTestFile(require.resolve('./security_response_headers'));
loadTestFile(require.resolve('./rollups'));
});
}

View file

@ -0,0 +1,44 @@
/*
* 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 expect from 'expect';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { INITIAL_REST_VERSION_INTERNAL } from '@kbn/data-views-plugin/server/constants';
import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST } from '@kbn/core-http-common/src/constants';
import { FIELDS_FOR_WILDCARD_PATH as BASE_URI } from '@kbn/data-views-plugin/common/constants';
import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
describe('rollup data views - fields for wildcard', function () {
before(async () => {
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('returns 200 and best effort response despite lack of rollup support', async () => {
const response = await supertest
.get(BASE_URI)
.query({
pattern: 'basic_index',
type: 'rollup',
rollup_index: 'bar',
})
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'true');
expect(response.status).toBe(200);
expect(response.body.fields.length).toEqual(5);
});
});
}

View file

@ -44,5 +44,7 @@
"@kbn/fleet-plugin",
"@kbn/cases-plugin",
"@kbn/test-subj-selector",
"@kbn/core-http-common",
"@kbn/data-views-plugin",
]
}