Data views, getExistingIndices method to server side (#168522)

This commit is contained in:
Steph Milovic 2023-10-16 14:19:50 -06:00 committed by GitHub
parent b61f570979
commit 91435a573f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 547 additions and 88 deletions

View file

@ -57,3 +57,9 @@ export const PLUGIN_NAME = 'DataViews';
* @public
*/
export const FIELDS_FOR_WILDCARD_PATH = '/internal/data_views/_fields_for_wildcard';
/**
* Existing indices path
* @public
*/
export const EXISTING_INDICES_PATH = '/internal/data_views/_existing_indices';

View file

@ -662,36 +662,4 @@ describe('IndexPatterns', () => {
expect(apiClient.getFieldsForWildcard.mock.calls[0][0].allowNoIndex).toBe(true);
});
});
describe('getExistingIndices', () => {
test('getExistingIndices returns the valid matched indices', async () => {
apiClient.getFieldsForWildcard = jest
.fn()
.mockResolvedValueOnce({ fields: ['length'] })
.mockResolvedValue({ fields: [] });
const patternList = await indexPatterns.getExistingIndices(['packetbeat-*', 'filebeat-*']);
expect(apiClient.getFieldsForWildcard).toBeCalledTimes(2);
expect(patternList.length).toBe(1);
});
test('getExistingIndices checks the positive pattern if provided with a negative pattern', async () => {
const mockFn = jest.fn().mockResolvedValue({ fields: ['length'] });
apiClient.getFieldsForWildcard = mockFn;
const patternList = await indexPatterns.getExistingIndices(['-filebeat-*', 'filebeat-*']);
expect(mockFn.mock.calls[0][0].pattern).toEqual('filebeat-*');
expect(mockFn.mock.calls[1][0].pattern).toEqual('filebeat-*');
expect(patternList).toEqual(['-filebeat-*', 'filebeat-*']);
});
test('getExistingIndices handles an error', async () => {
apiClient.getFieldsForWildcard = jest
.fn()
.mockImplementationOnce(async () => {
throw new DataViewMissingIndices('Catch me if you can!');
})
.mockImplementation(() => Promise.resolve({ fields: ['length'] }));
const patternList = await indexPatterns.getExistingIndices(['packetbeat-*', 'filebeat-*']);
expect(patternList).toEqual(['filebeat-*']);
});
});
});

View file

