Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.x] Add Pre-8.x Enterprise Search Index Incompatibility Deprecations #210688

Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ import { Connector } from '@kbn/search-connectors';

import { ConfigType } from '..';

import indexDeprecatorFxns = require('./pre_eight_index_deprecator');

import {
getCrawlerDeprecations,
getEnterpriseSearchNodeDeprecation,
getEnterpriseSearchPre8IndexDeprecations,
getNativeConnectorDeprecations,
} from '.';

Expand Down Expand Up @@ -218,3 +221,72 @@ describe('Native connector deprecations', () => {
expect(deprecations[1].title).toMatch('Integration Server must be provisioned');
});
});

describe('getEnterpriseSearchPre8IndexDeprecations', () => {
it('can register index and data stream deprecations that need to be set to read only', async () => {
const getIndicesMock = jest.fn(() =>
Promise.resolve([
{
name: '.ent-search-index_without_datastream',
isDatastream: false,
datastreamName: '',
},
{
name: '.ent-search-with_data_stream',
isDatastream: true,
datastreamName: 'datastream-testing',
},
])
);

jest
.spyOn(indexDeprecatorFxns, 'getPreEightEnterpriseSearchIndices')
.mockImplementation(getIndicesMock);

const deprecations = await getEnterpriseSearchPre8IndexDeprecations(ctx, 'docsurl', 'mockhost');
expect(deprecations).toHaveLength(1);
expect(deprecations[0].correctiveActions.api?.path).toStrictEqual(
'/internal/enterprise_search/deprecations/set_enterprise_search_indices_read_only'
);
expect(deprecations[0].title).toMatch('Pre 8.x Enterprise Search indices compatibility');
expect(deprecations[0].message.content).toContain(
'The following indices are found to be incompatible for upgrade'
);
expect(deprecations[0].message.content).toContain('.ent-search-index_without_datastream');
expect(deprecations[0].message.content).toContain(
'The following data streams are found to be incompatible for upgrade'
);
expect(deprecations[0].message.content).toContain('.ent-search-with_data_stream');
});

it('can register indexex without data stream deprecations that need to be set to read only', async () => {
jloleysens marked this conversation as resolved.
Show resolved Hide resolved
const getIndicesMock = jest.fn(() =>
Promise.resolve([
{
name: '.ent-search-index_without_datastream',
isDatastream: false,
datastreamName: '',
},
])
);

jest
.spyOn(indexDeprecatorFxns, 'getPreEightEnterpriseSearchIndices')
.mockImplementation(getIndicesMock);

const deprecations = await getEnterpriseSearchPre8IndexDeprecations(ctx, 'docsurl', 'mockhost');
expect(deprecations).toHaveLength(1);
expect(deprecations[0].correctiveActions.api?.path).toStrictEqual(
'/internal/enterprise_search/deprecations/set_enterprise_search_indices_read_only'
);
expect(deprecations[0].title).toMatch('Pre 8.x Enterprise Search indices compatibility');
expect(deprecations[0].message.content).toContain(
'The following indices are found to be incompatible for upgrade'
);
expect(deprecations[0].message.content).toContain('.ent-search-index_without_datastream');
expect(deprecations[0].message.content).not.toContain(
'The following data streams are found to be incompatible for upgrade'
);
expect(deprecations[0].message.content).not.toContain('.ent-search-with_data_stream');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { Connector, fetchConnectors } from '@kbn/search-connectors';

import { ConfigType } from '..';

import { getPreEightEnterpriseSearchIndices } from './pre_eight_index_deprecator';

const NATIVE_SERVICE_TYPES = [
'azure_blob_storage',
'box',
Expand Down Expand Up @@ -59,11 +61,18 @@ export const getRegisteredDeprecations = (
true // only counts if the Fleet Server is active
);
const entSearchDetails = getEnterpriseSearchNodeDeprecation(config, cloud, docsUrl);
const [crawlerDetails, nativeConnectorsDetails] = await Promise.all([
await getCrawlerDeprecations(ctx, docsUrl),
await getNativeConnectorDeprecations(ctx, hasAgentless, hasFleetServer, cloud, docsUrl),
]);
return [...entSearchDetails, ...crawlerDetails, ...nativeConnectorsDetails];
const [crawlerDetails, nativeConnectorsDetails, entSearchIndexIncompatibility] =
await Promise.all([
await getCrawlerDeprecations(ctx, docsUrl),
await getNativeConnectorDeprecations(ctx, hasAgentless, hasFleetServer, cloud, docsUrl),
await getEnterpriseSearchPre8IndexDeprecations(ctx, docsUrl, config.host),
]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry I missed this in the original PR but these inner awaits should not be here.

Suggested change
await Promise.all([
await getCrawlerDeprecations(ctx, docsUrl),
await getNativeConnectorDeprecations(ctx, hasAgentless, hasFleetServer, cloud, docsUrl),
await getEnterpriseSearchPre8IndexDeprecations(ctx, docsUrl, config.host),
]);
await Promise.all([
getCrawlerDeprecations(ctx, docsUrl),
getNativeConnectorDeprecations(ctx, hasAgentless, hasFleetServer, cloud, docsUrl),
getEnterpriseSearchPre8IndexDeprecations(ctx, docsUrl, config.host),
]);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @TattdCodeMonkey - Just to be sure (and for my own education too) - with the awaits there, basically, this will wait for each one, in sequence, to complete before creating a promise with all the completed tasks... when, what should be is that the await Promise.all call will itself wait for all the promises to be resolved before completing... correct? (i.e. without the individual await keywords for each of the async functions, those functions can essentially run in parallel... whereas as the moment, they will not... correct?)

return [
...entSearchDetails,
...crawlerDetails,
...nativeConnectorsDetails,
...entSearchIndexIncompatibility,
];
},
};
};
Expand Down Expand Up @@ -414,3 +423,108 @@ export async function getNativeConnectorDeprecations(
return deprecations;
}
}

/**
* If there are any Enterprise Search indices that were created with Elasticsearch 7.x, they must be removed
* or set to read-only
*/
export async function getEnterpriseSearchPre8IndexDeprecations(
ctx: GetDeprecationsContext,
docsUrl: string,
configHost?: string
): Promise<DeprecationsDetails[]> {
const deprecations: DeprecationsDetails[] = [];

if (!configHost) {
return deprecations;
}

// TODO - find out : is this applicable only on cloud?
// const isCloud = !!cloud?.cloudId;

const entSearchIndices = await getPreEightEnterpriseSearchIndices(ctx.esClient.asInternalUser);
if (!entSearchIndices || entSearchIndices.length === 0) {
return deprecations;
}

let indicesList = '';
let datastreamsList = '';
for (const index of entSearchIndices) {
if (index.isDatastream) {
datastreamsList += `${index.name}\n`;
} else {
indicesList += `${index.name}\n`;
}
}

let message = `There are ${entSearchIndices.length} incompatible Enterprise Search indices.\n\n`;

if (indicesList.length > 0) {
message +=
'The following indices are found to be incompatible for upgrade:\n\n' +
'```\n' +
`${indicesList}` +
'\n```\n\n' +
'These indices must be either set to read-only or deleted before upgrading. ';
}

if (datastreamsList.length > 0) {
message +=
'\nThe following data streams are found to be incompatible for upgrade:\n\n' +
'```\n' +
`${datastreamsList}` +
'\n```\n\n' +
'Using the "quick resolve" button below will roll over any datastreams and set all incompatible indices to read-only.\n\n' +
'Alternatively, manually deleting these indices and data streams will also unblock your upgrade.';
} else {
message +=
'Setting these indices to read-only can be attempted with the "quick resolve" button below.\n\n' +
'Alternatively, manually deleting these indices will also unblock your upgrade.';
}

deprecations.push({
level: 'critical',
deprecationType: 'feature',
title: i18n.translate(
'xpack.enterpriseSearch.deprecations.incompatibleEnterpriseSearchIndexes.title',
{
defaultMessage: 'Pre 8.x Enterprise Search indices compatibility',
}
),
message: {
type: 'markdown',
content: i18n.translate(
'xpack.enterpriseSearch.deprecations.incompatibleEnterpriseSearchIndexes.message',
{
defaultMessage: message,
}
),
},
documentationUrl: docsUrl,
correctiveActions: {
manualSteps: [
i18n.translate(
'xpack.enterpriseSearch.deprecations.incompatibleEnterpriseSearchIndexes.deleteIndices',
{
defaultMessage: 'Set all incompatible indices to read only, or',
}
),
i18n.translate(
'xpack.enterpriseSearch.deprecations.incompatibleEnterpriseSearchIndexes.deleteIndices',
{
defaultMessage: 'Delete all incompatible indices',
}
),
],
api: {
method: 'POST',
path: '/internal/enterprise_search/deprecations/set_enterprise_search_indices_read_only',
body: {
deprecationDetails: { domainId: 'enterpriseSearch' },
},
},
},
});

return deprecations;
}
Loading