Skip to content

Commit

Permalink
[UA] Allows upgrades on cloud for minor versions (elastic#208309)
Browse files Browse the repository at this point in the history
fix elastic#206468

## Summary

Upgrade Assistant treats upgrading to a minor or patch in the same way
as for a major and blocks the upgrade when there are critical
deprecations.
Critical deprecations only have to be resolved before upgrading to the
next major version and should not prevent upgrading to a minor or patch.

This PR refactors the blocking behavior and allows non-major upgrades
for healthy clusters.

### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)

### Identify risks

Does this PR introduce any risks? For example, consider risks like hard
to test bugs, performance regression, potential of data loss.

Describe the risk, its severity, and mitigation for each identified
risk. Invite stakeholders and evaluate how to proceed before merging.

- [ ] Cloud UI does not adapt the API to handle a query. Without query
support, calls to the API may not work as intended, or fail. Reverting
this PR will block upgrades to non major versions (next minor, next
patch) if there are critical deprecations that have not been resolved.

---------

Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
TinaHeiligers and elasticmachine authored Jan 27, 2025
1 parent d5764b3 commit 45634ed
Show file tree
Hide file tree
Showing 25 changed files with 532 additions and 116 deletions.
15 changes: 8 additions & 7 deletions docs/api/upgrade-assistant/status.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@ Check the status of your cluster.
[[upgrade-assistant-api-status-request]]
==== Request

`GET <kibana host>:<port>/api/upgrade_assistant/status`
`GET <kibana host>:<port>/api/upgrade_assistant/status?targetVersion=9.0.0`

`targetVersion`::
(optional, string): Version to upgrade to.

[[upgrade-assistant-api-status-response-codes]]
==== Response codes

`200`::
Indicates a successful call.

`403`::
Indicates a forbidden request when the upgrade path is not supported (e.g. upgrading more than 1 major or downgrading)

[[upgrade-assistant-api-status-example]]
==== Example
Expand All @@ -28,11 +34,6 @@ The API returns the following:
--------------------------------------------------
{
"readyForUpgrade": false,
"cluster": [
{
"message": "Cluster deprecated issue",
"details":"You have 2 system indices that must be migrated and 5 Elasticsearch deprecation issues and 0 Kibana deprecation issues that must be resolved before upgrading."
}
]
"details":"The following issues must be resolved before upgrading: 1 Elasticsearch deprecation issue."
}
--------------------------------------------------
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('Cluster settings deprecation flyout', () => {
let testBed: ElasticsearchTestBed;
let httpRequestsMockHelpers: ReturnType<typeof setupEnvironment>['httpRequestsMockHelpers'];
let httpSetup: ReturnType<typeof setupEnvironment>['httpSetup'];
const clusterSettingDeprecation = esDeprecationsMockResponse.deprecations[4];
const clusterSettingDeprecation = esDeprecationsMockResponse.migrationsDeprecations[4];

beforeEach(async () => {
const mockEnvironment = setupEnvironment();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ describe('Default deprecation flyout', () => {
});

test('renders a flyout with deprecation details', async () => {
const multiFieldsDeprecation = esDeprecationsMockResponse.deprecations[2];
const multiFieldsDeprecation = esDeprecationsMockResponse.migrationsDeprecations[2];
const { actions, find, exists } = testBed;

await actions.table.clickDeprecationRowAt('default', 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe('ES deprecations table', () => {

// Verify all deprecations appear in the table
expect(find('deprecationTableRow').length).toEqual(
esDeprecationsMockResponse.deprecations.length
esDeprecationsMockResponse.migrationsDeprecations.length
);
});

Expand All @@ -69,8 +69,8 @@ describe('ES deprecations table', () => {

await actions.table.clickRefreshButton();

const mlDeprecation = esDeprecationsMockResponse.deprecations[0];
const reindexDeprecation = esDeprecationsMockResponse.deprecations[3];
const mlDeprecation = esDeprecationsMockResponse.migrationsDeprecations[0];
const reindexDeprecation = esDeprecationsMockResponse.migrationsDeprecations[3];

// Since upgradeStatusMockResponse includes ML and reindex actions (which require fetching status), there will be 4 requests made
expect(httpSetup.get).toHaveBeenCalledWith(
Expand All @@ -96,10 +96,10 @@ describe('ES deprecations table', () => {

it('shows critical and warning deprecations count', () => {
const { find } = testBed;
const criticalDeprecations = esDeprecationsMockResponse.deprecations.filter(
const criticalDeprecations = esDeprecationsMockResponse.migrationsDeprecations.filter(
(deprecation) => deprecation.isCritical
);
const warningDeprecations = esDeprecationsMockResponse.deprecations.filter(
const warningDeprecations = esDeprecationsMockResponse.migrationsDeprecations.filter(
(deprecation) => deprecation.isCritical === false
);

Expand Down Expand Up @@ -133,7 +133,7 @@ describe('ES deprecations table', () => {

await actions.searchBar.clickCriticalFilterButton();

const criticalDeprecations = esDeprecationsMockResponse.deprecations.filter(
const criticalDeprecations = esDeprecationsMockResponse.migrationsDeprecations.filter(
(deprecation) => deprecation.isCritical
);

Expand All @@ -142,7 +142,7 @@ describe('ES deprecations table', () => {
await actions.searchBar.clickCriticalFilterButton();

expect(find('deprecationTableRow').length).toEqual(
esDeprecationsMockResponse.deprecations.length
esDeprecationsMockResponse.migrationsDeprecations.length
);
});

Expand All @@ -165,7 +165,7 @@ describe('ES deprecations table', () => {

component.update();

const clusterDeprecations = esDeprecationsMockResponse.deprecations.filter(
const clusterDeprecations = esDeprecationsMockResponse.migrationsDeprecations.filter(
(deprecation) => deprecation.type === 'cluster_settings'
);

Expand All @@ -174,7 +174,7 @@ describe('ES deprecations table', () => {

it('filters results by query string', async () => {
const { find, actions } = testBed;
const multiFieldsDeprecation = esDeprecationsMockResponse.deprecations[2];
const multiFieldsDeprecation = esDeprecationsMockResponse.migrationsDeprecations[2];

await actions.searchBar.setSearchInputValue(multiFieldsDeprecation.message);

Expand Down Expand Up @@ -205,7 +205,7 @@ describe('ES deprecations table', () => {

describe('pagination', () => {
const esDeprecationsMockResponseWithManyDeprecations = createEsDeprecationsMockResponse(20);
const { deprecations } = esDeprecationsMockResponseWithManyDeprecations;
const { migrationsDeprecations } = esDeprecationsMockResponseWithManyDeprecations;

beforeEach(async () => {
httpRequestsMockHelpers.setLoadEsDeprecationsResponse(
Expand All @@ -229,15 +229,15 @@ describe('ES deprecations table', () => {
const { find, actions } = testBed;

expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual(
Math.round(deprecations.length / 50) // Default rows per page is 50
Math.round(migrationsDeprecations.length / 50) // Default rows per page is 50
);
expect(find('deprecationTableRow').length).toEqual(50);

// Navigate to the next page
await actions.pagination.clickPaginationAt(1);

// On the second (last) page, we expect to see the remaining deprecations
expect(find('deprecationTableRow').length).toEqual(deprecations.length - 50);
expect(find('deprecationTableRow').length).toEqual(migrationsDeprecations.length - 50);
});

it('allows the number of viewable rows to change', async () => {
Expand All @@ -260,15 +260,17 @@ describe('ES deprecations table', () => {
component.update();

expect(find('esDeprecationsPagination').find('.euiPagination__item').length).toEqual(
Math.round(deprecations.length / 100) // Rows per page is now 100
Math.round(migrationsDeprecations.length / 100) // Rows per page is now 100
);
expect(find('deprecationTableRow').length).toEqual(deprecations.length);
expect(find('deprecationTableRow').length).toEqual(migrationsDeprecations.length);
});

it('updates pagination when filters change', async () => {
const { actions, find } = testBed;

const criticalDeprecations = deprecations.filter((deprecation) => deprecation.isCritical);
const criticalDeprecations = migrationsDeprecations.filter(
(deprecation) => deprecation.isCritical
);

await actions.searchBar.clickCriticalFilterButton();

Expand All @@ -279,7 +281,7 @@ describe('ES deprecations table', () => {

it('updates pagination on search', async () => {
const { actions, find } = testBed;
const reindexDeprecations = deprecations.filter(
const reindexDeprecations = migrationsDeprecations.filter(
(deprecation) => deprecation.correctiveAction?.type === 'reindex'
);

Expand All @@ -295,7 +297,9 @@ describe('ES deprecations table', () => {
beforeEach(async () => {
const noDeprecationsResponse = {
totalCriticalDeprecations: 0,
deprecations: [],
migrationsDeprecations: [],
totalCriticalHealthIssues: 0,
enrichedHealthIndicators: [],
};

httpRequestsMockHelpers.setLoadEsDeprecationsResponse(noDeprecationsResponse);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('Index settings deprecation flyout', () => {
let testBed: ElasticsearchTestBed;
let httpRequestsMockHelpers: ReturnType<typeof setupEnvironment>['httpRequestsMockHelpers'];
let httpSetup: ReturnType<typeof setupEnvironment>['httpSetup'];
const indexSettingDeprecation = esDeprecationsMockResponse.deprecations[1];
const indexSettingDeprecation = esDeprecationsMockResponse.migrationsDeprecations[1];
beforeEach(async () => {
const mockEnvironment = setupEnvironment();
httpRequestsMockHelpers = mockEnvironment.httpRequestsMockHelpers;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { esDeprecationsMockResponse, MOCK_SNAPSHOT_ID, MOCK_JOB_ID } from './moc

describe('Machine learning deprecation flyout', () => {
let testBed: ElasticsearchTestBed;
const mlDeprecation = esDeprecationsMockResponse.deprecations[0];
const mlDeprecation = esDeprecationsMockResponse.migrationsDeprecations[0];
let httpRequestsMockHelpers: ReturnType<typeof setupEnvironment>['httpRequestsMockHelpers'];
let httpSetup: ReturnType<typeof setupEnvironment>['httpSetup'];
beforeEach(async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,15 @@ const MOCK_DEFAULT_DEPRECATION: EnrichedDeprecationInfo = {

export const esDeprecationsMockResponse: ESUpgradeStatus = {
totalCriticalDeprecations: 2,
deprecations: [
migrationsDeprecations: [
MOCK_ML_DEPRECATION,
MOCK_INDEX_SETTING_DEPRECATION,
MOCK_DEFAULT_DEPRECATION,
MOCK_REINDEX_DEPRECATION,
MOCK_CLUSTER_SETTING_DEPRECATION,
],
totalCriticalHealthIssues: 0,
enrichedHealthIndicators: [],
};

// Useful for testing pagination where a large number of deprecations are needed
Expand Down Expand Up @@ -118,7 +120,7 @@ export const createEsDeprecationsMockResponse = (
() => MOCK_DEFAULT_DEPRECATION
);

const deprecations: EnrichedDeprecationInfo[] = [
const migrationsDeprecations: EnrichedDeprecationInfo[] = [
...defaultDeprecations,
...reindexDeprecations,
...indexSettingsDeprecations,
Expand All @@ -127,6 +129,8 @@ export const createEsDeprecationsMockResponse = (

return {
totalCriticalDeprecations: mlDeprecations.length + reindexDeprecations.length,
deprecations,
migrationsDeprecations,
totalCriticalHealthIssues: esDeprecationsMockResponse.totalCriticalHealthIssues,
enrichedHealthIndicators: esDeprecationsMockResponse.enrichedHealthIndicators,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ describe('Reindex deprecation flyout', () => {
});

it('renders a flyout with reindexing details', async () => {
const reindexDeprecation = esDeprecationsMockResponse.deprecations[3];
const reindexDeprecation = esDeprecationsMockResponse.migrationsDeprecations[3];
const { actions, find, exists } = testBed;

await actions.table.clickDeprecationRowAt('reindex', 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ESUpgradeStatus } from '../../../../common/types';

export const esCriticalAndWarningDeprecations: ESUpgradeStatus = {
totalCriticalDeprecations: 1,
deprecations: [
migrationsDeprecations: [
{
isCritical: true,
type: 'cluster_settings',
Expand All @@ -34,11 +34,13 @@ export const esCriticalAndWarningDeprecations: ESUpgradeStatus = {
},
},
],
totalCriticalHealthIssues: 0,
enrichedHealthIndicators: [],
};

export const esCriticalOnlyDeprecations: ESUpgradeStatus = {
totalCriticalDeprecations: 1,
deprecations: [
migrationsDeprecations: [
{
isCritical: true,
type: 'cluster_settings',
Expand All @@ -49,9 +51,13 @@ export const esCriticalOnlyDeprecations: ESUpgradeStatus = {
'The Index Lifecycle Management poll interval setting [indices.lifecycle.poll_interval] is currently set to [500ms], but must be 1s or greater',
},
],
totalCriticalHealthIssues: 0,
enrichedHealthIndicators: [],
};

export const esNoDeprecations: ESUpgradeStatus = {
totalCriticalDeprecations: 0,
deprecations: [],
migrationsDeprecations: [],
totalCriticalHealthIssues: 0,
enrichedHealthIndicators: [],
};
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,9 @@ export interface CloudBackupStatus {

export interface ESUpgradeStatus {
totalCriticalDeprecations: number;
deprecations: EnrichedDeprecationInfo[];
migrationsDeprecations: EnrichedDeprecationInfo[];
totalCriticalHealthIssues: number;
enrichedHealthIndicators: EnrichedDeprecationInfo[];
}

export interface ResolveIndexResponseFromES {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ export const EsDeprecations = withRouter(({ history }: RouteComponentProps) => {
warningDeprecations: number;
criticalDeprecations: number;
} = useMemo(
() => getDeprecationCountByLevel(esDeprecations?.deprecations || []),
[esDeprecations?.deprecations]
() => getDeprecationCountByLevel(esDeprecations?.migrationsDeprecations || []),
[esDeprecations?.migrationsDeprecations]
);

useEffect(() => {
Expand All @@ -152,7 +152,7 @@ export const EsDeprecations = withRouter(({ history }: RouteComponentProps) => {
return <SectionLoading>{i18nTexts.isLoading}</SectionLoading>;
}

if (esDeprecations?.deprecations?.length === 0) {
if (esDeprecations?.migrationsDeprecations?.length === 0) {
return (
<NoDeprecationsPrompt
deprecationType="Elasticsearch"
Expand Down Expand Up @@ -198,7 +198,10 @@ export const EsDeprecations = withRouter(({ history }: RouteComponentProps) => {

<EuiSpacer size="l" />

<EsDeprecationsTable deprecations={esDeprecations?.deprecations} reload={resendRequest} />
<EsDeprecationsTable
deprecations={esDeprecations?.migrationsDeprecations}
reload={resendRequest}
/>
</div>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ export const EsDeprecationIssuesPanel: FunctionComponent<Props> = ({ setIsFixed
const { data: esDeprecations, isLoading, error } = api.useLoadEsDeprecations();

const criticalDeprecationsCount =
esDeprecations?.deprecations?.filter((deprecation) => deprecation.isCritical)?.length ?? 0;
esDeprecations?.migrationsDeprecations?.filter((deprecation) => deprecation.isCritical)
?.length ?? 0;

const warningDeprecationsCount =
esDeprecations?.deprecations?.filter((deprecation) => deprecation.isCritical === false)
?.length ?? 0;
esDeprecations?.migrationsDeprecations?.filter(
(deprecation) => deprecation.isCritical === false
)?.length ?? 0;

const errorMessage = error && getEsDeprecationError(error).message;

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 45634ed

Please sign in to comment.