@ -7,12 +7,10 @@
*/
import { i18n } from '@kbn/i18n';
import { defer, from } from 'rxjs';
import type { PublicMethodsOf } from '@kbn/utility-types';
import { castEsToKbnFieldTypeName } from '@kbn/field-types';
import { FieldFormatsStartCommon, FORMATS_UI_SETTINGS } from '@kbn/field-formats-plugin/common';
import { v4 as uuidv4 } from 'uuid';
import { rateLimitingForkJoin } from './utils';
import { PersistenceAPI } from '../types';
import { createDataViewCache } from '.';
@ -240,12 +238,6 @@ export interface DataViewsServicePublicMethods {
* @param options - options for getting fields
*/
getFieldsForWildcard: (options: GetFieldsOptions) => Promise<FieldSpec[]>;
/**
* Get existing index pattern list by providing string array index pattern list.
* @param indices - index pattern list
* @returns index pattern list of index patterns that match indices
*/
getExistingIndices: (indices: string[]) => Promise<string[]>;
/**
* Get list of data view ids.
* @param refresh - clear cache and fetch from server
@ -524,41 +516,6 @@ export class DataViewsService {
return fields;
};
/**
* Get existing index pattern list by providing string array index pattern list.
* @param indices index pattern list
* @returns index pattern list
*/
getExistingIndices = async (indices: string[]): Promise<string[]> => {
const indicesObs = indices.map((pattern) => {
// when checking a negative pattern, check if the positive pattern exists
const indexToQuery = pattern.trim().startsWith('-')
? pattern.trim().substring(1)
: pattern.trim();
return defer(() =>
from(
this.getFieldsForWildcard({
// check one field to keep request fast/small
fields: ['_id'],
// true so no errors thrown in browser
allowNoIndex: true,
pattern: indexToQuery,
})
)
);
});
return new Promise<boolean[]>((resolve) => {
rateLimitingForkJoin(indicesObs, 3, []).subscribe((value) => {
resolve(value.map((v) => v.length > 0));
});
})
.then((allPatterns: boolean[]) =>
indices.filter((pattern, i, self) => self.indexOf(pattern) === i && allPatterns[i])
)
.catch(() => indices);
};
/**
* Get field list by providing an index patttern (or spec).
* @param options options for getting field list

View file

@ -319,6 +319,11 @@ export interface FieldsForWildcardResponse {
indices: string[];
}
/**
* Existing Indices response
*/
export type ExistingIndicesResponse = string[];
export interface IDataViewsApiClient {
getFieldsForWildcard: (options: GetFieldsOptions) => Promise<FieldsForWildcardResponse>;
hasUserDataView: () => Promise<boolean>;

View file

@ -6,11 +6,15 @@
* Side Public License, v 1.
*/
import { HttpStart } from '@kbn/core/public';
import { DataViewsService, MatchedItem } from '.';
import { DataViewsServiceDeps } from '../common/data_views/data_views';
import { HasDataService } from '../common';
import { ExistingIndicesResponse } from '../common/types';
import { EXISTING_INDICES_PATH } from '../common/constants';
/**
* Data Views public service dependencies
* @public
@ -32,6 +36,7 @@ export interface DataViewsServicePublicDeps extends DataViewsServiceDeps {
getRollupsEnabled: () => boolean;
scriptedFieldsEnabled: boolean;
http: HttpStart;
}
/**
@ -48,6 +53,7 @@ export class DataViewsServicePublic extends DataViewsService {
}) => Promise<MatchedItem[]>;
public hasData: HasDataService;
private rollupsEnabled: boolean = false;
private readonly http: HttpStart;
public readonly scriptedFieldsEnabled: boolean;
/**
@ -62,9 +68,22 @@ export class DataViewsServicePublic extends DataViewsService {
this.getIndices = deps.getIndices;
this.rollupsEnabled = deps.getRollupsEnabled();
this.scriptedFieldsEnabled = deps.scriptedFieldsEnabled;
this.http = deps.http;
}
getRollupsEnabled() {
return this.rollupsEnabled;
}
/**
* Get existing index pattern list by providing string array index pattern list.
* @param indices - index pattern list
* @returns index pattern list of index patterns that match indices
*/
async getExistingIndices(indices: string[]): Promise<ExistingIndicesResponse> {
return this.http.get<ExistingIndicesResponse>(EXISTING_INDICES_PATH, {
query: { indices },
version: '1',
});
}
}

View file

@ -88,6 +88,7 @@ export class DataViewsPublicPlugin
savedObjectsClient: new ContentMagementWrapper(contentManagement.client),
apiClient: new DataViewsApiClient(http),
fieldFormats,
http,
onNotification: (toastInputFields, key) => {
onNotifDebounced(key)(toastInputFields);
},

View file

@ -123,6 +123,12 @@ export interface DataViewsServicePublic extends DataViewsServicePublicMethods {
}) => Promise<MatchedItem[]>;
getRollupsEnabled: () => boolean;
scriptedFieldsEnabled: boolean;
/**
* Get existing index pattern list by providing string array index pattern list.
* @param indices - index pattern list
* @returns index pattern list of index patterns that match indices
*/
getExistingIndices: (indices: string[]) => Promise<string[]>;
}
export type DataViewsContract = DataViewsServicePublic;

View file

@ -9,6 +9,7 @@
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { IndexPatternsFetcher } from '.';
import { elasticsearchServiceMock } from '@kbn/core/server/mocks';
import { DataViewMissingIndices } from '../../common';
const rollupResponse = {
foo: {
@ -34,17 +35,16 @@ describe('Index Pattern Fetcher - server', () => {
beforeEach(() => {
jest.clearAllMocks();
esClient = elasticsearchServiceMock.createElasticsearchClient();
esClient.fieldCaps.mockResponse(response as unknown as estypes.FieldCapsResponse);
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, 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
);
@ -58,7 +58,6 @@ describe('Index Pattern Fetcher - server', () => {
});
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
);
@ -70,4 +69,39 @@ describe('Index Pattern Fetcher - server', () => {
});
expect(esClient.rollup.getRollupIndexCaps).toHaveBeenCalledTimes(0);
});
describe('getExistingIndices', () => {
test('getExistingIndices returns the valid matched indices', async () => {
indexPatterns = new IndexPatternsFetcher(esClient, true, true);
indexPatterns.getFieldsForWildcard = jest
.fn()
.mockResolvedValueOnce({ indices: ['length'] })
.mockResolvedValue({ indices: [] });
const result = await indexPatterns.getExistingIndices(['packetbeat-*', 'filebeat-*']);
expect(indexPatterns.getFieldsForWildcard).toBeCalledTimes(2);
expect(result.length).toBe(1);
});
test('getExistingIndices checks the positive pattern if provided with a negative pattern', async () => {
indexPatterns = new IndexPatternsFetcher(esClient, true, true);
const mockFn = jest.fn().mockResolvedValue({ indices: ['length'] });
indexPatterns.getFieldsForWildcard = mockFn;
const result = await indexPatterns.getExistingIndices(['-filebeat-*', 'filebeat-*']);
expect(mockFn.mock.calls[0][0].pattern).toEqual('filebeat-*');
expect(mockFn.mock.calls[1][0].pattern).toEqual('filebeat-*');
expect(result).toEqual(['-filebeat-*', 'filebeat-*']);
});
test('getExistingIndices handles an error', async () => {
indexPatterns = new IndexPatternsFetcher(esClient, true, true);
indexPatterns.getFieldsForWildcard = jest
.fn()
.mockImplementationOnce(async () => {
throw new DataViewMissingIndices('Catch me if you can!');
})
.mockImplementation(() => Promise.resolve({ indices: ['length'] }));
const result = await indexPatterns.getExistingIndices(['packetbeat-*', 'filebeat-*']);
expect(result).toEqual(['filebeat-*']);
});
});
});

View file

@ -9,6 +9,8 @@
import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { ElasticsearchClient } from '@kbn/core/server';
import { keyBy } from 'lodash';
import { defer, from } from 'rxjs';
import { rateLimitingForkJoin } from '../../common/data_views/utils';
import type { QueryDslQueryContainer } from '../../common/types';
import {
@ -117,4 +119,37 @@ export class IndexPatternsFetcher {
}
return fieldCapsResponse;
}
/**
* Get existing index pattern list by providing string array index pattern list.
* @param indices - index pattern list
* @returns index pattern list of index patterns that match indices
*/
async getExistingIndices(indices: string[]): Promise<string[]> {
const indicesObs = indices.map((pattern) => {
// when checking a negative pattern, check if the positive pattern exists
const indexToQuery = pattern.trim().startsWith('-')
? pattern.trim().substring(1)
: pattern.trim();
return defer(() =>
from(
this.getFieldsForWildcard({
// check one field to keep request fast/small
fields: ['_id'],
pattern: indexToQuery,
})
)
);
});
return new Promise<boolean[]>((resolve) => {
rateLimitingForkJoin(indicesObs, 3, { fields: [], indices: [] }).subscribe((value) => {
resolve(value.map((v) => v.indices.length > 0));
});
})
.then((allPatterns: boolean[]) =>
indices.filter((pattern, i, self) => self.indexOf(pattern) === i && allPatterns[i])
)
.catch(() => indices);
}
}

View file

