mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[index patterns] Add pattern validation method to index patterns fetcher (#90170)
This commit is contained in:
parent
a7b46a975d
commit
fc516bacbd
6 changed files with 197 additions and 51 deletions
|
@ -22,4 +22,5 @@ export declare class IndexPatternsFetcher
|
|||
| --- | --- | --- |
|
||||
| [getFieldsForTimePattern(options)](./kibana-plugin-plugins-data-server.indexpatternsfetcher.getfieldsfortimepattern.md) | | Get a list of field objects for a time pattern |
|
||||
| [getFieldsForWildcard(options)](./kibana-plugin-plugins-data-server.indexpatternsfetcher.getfieldsforwildcard.md) | | Get a list of field objects for an index pattern that may contain wildcards |
|
||||
| [validatePatternListActive(patternList)](./kibana-plugin-plugins-data-server.indexpatternsfetcher.validatepatternlistactive.md) | | Returns an index pattern list of only those index pattern strings in the given list that return indices |
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IndexPatternsFetcher](./kibana-plugin-plugins-data-server.indexpatternsfetcher.md) > [validatePatternListActive](./kibana-plugin-plugins-data-server.indexpatternsfetcher.validatepatternlistactive.md)
|
||||
|
||||
## IndexPatternsFetcher.validatePatternListActive() method
|
||||
|
||||
Returns an index pattern list of only those index pattern strings in the given list that return indices
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
validatePatternListActive(patternList: string[]): Promise<string[]>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| patternList | <code>string[]</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`Promise<string[]>`
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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 { IndexPatternsFetcher } from '.';
|
||||
import { ElasticsearchClient } from 'kibana/server';
|
||||
import * as indexNotFoundException from '../../../common/search/test_data/index_not_found_exception.json';
|
||||
|
||||
describe('Index Pattern Fetcher - server', () => {
|
||||
let indexPatterns: IndexPatternsFetcher;
|
||||
let esClient: ElasticsearchClient;
|
||||
const emptyResponse = {
|
||||
body: {
|
||||
count: 0,
|
||||
},
|
||||
};
|
||||
const response = {
|
||||
body: {
|
||||
count: 1115,
|
||||
},
|
||||
};
|
||||
const patternList = ['a', 'b', 'c'];
|
||||
beforeEach(() => {
|
||||
esClient = ({
|
||||
count: jest.fn().mockResolvedValueOnce(emptyResponse).mockResolvedValue(response),
|
||||
} as unknown) as ElasticsearchClient;
|
||||
indexPatterns = new IndexPatternsFetcher(esClient);
|
||||
});
|
||||
|
||||
it('Removes pattern without matching indices', async () => {
|
||||
const result = await indexPatterns.validatePatternListActive(patternList);
|
||||
expect(result).toEqual(['b', 'c']);
|
||||
});
|
||||
|
||||
it('Returns all patterns when all match indices', async () => {
|
||||
esClient = ({
|
||||
count: jest.fn().mockResolvedValue(response),
|
||||
} as unknown) as ElasticsearchClient;
|
||||
indexPatterns = new IndexPatternsFetcher(esClient);
|
||||
const result = await indexPatterns.validatePatternListActive(patternList);
|
||||
expect(result).toEqual(patternList);
|
||||
});
|
||||
it('Removes pattern when "index_not_found_exception" error is thrown', async () => {
|
||||
class ServerError extends Error {
|
||||
public body?: Record<string, any>;
|
||||
constructor(
|
||||
message: string,
|
||||
public readonly statusCode: number,
|
||||
errBody?: Record<string, any>
|
||||
) {
|
||||
super(message);
|
||||
this.body = errBody;
|
||||
}
|
||||
}
|
||||
|
||||
esClient = ({
|
||||
count: jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce(response)
|
||||
.mockRejectedValue(
|
||||
new ServerError('index_not_found_exception', 404, indexNotFoundException)
|
||||
),
|
||||
} as unknown) as ElasticsearchClient;
|
||||
indexPatterns = new IndexPatternsFetcher(esClient);
|
||||
const result = await indexPatterns.validatePatternListActive(patternList);
|
||||
expect(result).toEqual([patternList[0]]);
|
||||
});
|
||||
});
|
|
@ -58,9 +58,16 @@ export class IndexPatternsFetcher {
|
|||
rollupIndex?: string;
|
||||
}): Promise<FieldDescriptor[]> {
|
||||
const { pattern, metaFields, fieldCapsOptions, type, rollupIndex } = options;
|
||||
const patternList = Array.isArray(pattern) ? pattern : pattern.split(',');
|
||||
let patternListActive: string[] = patternList;
|
||||
// if only one pattern, don't bother with validation. We let getFieldCapabilities fail if the single pattern is bad regardless
|
||||
if (patternList.length > 1) {
|
||||
patternListActive = await this.validatePatternListActive(patternList);
|
||||
}
|
||||
const fieldCapsResponse = await getFieldCapabilities(
|
||||
this.elasticsearchClient,
|
||||
pattern,
|
||||
// if none of the patterns are active, pass the original list to get an error
|
||||
patternListActive.length > 0 ? patternListActive : patternList,
|
||||
metaFields,
|
||||
{
|
||||
allow_no_indices: fieldCapsOptions
|
||||
|
@ -68,6 +75,7 @@ export class IndexPatternsFetcher {
|
|||
: this.allowNoIndices,
|
||||
}
|
||||
);
|
||||
|
||||
if (type === 'rollup' && rollupIndex) {
|
||||
const rollupFields: FieldDescriptor[] = [];
|
||||
const rollupIndexCapabilities = getCapabilitiesForRollupIndices(
|
||||
|
@ -118,4 +126,34 @@ export class IndexPatternsFetcher {
|
|||
}
|
||||
return await getFieldCapabilities(this.elasticsearchClient, indices, metaFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an index pattern list of only those index pattern strings in the given list that return indices
|
||||
*
|
||||
* @param patternList string[]
|
||||
* @return {Promise<string[]>}
|
||||
*/
|
||||
async validatePatternListActive(patternList: string[]) {
|
||||
const result = await Promise.all(
|
||||
patternList
|
||||
.map((pattern) =>
|
||||
this.elasticsearchClient.count({
|
||||
index: pattern,
|
||||
})
|
||||
)
|
||||
.map((p) =>
|
||||
p.catch((e) => {
|
||||
if (e.body.error.type === 'index_not_found_exception') {
|
||||
return { body: { count: 0 } };
|
||||
}
|
||||
throw e;
|
||||
})
|
||||
)
|
||||
);
|
||||
return result.reduce(
|
||||
(acc: string[], { body: { count } }, patternListIndex) =>
|
||||
count > 0 ? [...acc, patternList[patternListIndex]] : acc,
|
||||
[]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -885,6 +885,7 @@ export class IndexPatternsFetcher {
|
|||
type?: string;
|
||||
rollupIndex?: string;
|
||||
}): Promise<FieldDescriptor[]>;
|
||||
validatePatternListActive(patternList: string[]): Promise<string[]>;
|
||||
}
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "IndexPatternsServiceStart" needs to be exported by the entry point index.d.ts
|
||||
|
|
|
@ -17,6 +17,55 @@ export default function ({ getService }) {
|
|||
expect(resp.body.fields).to.eql(sortBy(resp.body.fields, 'name'));
|
||||
};
|
||||
|
||||
const testFields = [
|
||||
{
|
||||
type: 'boolean',
|
||||
esTypes: ['boolean'],
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
name: 'bar',
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
esTypes: ['text'],
|
||||
searchable: true,
|
||||
aggregatable: false,
|
||||
name: 'baz',
|
||||
readFromDocValues: false,
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
name: 'baz.keyword',
|
||||
readFromDocValues: true,
|
||||
subType: { multi: { parent: 'baz' } },
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
name: 'foo',
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
aggregatable: true,
|
||||
esTypes: ['keyword'],
|
||||
name: 'nestedField.child',
|
||||
readFromDocValues: true,
|
||||
searchable: true,
|
||||
subType: {
|
||||
nested: {
|
||||
path: 'nestedField',
|
||||
},
|
||||
},
|
||||
type: 'string',
|
||||
},
|
||||
];
|
||||
|
||||
describe('fields_for_wildcard_route response', () => {
|
||||
before(() => esArchiver.load('index_patterns/basic_index'));
|
||||
after(() => esArchiver.unload('index_patterns/basic_index'));
|
||||
|
@ -26,54 +75,7 @@ export default function ({ getService }) {
|
|||
.get('/api/index_patterns/_fields_for_wildcard')
|
||||
.query({ pattern: 'basic_index' })
|
||||
.expect(200, {
|
||||
fields: [
|
||||
{
|
||||
type: 'boolean',
|
||||
esTypes: ['boolean'],
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
name: 'bar',
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
esTypes: ['text'],
|
||||
searchable: true,
|
||||
aggregatable: false,
|
||||
name: 'baz',
|
||||
readFromDocValues: false,
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
name: 'baz.keyword',
|
||||
readFromDocValues: true,
|
||||
subType: { multi: { parent: 'baz' } },
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
name: 'foo',
|
||||
readFromDocValues: true,
|
||||
},
|
||||
{
|
||||
aggregatable: true,
|
||||
esTypes: ['keyword'],
|
||||
name: 'nestedField.child',
|
||||
readFromDocValues: true,
|
||||
searchable: true,
|
||||
subType: {
|
||||
nested: {
|
||||
path: 'nestedField',
|
||||
},
|
||||
},
|
||||
type: 'string',
|
||||
},
|
||||
],
|
||||
fields: testFields,
|
||||
})
|
||||
.then(ensureFieldsAreSorted);
|
||||
});
|
||||
|
@ -162,11 +164,19 @@ export default function ({ getService }) {
|
|||
.then(ensureFieldsAreSorted);
|
||||
});
|
||||
|
||||
it('returns 404 when the pattern does not exist', async () => {
|
||||
it('returns fields when one pattern exists and the other does not', async () => {
|
||||
await supertest
|
||||
.get('/api/index_patterns/_fields_for_wildcard')
|
||||
.query({ pattern: 'bad_index,basic_index' })
|
||||
.expect(200, {
|
||||
fields: testFields,
|
||||
});
|
||||
});
|
||||
it('returns 404 when no patterns exist', async () => {
|
||||
await supertest
|
||||
.get('/api/index_patterns/_fields_for_wildcard')
|
||||
.query({
|
||||
pattern: '[non-existing-pattern]its-invalid-*',
|
||||
pattern: 'bad_index',
|
||||
})
|
||||
.expect(404);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue