[Event Log][8.0] Set all event log index assets to hidden (#110929)

* Setting event log indices to hidden

* Cleaning up cluster client and adding unit tests

* Unit tests

* Unit tests

* Unit tests

* Unit tests

* PR feedback

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
ymao1 2021-09-09 12:14:39 -04:00 committed by GitHub
parent 7ae423c5bb
commit 604a745de0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 875 additions and 24 deletions

View file

@ -17,6 +17,12 @@ const createClusterClientMock = () => {
createIndexTemplate: jest.fn(),
doesAliasExist: jest.fn(),
createIndex: jest.fn(),
getExistingLegacyIndexTemplates: jest.fn(),
setLegacyIndexTemplateToHidden: jest.fn(),
getExistingIndices: jest.fn(),
setIndexToHidden: jest.fn(),
getExistingIndexAliases: jest.fn(),
setIndexAliasToHidden: jest.fn(),
queryEventsBySavedObjects: jest.fn(),
shutdown: jest.fn(),
};

View file

@ -16,7 +16,7 @@ import { findOptionsSchema } from '../event_log_client';
import { delay } from '../lib/delay';
import { times } from 'lodash';
import { DeeplyMockedKeys } from '@kbn/utility-types/jest';
import { RequestEvent } from '@elastic/elasticsearch';
import { estypes, RequestEvent } from '@elastic/elasticsearch';
type MockedLogger = ReturnType<typeof loggingSystemMock['createLogger']>;
@ -215,22 +215,39 @@ describe('doesIndexTemplateExist', () => {
});
});
test('should return true when call cluster returns true', async () => {
test('should return true when call cluster to legacy template API returns true', async () => {
clusterClient.indices.existsTemplate.mockResolvedValue(asApiResponse(true));
clusterClient.indices.existsIndexTemplate.mockResolvedValue(asApiResponse(false));
await expect(clusterClientAdapter.doesIndexTemplateExist('foo')).resolves.toEqual(true);
});
test('should return false when call cluster returns false', async () => {
test('should return true when call cluster to index template API returns true', async () => {
clusterClient.indices.existsTemplate.mockResolvedValue(asApiResponse(false));
clusterClient.indices.existsIndexTemplate.mockResolvedValue(asApiResponse(true));
await expect(clusterClientAdapter.doesIndexTemplateExist('foo')).resolves.toEqual(true);
});
test('should return false when both call cluster calls returns false', async () => {
clusterClient.indices.existsTemplate.mockResolvedValue(asApiResponse(false));
clusterClient.indices.existsIndexTemplate.mockResolvedValue(asApiResponse(false));
await expect(clusterClientAdapter.doesIndexTemplateExist('foo')).resolves.toEqual(false);
});
test('should throw error when call cluster throws an error', async () => {
test('should throw error when call cluster to legacy template API throws an error', async () => {
clusterClient.indices.existsTemplate.mockRejectedValue(new Error('Fail'));
await expect(
clusterClientAdapter.doesIndexTemplateExist('foo')
).rejects.toThrowErrorMatchingInlineSnapshot(
`"error checking existance of index template: Fail"`
`"error checking existence of index template: Fail"`
);
});
test('should throw error when call cluster to index template API throws an error', async () => {
clusterClient.indices.existsIndexTemplate.mockRejectedValue(new Error('Fail'));
await expect(
clusterClientAdapter.doesIndexTemplateExist('foo')
).rejects.toThrowErrorMatchingInlineSnapshot(
`"error checking existence of index template: Fail"`
);
});
});
@ -238,7 +255,7 @@ describe('doesIndexTemplateExist', () => {
describe('createIndexTemplate', () => {
test('should call cluster with given template', async () => {
await clusterClientAdapter.createIndexTemplate('foo', { args: true });
expect(clusterClient.indices.putTemplate).toHaveBeenCalledWith({
expect(clusterClient.indices.putIndexTemplate).toHaveBeenCalledWith({
name: 'foo',
create: true,
body: { args: true },
@ -246,20 +263,274 @@ describe('createIndexTemplate', () => {
});
test(`should throw error if index template still doesn't exist after error is thrown`, async () => {
clusterClient.indices.putTemplate.mockRejectedValueOnce(new Error('Fail'));
clusterClient.indices.putIndexTemplate.mockRejectedValueOnce(new Error('Fail'));
clusterClient.indices.existsTemplate.mockResolvedValueOnce(asApiResponse(false));
clusterClient.indices.existsIndexTemplate.mockResolvedValueOnce(asApiResponse(false));
await expect(
clusterClientAdapter.createIndexTemplate('foo', { args: true })
).rejects.toThrowErrorMatchingInlineSnapshot(`"error creating index template: Fail"`);
});
test('should not throw error if index template exists after error is thrown', async () => {
clusterClient.indices.putTemplate.mockRejectedValueOnce(new Error('Fail'));
clusterClient.indices.putIndexTemplate.mockRejectedValueOnce(new Error('Fail'));
clusterClient.indices.existsTemplate.mockResolvedValueOnce(asApiResponse(true));
await clusterClientAdapter.createIndexTemplate('foo', { args: true });
});
});
describe('getExistingLegacyIndexTemplates', () => {
test('should call cluster with given index template pattern', async () => {
await clusterClientAdapter.getExistingLegacyIndexTemplates('foo*');
expect(clusterClient.indices.getTemplate).toHaveBeenCalledWith(
{
name: 'foo*',
},
{ ignore: [404] }
);
});
test('should return templates when found', async () => {
const response = {
'foo-bar-template': {
order: 0,
index_patterns: ['foo-bar-*'],
settings: { index: { number_of_shards: '1' } },
mappings: { dynamic: false, properties: {} },
aliases: {},
},
};
clusterClient.indices.getTemplate.mockResolvedValue(
asApiResponse<estypes.IndicesGetTemplateResponse>(response)
);
await expect(clusterClientAdapter.getExistingLegacyIndexTemplates('foo*')).resolves.toEqual(
response
);
});
test('should throw error when call cluster throws an error', async () => {
clusterClient.indices.getTemplate.mockRejectedValue(new Error('Fail'));
await expect(
clusterClientAdapter.getExistingLegacyIndexTemplates('foo*')
).rejects.toThrowErrorMatchingInlineSnapshot(
`"error getting existing legacy index templates: Fail"`
);
});
});
describe('setLegacyIndexTemplateToHidden', () => {
test('should call cluster with given index template name and template', async () => {
const currentTemplate = {
order: 0,
index_patterns: ['foo-bar-*'],
settings: { index: { number_of_shards: '1' } },
mappings: { dynamic: false, properties: {} },
aliases: {},
};
await clusterClientAdapter.setLegacyIndexTemplateToHidden('foo-bar-template', currentTemplate);
expect(clusterClient.indices.putTemplate).toHaveBeenCalledWith({
name: 'foo-bar-template',
body: {
order: 0,
index_patterns: ['foo-bar-*'],
settings: { index: { number_of_shards: '1' }, 'index.hidden': true },
mappings: { dynamic: false, properties: {} },
aliases: {},
},
});
});
test('should throw error when call cluster throws an error', async () => {
clusterClient.indices.putTemplate.mockRejectedValue(new Error('Fail'));
await expect(
clusterClientAdapter.setLegacyIndexTemplateToHidden('foo-bar-template', {
aliases: {},
index_patterns: [],
mappings: {},
order: 0,
settings: {},
})
).rejects.toThrowErrorMatchingInlineSnapshot(
`"error setting existing legacy index template foo-bar-template to hidden: Fail"`
);
});
});
describe('getExistingIndices', () => {
test('should call cluster with given index pattern', async () => {
await clusterClientAdapter.getExistingIndices('foo*');
expect(clusterClient.indices.getSettings).toHaveBeenCalledWith(
{
index: 'foo*',
},
{ ignore: [404] }
);
});
test('should return indices when found', async () => {
const response = {
'foo-bar-000001': {
settings: {
index: {
number_of_shards: 1,
uuid: 'Ure4d9edQbCMtcmyy0ObrA',
},
},
},
};
clusterClient.indices.getSettings.mockResolvedValue(
asApiResponse<estypes.IndicesGetSettingsResponse>(response)
);
await expect(clusterClientAdapter.getExistingIndices('foo*')).resolves.toEqual(response);
});
test('should throw error when call cluster throws an error', async () => {
clusterClient.indices.getSettings.mockRejectedValue(new Error('Fail'));
await expect(
clusterClientAdapter.getExistingIndices('foo*')
).rejects.toThrowErrorMatchingInlineSnapshot(
`"error getting existing indices matching pattern foo*: Fail"`
);
});
});
describe('setIndexToHidden', () => {
test('should call cluster with given index name', async () => {
await clusterClientAdapter.setIndexToHidden('foo-bar-000001');
expect(clusterClient.indices.putSettings).toHaveBeenCalledWith({
index: 'foo-bar-000001',
body: {
settings: {
'index.hidden': true,
},
},
});
});
test('should throw error when call cluster throws an error', async () => {
clusterClient.indices.putSettings.mockRejectedValue(new Error('Fail'));
await expect(
clusterClientAdapter.setIndexToHidden('foo-bar-000001')
).rejects.toThrowErrorMatchingInlineSnapshot(
`"error setting existing index foo-bar-000001 to hidden: Fail"`
);
});
});
describe('getExistingIndexAliases', () => {
test('should call cluster with given index pattern', async () => {
await clusterClientAdapter.getExistingIndexAliases('foo*');
expect(clusterClient.indices.getAlias).toHaveBeenCalledWith(
{
index: 'foo*',
},
{ ignore: [404] }
);
});
test('should return aliases when found', async () => {
const response = {
'foo-bar-000001': {
aliases: {
'foo-bar': {
is_write_index: true,
},
},
},
};
clusterClient.indices.getAlias.mockResolvedValue(
asApiResponse<estypes.IndicesGetAliasResponse>(response)
);
await expect(clusterClientAdapter.getExistingIndexAliases('foo*')).resolves.toEqual(response);
});
test('should throw error when call cluster throws an error', async () => {
clusterClient.indices.getAlias.mockRejectedValue(new Error('Fail'));
await expect(
clusterClientAdapter.getExistingIndexAliases('foo*')
).rejects.toThrowErrorMatchingInlineSnapshot(
`"error getting existing index aliases matching pattern foo*: Fail"`
);
});
});
describe('setIndexAliasToHidden', () => {
test('should call cluster with given index name and aliases', async () => {
await clusterClientAdapter.setIndexAliasToHidden('foo-bar-000001', {
aliases: {
'foo-bar': {
is_write_index: true,
},
},
});
expect(clusterClient.indices.updateAliases).toHaveBeenCalledWith({
body: {
actions: [
{
add: {
index: 'foo-bar-000001',
alias: 'foo-bar',
is_hidden: true,
is_write_index: true,
},
},
],
},
});
});
test('should update multiple aliases at once and preserve existing alias settings', async () => {
await clusterClientAdapter.setIndexAliasToHidden('foo-bar-000001', {
aliases: {
'foo-bar': {
is_write_index: true,
},
'foo-b': {
index_routing: 'index',
routing: 'route',
},
},
});
expect(clusterClient.indices.updateAliases).toHaveBeenCalledWith({
body: {
actions: [
{
add: {
index: 'foo-bar-000001',
alias: 'foo-bar',
is_hidden: true,
is_write_index: true,
},
},
{
add: {
index: 'foo-bar-000001',
alias: 'foo-b',
is_hidden: true,
index_routing: 'index',
routing: 'route',
},
},
],
},
});
});
test('should throw error when call cluster throws an error', async () => {
clusterClient.indices.updateAliases.mockRejectedValue(new Error('Fail'));
await expect(
clusterClientAdapter.setIndexAliasToHidden('foo-bar-000001', {
aliases: {
'foo-bar': {
is_write_index: true,
},
},
})
).rejects.toThrowErrorMatchingInlineSnapshot(
`"error setting existing index aliases for index foo-bar-000001 to is_hidden: Fail"`
);
});
});
describe('doesAliasExist', () => {
test('should call cluster with proper arguments', async () => {
await clusterClientAdapter.doesAliasExist('foo');

View file

@ -7,7 +7,7 @@
import { Subject } from 'rxjs';
import { bufferTime, filter as rxFilter, switchMap } from 'rxjs/operators';
import { reject, isUndefined, isNumber } from 'lodash';
import { reject, isUndefined, isNumber, pick } from 'lodash';
import type { PublicMethodsOf } from '@kbn/utility-types';
import { Logger, ElasticsearchClient } from 'src/core/server';
import util from 'util';
@ -163,17 +163,23 @@ export class ClusterClientAdapter<TDoc extends { body: AliasAny; index: string }
public async doesIndexTemplateExist(name: string): Promise<boolean> {
try {
const esClient = await this.elasticsearchClientPromise;
const { body } = await esClient.indices.existsTemplate({ name });
return body as boolean;
const { body: legacyResult } = await esClient.indices.existsTemplate({ name });
const { body: indexTemplateResult } = await esClient.indices.existsIndexTemplate({ name });
return (legacyResult as boolean) || (indexTemplateResult as boolean);
} catch (err) {
throw new Error(`error checking existance of index template: ${err.message}`);
throw new Error(`error checking existence of index template: ${err.message}`);
}
}
public async createIndexTemplate(name: string, template: Record<string, unknown>): Promise<void> {
try {
const esClient = await this.elasticsearchClientPromise;
await esClient.indices.putTemplate({ name, body: template, create: true });
await esClient.indices.putIndexTemplate({
name,
body: template,
// @ts-expect-error doesn't exist in @elastic/elasticsearch
create: true,
});
} catch (err) {
// The error message doesn't have a type attribute we can look to guarantee it's due
// to the template already existing (only long message) so we'll check ourselves to see
@ -188,6 +194,128 @@ export class ClusterClientAdapter<TDoc extends { body: AliasAny; index: string }
}
}
public async getExistingLegacyIndexTemplates(
indexTemplatePattern: string
): Promise<estypes.IndicesGetTemplateResponse> {
try {
const esClient = await this.elasticsearchClientPromise;
const { body: templates } = await esClient.indices.getTemplate(
{ name: indexTemplatePattern },
{ ignore: [404] }
);
return templates;
} catch (err) {
throw new Error(`error getting existing legacy index templates: ${err.message}`);
}
}
public async setLegacyIndexTemplateToHidden(
indexTemplateName: string,
currentIndexTemplate: estypes.IndicesTemplateMapping
): Promise<void> {
try {
const esClient = await this.elasticsearchClientPromise;
await esClient.indices.putTemplate({
name: indexTemplateName,
body: {
...currentIndexTemplate,
settings: {
...currentIndexTemplate.settings,
'index.hidden': true,
},
},
});
} catch (err) {
throw new Error(
`error setting existing legacy index template ${indexTemplateName} to hidden: ${err.message}`
);
}
}
public async getExistingIndices(
indexPattern: string
): Promise<estypes.IndicesGetSettingsResponse> {
try {
const esClient = await this.elasticsearchClientPromise;
const { body: indexSettings } = await esClient.indices.getSettings(
{ index: indexPattern },
{ ignore: [404] }
);
return indexSettings;
} catch (err) {
throw new Error(
`error getting existing indices matching pattern ${indexPattern}: ${err.message}`
);
}
}
public async setIndexToHidden(indexName: string): Promise<void> {
try {
const esClient = await this.elasticsearchClientPromise;
await esClient.indices.putSettings({
index: indexName,
body: {
settings: {
'index.hidden': true,
},
},
});
} catch (err) {
throw new Error(`error setting existing index ${indexName} to hidden: ${err.message}`);
}
}
public async getExistingIndexAliases(
indexPattern: string
): Promise<estypes.IndicesGetAliasResponse> {
try {
const esClient = await this.elasticsearchClientPromise;
const { body: indexAliases } = await esClient.indices.getAlias(
{ index: indexPattern },
{ ignore: [404] }
);
return indexAliases;
} catch (err) {
throw new Error(
`error getting existing index aliases matching pattern ${indexPattern}: ${err.message}`
);
}
}
public async setIndexAliasToHidden(
indexName: string,
currentAliases: estypes.IndicesGetAliasIndexAliases
): Promise<void> {
try {
const esClient = await this.elasticsearchClientPromise;
await esClient.indices.updateAliases({
body: {
actions: Object.keys(currentAliases.aliases).map((aliasName) => {
const existingAliasOptions = pick(currentAliases.aliases[aliasName], [
'is_write_index',
'filter',
'index_routing',
'routing',
'search_routing',
]);
return {
add: {
...existingAliasOptions,
index: indexName,
alias: aliasName,
is_hidden: true,
},
};
}),
},
});
} catch (err) {
throw new Error(
`error setting existing index aliases for index ${indexName} to is_hidden: ${err.message}`
);
}
}
public async doesAliasExist(name: string): Promise<boolean> {
try {
const esClient = await this.elasticsearchClientPromise;

View file

@ -64,6 +64,7 @@ describe('createEsContext', () => {
elasticsearchClientPromise: Promise.resolve(elasticsearchClient),
});
elasticsearchClient.indices.existsTemplate.mockResolvedValue(asApiResponse(false));
elasticsearchClient.indices.existsIndexTemplate.mockResolvedValue(asApiResponse(false));
elasticsearchClient.indices.existsAlias.mockResolvedValue(asApiResponse(false));
const doesAliasExist = await context.esAdapter.doesAliasExist(context.esNames.alias);
expect(doesAliasExist).toBeFalsy();

View file

@ -25,10 +25,11 @@ describe('getIndexTemplate()', () => {
test('returns the correct details of the index template', () => {
const indexTemplate = getIndexTemplate(esNames);
expect(indexTemplate.index_patterns).toEqual([esNames.indexPatternWithVersion]);
expect(indexTemplate.settings.number_of_shards).toBeGreaterThanOrEqual(0);
expect(indexTemplate.settings.auto_expand_replicas).toBe('0-1');
expect(indexTemplate.settings['index.lifecycle.name']).toBe(esNames.ilmPolicy);
expect(indexTemplate.settings['index.lifecycle.rollover_alias']).toBe(esNames.alias);
expect(indexTemplate.mappings).toMatchObject({});
expect(indexTemplate.template.settings.number_of_shards).toBeGreaterThanOrEqual(0);
expect(indexTemplate.template.settings.auto_expand_replicas).toBe('0-1');
expect(indexTemplate.template.settings['index.lifecycle.name']).toBe(esNames.ilmPolicy);
expect(indexTemplate.template.settings['index.lifecycle.rollover_alias']).toBe(esNames.alias);
expect(indexTemplate.template.settings['index.hidden']).toBe(true);
expect(indexTemplate.template.mappings).toMatchObject({});
});
});

View file

@ -12,13 +12,16 @@ import mappings from '../../generated/mappings.json';
export function getIndexTemplate(esNames: EsNames) {
const indexTemplateBody = {
index_patterns: [esNames.indexPatternWithVersion],
settings: {
number_of_shards: 1,
auto_expand_replicas: '0-1',
'index.lifecycle.name': esNames.ilmPolicy,
'index.lifecycle.rollover_alias': esNames.alias,
template: {
settings: {
number_of_shards: 1,
auto_expand_replicas: '0-1',
'index.lifecycle.name': esNames.ilmPolicy,
'index.lifecycle.rollover_alias': esNames.alias,
'index.hidden': true,
},
mappings,
},
mappings,
};
return indexTemplateBody;

View file

@ -13,6 +13,327 @@ describe('initializeEs', () => {
beforeEach(() => {
esContext = contextMock.create();
esContext.esAdapter.getExistingLegacyIndexTemplates.mockResolvedValue({});
esContext.esAdapter.getExistingIndices.mockResolvedValue({});
esContext.esAdapter.getExistingIndexAliases.mockResolvedValue({});
});
test(`should update existing index templates if any exist and are not hidden`, async () => {
const testTemplate = {
order: 0,
index_patterns: ['foo-bar-*'],
settings: {
index: {
lifecycle: {
name: 'foo-bar-policy',
rollover_alias: 'foo-bar-1',
},
number_of_shards: '1',
auto_expand_replicas: '0-1',
},
},
mappings: {},
aliases: {},
};
esContext.esAdapter.getExistingLegacyIndexTemplates.mockResolvedValue({
'foo-bar-template': testTemplate,
});
await initializeEs(esContext);
expect(esContext.esAdapter.getExistingLegacyIndexTemplates).toHaveBeenCalled();
expect(esContext.esAdapter.setLegacyIndexTemplateToHidden).toHaveBeenCalledWith(
'foo-bar-template',
testTemplate
);
});
test(`should not update existing index templates if any exist and are already hidden`, async () => {
const testTemplate = {
order: 0,
index_patterns: ['foo-bar-*'],
settings: {
index: {
lifecycle: {
name: 'foo-bar-policy',
rollover_alias: 'foo-bar-1',
},
hidden: 'true',
number_of_shards: '1',
auto_expand_replicas: '0-1',
},
},
mappings: {},
aliases: {},
};
esContext.esAdapter.getExistingLegacyIndexTemplates.mockResolvedValue({
'foo-bar-template': testTemplate,
});
await initializeEs(esContext);
expect(esContext.esAdapter.getExistingLegacyIndexTemplates).toHaveBeenCalled();
expect(esContext.esAdapter.setLegacyIndexTemplateToHidden).not.toHaveBeenCalled();
});
test(`should continue initialization if getting existing index templates throws an error`, async () => {
esContext.esAdapter.getExistingLegacyIndexTemplates.mockRejectedValue(new Error('Fail'));
await initializeEs(esContext);
expect(esContext.esAdapter.getExistingLegacyIndexTemplates).toHaveBeenCalled();
expect(esContext.logger.error).toHaveBeenCalledWith(
`error getting existing index templates - Fail`
);
expect(esContext.esAdapter.setLegacyIndexTemplateToHidden).not.toHaveBeenCalled();
expect(esContext.esAdapter.doesIlmPolicyExist).toHaveBeenCalled();
});
test(`should continue initialization if updating existing index templates throws an error`, async () => {
const testTemplate = {
order: 0,
index_patterns: ['foo-bar-*'],
settings: {
index: {
lifecycle: {
name: 'foo-bar-policy',
rollover_alias: 'foo-bar-1',
},
number_of_shards: '1',
auto_expand_replicas: '0-1',
},
},
mappings: {},
aliases: {},
};
esContext.esAdapter.getExistingLegacyIndexTemplates.mockResolvedValue({
'foo-bar-template': testTemplate,
'another-test-template': testTemplate,
});
esContext.esAdapter.setLegacyIndexTemplateToHidden.mockRejectedValueOnce(new Error('Fail'));
esContext.esAdapter.setLegacyIndexTemplateToHidden.mockResolvedValueOnce();
await initializeEs(esContext);
expect(esContext.esAdapter.getExistingLegacyIndexTemplates).toHaveBeenCalled();
expect(esContext.esAdapter.setLegacyIndexTemplateToHidden).toHaveBeenCalledWith(
'foo-bar-template',
testTemplate
);
expect(esContext.esAdapter.setLegacyIndexTemplateToHidden).toHaveBeenCalledWith(
'another-test-template',
testTemplate
);
expect(esContext.logger.error).toHaveBeenCalledTimes(1);
expect(esContext.logger.error).toHaveBeenCalledWith(
`error setting existing \"foo-bar-template\" index template to hidden - Fail`
);
expect(esContext.esAdapter.doesIlmPolicyExist).toHaveBeenCalled();
});
test(`should update existing index settings if any exist and are not hidden`, async () => {
const testSettings = {
settings: {
index: {
lifecycle: {
name: 'foo-bar-policy',
rollover_alias: 'foo-bar-1',
},
routing: {
allocation: {
include: {
_tier_preference: 'data_content',
},
},
},
number_of_shards: '1',
auto_expand_replicas: '0-1',
provided_name: '.kibana-event-log-7.15.0-000001',
creation_date: '1630439186791',
number_of_replicas: '0',
uuid: 'Ure4d9edQbCMtcmyy0ObrA',
version: {
created: '7150099',
},
},
},
};
esContext.esAdapter.getExistingIndices.mockResolvedValue({
'foo-bar-000001': testSettings,
});
await initializeEs(esContext);
expect(esContext.esAdapter.getExistingIndices).toHaveBeenCalled();
expect(esContext.esAdapter.setIndexToHidden).toHaveBeenCalledWith('foo-bar-000001');
});
test(`should not update existing index settings if any exist and are already hidden`, async () => {
const testSettings = {
settings: {
index: {
lifecycle: {
name: 'foo-bar-policy',
rollover_alias: 'foo-bar-1',
},
routing: {
allocation: {
include: {
_tier_preference: 'data_content',
},
},
},
hidden: 'true',
number_of_shards: '1',
auto_expand_replicas: '0-1',
provided_name: '.kibana-event-log-7.15.0-000001',
creation_date: '1630439186791',
number_of_replicas: '0',
uuid: 'Ure4d9edQbCMtcmyy0ObrA',
version: {
created: '7150099',
},
},
},
};
esContext.esAdapter.getExistingIndices.mockResolvedValue({
'foo-bar-000001': testSettings,
});
await initializeEs(esContext);
expect(esContext.esAdapter.getExistingIndices).toHaveBeenCalled();
expect(esContext.esAdapter.setIndexToHidden).not.toHaveBeenCalled();
});
test(`should continue initialization if getting existing index settings throws an error`, async () => {
esContext.esAdapter.getExistingIndices.mockRejectedValue(new Error('Fail'));
await initializeEs(esContext);
expect(esContext.esAdapter.getExistingIndices).toHaveBeenCalled();
expect(esContext.logger.error).toHaveBeenCalledWith(`error getting existing indices - Fail`);
expect(esContext.esAdapter.setIndexToHidden).not.toHaveBeenCalled();
expect(esContext.esAdapter.doesIlmPolicyExist).toHaveBeenCalled();
});
test(`should continue initialization if updating existing index settings throws an error`, async () => {
const testSettings = {
settings: {
index: {
lifecycle: {
name: 'foo-bar-policy',
rollover_alias: 'foo-bar-1',
},
routing: {
allocation: {
include: {
_tier_preference: 'data_content',
},
},
},
number_of_shards: '1',
auto_expand_replicas: '0-1',
provided_name: '.kibana-event-log-7.15.0-000001',
creation_date: '1630439186791',
number_of_replicas: '0',
uuid: 'Ure4d9edQbCMtcmyy0ObrA',
version: {
created: '7150099',
},
},
},
};
esContext.esAdapter.getExistingIndices.mockResolvedValue({
'foo-bar-000001': testSettings,
'foo-bar-000002': testSettings,
});
esContext.esAdapter.setIndexToHidden.mockRejectedValueOnce(new Error('Fail'));
esContext.esAdapter.setIndexToHidden.mockResolvedValueOnce();
await initializeEs(esContext);
expect(esContext.esAdapter.getExistingIndices).toHaveBeenCalled();
expect(esContext.logger.error).toHaveBeenCalledTimes(1);
expect(esContext.logger.error).toHaveBeenCalledWith(
`error setting existing \"foo-bar-000001\" index to hidden - Fail`
);
expect(esContext.esAdapter.doesIlmPolicyExist).toHaveBeenCalled();
});
test(`should update existing index aliases if any exist and are not hidden`, async () => {
const testAliases = {
aliases: {
'foo-bar': {
is_write_index: true,
},
},
};
esContext.esAdapter.getExistingIndexAliases.mockResolvedValue({
'foo-bar-000001': testAliases,
});
await initializeEs(esContext);
expect(esContext.esAdapter.getExistingIndexAliases).toHaveBeenCalled();
expect(esContext.esAdapter.setIndexAliasToHidden).toHaveBeenCalledWith(
'foo-bar-000001',
testAliases
);
});
test(`should not update existing index aliases if any exist and are already hidden`, async () => {
const testAliases = {
aliases: {
'foo-bar': {
is_write_index: true,
is_hidden: true,
},
},
};
esContext.esAdapter.getExistingIndexAliases.mockResolvedValue({
'foo-bar-000001': testAliases,
});
await initializeEs(esContext);
expect(esContext.esAdapter.getExistingIndexAliases).toHaveBeenCalled();
expect(esContext.esAdapter.setIndexAliasToHidden).not.toHaveBeenCalled();
});
test(`should continue initialization if getting existing index aliases throws an error`, async () => {
esContext.esAdapter.getExistingIndexAliases.mockRejectedValue(new Error('Fail'));
await initializeEs(esContext);
expect(esContext.esAdapter.getExistingIndexAliases).toHaveBeenCalled();
expect(esContext.logger.error).toHaveBeenCalledWith(
`error getting existing index aliases - Fail`
);
expect(esContext.esAdapter.setIndexAliasToHidden).not.toHaveBeenCalled();
expect(esContext.esAdapter.doesIlmPolicyExist).toHaveBeenCalled();
});
test(`should continue initialization if updating existing index aliases throws an error`, async () => {
const testAliases = {
aliases: {
'foo-bar': {
is_write_index: true,
},
},
};
esContext.esAdapter.getExistingIndexAliases.mockResolvedValue({
'foo-bar-000001': testAliases,
'foo-bar-000002': testAliases,
});
esContext.esAdapter.setIndexAliasToHidden.mockRejectedValueOnce(new Error('Fail'));
esContext.esAdapter.setIndexAliasToHidden.mockResolvedValueOnce();
await initializeEs(esContext);
expect(esContext.esAdapter.getExistingIndexAliases).toHaveBeenCalled();
expect(esContext.esAdapter.setIndexAliasToHidden).toHaveBeenCalledWith(
'foo-bar-000001',
testAliases
);
expect(esContext.esAdapter.setIndexAliasToHidden).toHaveBeenCalledWith(
'foo-bar-000002',
testAliases
);
expect(esContext.logger.error).toHaveBeenCalledTimes(1);
expect(esContext.logger.error).toHaveBeenCalledWith(
`error setting existing \"foo-bar-000001\" index aliases - Fail`
);
expect(esContext.esAdapter.doesIlmPolicyExist).toHaveBeenCalled();
});
test(`should create ILM policy if it doesn't exist`, async () => {

View file

@ -5,6 +5,8 @@
* 2.0.
*/
import { IndicesAlias, IndicesIndexStatePrefixedSettings } from '@elastic/elasticsearch/api/types';
import { estypes } from '@elastic/elasticsearch';
import { getIlmPolicy, getIndexTemplate } from './documents';
import { EsContext } from './context';
@ -25,6 +27,7 @@ export async function initializeEs(esContext: EsContext): Promise<boolean> {
async function initializeEsResources(esContext: EsContext) {
const steps = new EsInitializationSteps(esContext);
await steps.setExistingAssetsToHidden();
await steps.createIlmPolicyIfNotExists();
await steps.createIndexTemplateIfNotExists();
await steps.createInitialIndexIfNotExists();
@ -35,6 +38,122 @@ class EsInitializationSteps {
this.esContext = esContext;
}
async setExistingIndexTemplatesToHidden() {
let indexTemplates: estypes.IndicesGetTemplateResponse = {};
try {
// look up existing index templates and update index.hidden to true if that
// setting is currently false or undefined
// since we are updating to the new index template API and converting new event log
// indices to hidden in the same PR, we only need to use the legacy template API to
// look for and update existing event log indices.
indexTemplates = await this.esContext.esAdapter.getExistingLegacyIndexTemplates(
this.esContext.esNames.indexPattern
);
} catch (err) {
// errors when trying to get existing index templates
// should not block the rest of initialization, log the error and move on
this.esContext.logger.error(`error getting existing index templates - ${err.message}`);
}
Object.keys(indexTemplates).forEach(async (indexTemplateName: string) => {
try {
const hidden: string | boolean = indexTemplates[indexTemplateName]?.settings?.index?.hidden;
// Check to see if this index template is hidden
if (hidden !== true && hidden !== 'true') {
this.esContext.logger.debug(
`setting existing "${indexTemplateName}" index template to hidden.`
);
await this.esContext.esAdapter.setLegacyIndexTemplateToHidden(
indexTemplateName,
indexTemplates[indexTemplateName]
);
}
} catch (err) {
// errors when trying to update existing index templates to hidden
// should not block the rest of initialization, log the error and move on
this.esContext.logger.error(
`error setting existing "${indexTemplateName}" index template to hidden - ${err.message}`
);
}
});
}
async setExistingIndicesToHidden() {
let indices: estypes.IndicesGetSettingsResponse = {};
try {
// look up existing indices and update index.hidden to true if that
// setting is currently false or undefined
indices = await this.esContext.esAdapter.getExistingIndices(
this.esContext.esNames.indexPattern
);
} catch (err) {
// errors when trying to get existing indices
// should not block the rest of initialization, log the error and move on
this.esContext.logger.error(`error getting existing indices - ${err.message}`);
}
Object.keys(indices).forEach(async (indexName: string) => {
try {
const hidden: string | boolean | undefined = (indices[indexName]
?.settings as IndicesIndexStatePrefixedSettings)?.index?.hidden;
// Check to see if this index template is hidden
if (hidden !== true && hidden !== 'true') {
this.esContext.logger.debug(`setting existing ${indexName} index to hidden.`);
await this.esContext.esAdapter.setIndexToHidden(indexName);
}
} catch (err) {
// errors when trying to update existing indices to hidden
// should not block the rest of initialization, log the error and move on
this.esContext.logger.error(
`error setting existing "${indexName}" index to hidden - ${err.message}`
);
}
});
}
async setExistingIndexAliasesToHidden() {
let indexAliases: estypes.IndicesGetAliasResponse = {};
try {
// Look up existing index aliases and update index.is_hidden to true if that
// setting is currently false or undefined
indexAliases = await this.esContext.esAdapter.getExistingIndexAliases(
this.esContext.esNames.indexPattern
);
} catch (err) {
// errors when trying to get existing index aliases
// should not block the rest of initialization, log the error and move on
this.esContext.logger.error(`error getting existing index aliases - ${err.message}`);
}
Object.keys(indexAliases).forEach(async (indexName: string) => {
try {
const aliases = indexAliases[indexName]?.aliases;
const hasNotHiddenAliases: boolean = Object.keys(aliases).some((alias: string) => {
return (aliases[alias] as IndicesAlias)?.is_hidden !== true;
});
if (hasNotHiddenAliases) {
this.esContext.logger.debug(`setting existing "${indexName}" index aliases to hidden.`);
await this.esContext.esAdapter.setIndexAliasToHidden(indexName, indexAliases[indexName]);
}
} catch (err) {
// errors when trying to set existing index aliases to is_hidden
// should not block the rest of initialization, log the error and move on
this.esContext.logger.error(
`error setting existing "${indexName}" index aliases - ${err.message}`
);
}
});
}
async setExistingAssetsToHidden(): Promise<void> {
await this.setExistingIndexTemplatesToHidden();
await this.setExistingIndicesToHidden();
await this.setExistingIndexAliasesToHidden();
}
async createIlmPolicyIfNotExists(): Promise<void> {
const exists = await this.esContext.esAdapter.doesIlmPolicyExist(
this.esContext.esNames.ilmPolicy
@ -67,6 +186,7 @@ class EsInitializationSteps {
aliases: {
[this.esContext.esNames.alias]: {
is_write_index: true,
is_hidden: true,
},
},
});