@ -0,0 +1,53 @@
/*
* 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 { parseIndices } from './existing_indices';
describe('parseIndices', () => {
it('should return an array of indices when given an array of indices', () => {
const indices = ['index1', 'index2', 'index3'];
const result = parseIndices(indices);
expect(result).toEqual(indices);
});
it('should return an array of indices when given a JSON-stringified array of indices', () => {
const indices = '["index1", "index2", "index3"]';
const result = parseIndices(indices);
expect(result).toEqual(['index1', 'index2', 'index3']);
});
it('should return an array with a single index when given a single index name', () => {
const index = 'index1';
const result = parseIndices(index);
expect(result).toEqual(['index1']);
});
it('should throw an error when given an invalid JSON-stringified array', () => {
const indices = '["index1", "index2"';
expect(() => {
parseIndices(indices);
}).toThrowError(
'indices should be an array of index aliases, a JSON-stringified array of index aliases, or a single index alias'
);
});
it('should throw an error when given a string with a comma but not JSON-stringified', () => {
const indices = 'index1,index2';
expect(() => {
parseIndices(indices);
}).toThrowError(
'indices should be an array of index aliases, a JSON-stringified array of index aliases, or a single index alias'
);
});
it('should return an empty array when given an empty array', () => {
const indices: string[] = [];
const result = parseIndices(indices);
expect(result).toEqual([]);
});
});

View file

@ -0,0 +1,77 @@
/*
* 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 { IRouter, RequestHandler } from '@kbn/core/server';
import { schema } from '@kbn/config-schema';
import { INITIAL_REST_VERSION_INTERNAL as version } from '../../constants';
import { IndexPatternsFetcher } from '../..';
import { EXISTING_INDICES_PATH } from '../../../common/constants';
/**
* Accepts one of the following:
* 1. An array of field names
* 2. A JSON-stringified array of field names
* 3. A single field name (not comma-separated)
* @returns an array of indices
* @param indices
*/
export const parseIndices = (indices: string | string[]): string[] => {
if (Array.isArray(indices)) return indices;
try {
return JSON.parse(indices);
} catch (e) {
if (!indices.includes(',')) return [indices];
throw new Error(
'indices should be an array of index aliases, a JSON-stringified array of index aliases, or a single index alias'
);
}
};
export const handler: RequestHandler<{}, { indices: string | string[] }, string[]> = async (
ctx,
req,
res
) => {
const { indices } = req.query;
try {
const indexArray = parseIndices(indices);
const core = await ctx.core;
const elasticsearchClient = core.elasticsearch.client.asCurrentUser;
const indexPatterns = new IndexPatternsFetcher(elasticsearchClient, true);
const response: string[] = await indexPatterns.getExistingIndices(indexArray);
return res.ok({ body: response });
} catch (error) {
return res.badRequest();
}
};
export const registerExistingIndicesPath = (router: IRouter): void => {
router.versioned
.get({
path: EXISTING_INDICES_PATH,
access: 'internal',
})
.addVersion(
{
version,
validate: {
request: {
query: schema.object({
indices: schema.oneOf([schema.string(), schema.arrayOf(schema.string())]),
}),
},
response: {
200: {
body: schema.arrayOf(schema.string()),
},
},
},
},
handler
);
};

View file

@ -11,6 +11,7 @@ import { UsageCounter } from '@kbn/usage-collection-plugin/server';
import { routes } from './rest_api_routes/public';
import type { DataViewsServerPluginStart, DataViewsServerPluginStartDependencies } from './types';
import { registerExistingIndicesPath } from './rest_api_routes/internal/existing_indices';
import { registerFieldForWildcard } from './rest_api_routes/internal/fields_for';
import { registerHasDataViewsRoute } from './rest_api_routes/internal/has_data_views';
@ -27,6 +28,7 @@ export function registerRoutes(
routes.forEach((route) => route(router, getStartServices, dataViewRestCounter));
registerExistingIndicesPath(router);
registerFieldForWildcard(router, getStartServices, isRollupsEnabled);
registerHasDataViewsRoute(router);
}

View file

@ -0,0 +1,16 @@
/*
* 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('index_patterns/_existing_indices route', () => {
loadTestFile(require.resolve('./params'));
loadTestFile(require.resolve('./response'));
});
}

View file

@ -0,0 +1,79 @@
/*
* 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 { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { INITIAL_REST_VERSION_INTERNAL } from '@kbn/data-views-plugin/server/constants';
import { EXISTING_INDICES_PATH } from '@kbn/data-views-plugin/common/constants';
import { FtrProviderContext } from '../../../ftr_provider_context';
export default function ({ getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const supertest = getService('supertest');
const randomness = getService('randomness');
describe('_existing_indices params', () => {
before(() =>
esArchiver.load('test/api_integration/fixtures/es_archiver/index_patterns/basic_index')
);
after(() =>
esArchiver.unload('test/api_integration/fixtures/es_archiver/index_patterns/basic_index')
);
it('requires a query param', () =>
supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
.query({})
.expect(400));
it('accepts indices param as single index string', () =>
supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
.query({
indices: 'filebeat-*',
})
.expect(200));
it('accepts indices param as single index array', () =>
supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
.query({
indices: ['filebeat-*'],
})
.expect(200));
it('accepts indices param', () =>
supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
.query({
indices: ['filebeat-*', 'packetbeat-*'],
})
.expect(200));
it('rejects unexpected query params', () =>
supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
.query({
[randomness.word()]: randomness.word(),
})
.expect(400));
it('rejects a comma-separated list of indices', () =>
supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
.query({
indices: 'filebeat-*,packetbeat-*',
})
.expect(400));
});
}

View file

@ -0,0 +1,46 @@
/*
* 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 { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { INITIAL_REST_VERSION_INTERNAL } from '@kbn/data-views-plugin/server/constants';
import { EXISTING_INDICES_PATH } from '@kbn/data-views-plugin/common/constants';
import { FtrProviderContext } from '../../../ftr_provider_context';
export default function ({ getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const supertest = getService('supertest');
describe('_existing_indices response', () => {
before(() =>
esArchiver.load('test/api_integration/fixtures/es_archiver/index_patterns/basic_index')
);
after(() =>
esArchiver.unload('test/api_integration/fixtures/es_archiver/index_patterns/basic_index')
);
it('returns an array of existing indices', async () => {
await supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
.query({
indices: ['basic_index', 'bad_index'],
})
.expect(200, ['basic_index']);
});
it('returns an empty array when no indices exist', async () => {
await supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
.query({
indices: ['bad_index'],
})
.expect(200, []);
});
});
}

View file

@ -11,6 +11,7 @@ import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
describe('index_patterns', () => {
loadTestFile(require.resolve('./es_errors'));
loadTestFile(require.resolve('./existing_indices_route'));
loadTestFile(require.resolve('./fields_for_wildcard_route'));
loadTestFile(require.resolve('./data_views_crud'));
loadTestFile(require.resolve('./scripted_fields_crud'));

View file

@ -5,11 +5,8 @@
* 2.0.
*/
import type {
DataViewListItem,
DataViewsContract,
DataView as DataViewType,
} from '@kbn/data-views-plugin/common';
import type { DataViewListItem, DataView as DataViewType } from '@kbn/data-views-plugin/common';
import type { DataViewsServicePublic } from '@kbn/data-views-plugin/public/types';
import { transformError } from '@kbn/securitysolution-es-utils';
import { ensurePatternFormat } from '../../../../common/utils/sourcerer';
import type { KibanaDataView } from '../../store/sourcerer/model';
@ -21,7 +18,7 @@ export interface GetSourcererDataView {
body: {
patternList: string[];
};
dataViewService: DataViewsContract;
dataViewService: DataViewsServicePublic;
dataViewId: string | null;
}

View file

@ -6,7 +6,7 @@
*/
import { getSourcererDataView } from './get_sourcerer_data_view';
import type { DataViewsService } from '@kbn/data-views-plugin/common';
import type { DataViewsServicePublic } from '@kbn/data-views-plugin/public/types';
const dataViewId = 'test-id';
const dataViewsService = {
@ -20,7 +20,7 @@ const dataViewsService = {
fields: {},
}),
getExistingIndices: jest.fn().mockResolvedValue(['test-pattern']),
} as unknown as jest.Mocked<DataViewsService>;
} as unknown as jest.Mocked<DataViewsServicePublic>;
describe('getSourcererDataView', () => {
beforeEach(() => {
jest.clearAllMocks();

View file

@ -5,14 +5,14 @@
* 2.0.
*/
import type { DataViewsContract } from '@kbn/data-views-plugin/common';
import type { DataViewsServicePublic } from '@kbn/data-views-plugin/public/types';
import { ensurePatternFormat } from '../../../../common/utils/sourcerer';
import type { SourcererDataView, RunTimeMappings } from '../../store/sourcerer/model';
import { getDataViewStateFromIndexFields } from '../source/use_data_view';
export const getSourcererDataView = async (
dataViewId: string,
dataViewsService: DataViewsContract,
dataViewsService: DataViewsServicePublic,
refreshFields = false
): Promise<SourcererDataView> => {
const dataView = await dataViewsService.get(dataViewId, true, refreshFields);

View file

@ -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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { FtrProviderContext } from '../../../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
describe('index_patterns/_existing_indices route', () => {
loadTestFile(require.resolve('./params'));
loadTestFile(require.resolve('./response'));
});
}

View file

@ -0,0 +1,91 @@
/*
* 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 { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { INITIAL_REST_VERSION_INTERNAL } from '@kbn/data-views-plugin/server/constants';
import { EXISTING_INDICES_PATH } from '@kbn/data-views-plugin/common/constants';
import type { FtrProviderContext } from '../../../../ftr_provider_context';
export default function ({ getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const supertest = getService('supertest');
const randomness = getService('randomness');
const svlCommonApi = getService('svlCommonApi');
describe('_existing_indices params', () => {
before(() =>
esArchiver.load('test/api_integration/fixtures/es_archiver/index_patterns/basic_index')
);
after(() =>
esArchiver.unload('test/api_integration/fixtures/es_archiver/index_patterns/basic_index')
);
it('requires a query param', () =>
supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
// TODO: API requests in Serverless require internal request headers
.set(svlCommonApi.getInternalRequestHeader())
.query({})
.expect(400));
it('accepts indices param as single index string', () =>
supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
// TODO: API requests in Serverless require internal request headers
.set(svlCommonApi.getInternalRequestHeader())
.query({
indices: 'filebeat-*',
})
.expect(200));
it('accepts indices param as single index array', () =>
supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
// TODO: API requests in Serverless require internal request headers
.set(svlCommonApi.getInternalRequestHeader())
.query({
indices: ['filebeat-*'],
})
.expect(200));
it('accepts indices param', () =>
supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
// TODO: API requests in Serverless require internal request headers
.set(svlCommonApi.getInternalRequestHeader())
.query({
indices: ['filebeat-*', 'packetbeat-*'],
})
.expect(200));
it('rejects unexpected query params', () =>
supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
// TODO: API requests in Serverless require internal request headers
.set(svlCommonApi.getInternalRequestHeader())
.query({
[randomness.word()]: randomness.word(),
})
.expect(400));
it('rejects a comma-separated list of indices', () =>
supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
// TODO: API requests in Serverless require internal request headers
.set(svlCommonApi.getInternalRequestHeader())
.query({
indices: 'filebeat-*,packetbeat-*',
})
.expect(400));
});
}

View file

@ -0,0 +1,50 @@
/*
* 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 { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { INITIAL_REST_VERSION_INTERNAL } from '@kbn/data-views-plugin/server/constants';
import { EXISTING_INDICES_PATH } from '@kbn/data-views-plugin/common/constants';
import type { FtrProviderContext } from '../../../../ftr_provider_context';
export default function ({ getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const supertest = getService('supertest');
const svlCommonApi = getService('svlCommonApi');
describe('_existing_indices response', () => {
before(() =>
esArchiver.load('test/api_integration/fixtures/es_archiver/index_patterns/basic_index')
);
after(() =>
esArchiver.unload('test/api_integration/fixtures/es_archiver/index_patterns/basic_index')
);
it('returns an array of existing indices', async () => {
await supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
// TODO: API requests in Serverless require internal request headers
.set(svlCommonApi.getInternalRequestHeader())
.query({
indices: ['basic_index', 'bad_index'],
})
.expect(200, ['basic_index']);
});
it('returns an empty array when no indices exist', async () => {
await supertest
.get(EXISTING_INDICES_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
// TODO: API requests in Serverless require internal request headers
.set(svlCommonApi.getInternalRequestHeader())
.query({
indices: ['bad_index'],
})
.expect(200, []);
});
});
}

View file

@ -12,6 +12,7 @@ export default function ({ loadTestFile }: FtrProviderContext) {
this.tags(['esGate']);
loadTestFile(require.resolve('./es_errors'));
loadTestFile(require.resolve('./existing_indices_route'));
loadTestFile(require.resolve('./fields_for_wildcard_route'));
loadTestFile(require.resolve('./data_views_crud'));
// TODO: Removed `scripted_fields_crud` since