From 8c903516c463863b634257fa4e724b3172214e22 Mon Sep 17 00:00:00 2001 From: maryliag Date: Fri, 9 Jun 2023 18:33:12 +0000 Subject: [PATCH] ui: show alert on DB Console overview when upgrade is not finalized Display a warning on the DB Console overview page when all the nodes are running on the new version, but the cluster is not finalized. Fixes #66987 Release note (ui change): Add warning to DB Console overview page when all nodes are running on the new version, but the cluster upgrade is not finalized. --- .../workspaces/db-console/src/redux/alerts.ts | 70 ++++++++++++++++++- .../clusterSettings.selectors.ts | 10 +++ .../db-console/src/redux/nodes.spec.ts | 6 +- .../workspaces/db-console/src/redux/nodes.ts | 22 +++++- 4 files changed, 102 insertions(+), 6 deletions(-) diff --git a/pkg/ui/workspaces/db-console/src/redux/alerts.ts b/pkg/ui/workspaces/db-console/src/redux/alerts.ts index 8d398099bd07..bf4ca30a6a97 100644 --- a/pkg/ui/workspaces/db-console/src/redux/alerts.ts +++ b/pkg/ui/workspaces/db-console/src/redux/alerts.ts @@ -38,12 +38,16 @@ import { } from "./apiReducers"; import { singleVersionSelector, + numNodesByVersionsTagSelector, numNodesByVersionsSelector, } from "src/redux/nodes"; import { AdminUIState, AppDispatch } from "./state"; import * as docsURL from "src/util/docs"; import { getDataFromServer } from "../util/dataFromServer"; -import { selectClusterSettings } from "./clusterSettings"; +import { + selectClusterSettings, + selectClusterSettingVersion, +} from "./clusterSettings"; import { longToInt } from "src/util/fixLong"; export enum AlertLevel { @@ -141,7 +145,7 @@ export const staggeredVersionDismissedSetting = new LocalSetting( * This excludes decommissioned nodes. */ export const staggeredVersionWarningSelector = createSelector( - numNodesByVersionsSelector, + numNodesByVersionsTagSelector, staggeredVersionDismissedSetting.selector, (versionsMap, versionMismatchDismissed): Alert => { if (versionMismatchDismissed) { @@ -562,6 +566,67 @@ export const clusterPreserveDowngradeOptionOvertimeSelector = createSelector( }, ); +//////////////////////////////////////// +// Upgrade not finalized. +//////////////////////////////////////// +export const upgradeNotFinalizedDismissedSetting = new LocalSetting( + "upgrade_not_finalized_dismissed", + localSettingsSelector, + false, +); + +/** + * Warning when all the nodes are running on the new version, but the cluster is not finalized. + */ +export const upgradeNotFinalizedWarningSelector = createSelector( + selectClusterSettings, + numNodesByVersionsSelector, + selectClusterSettingVersion, + upgradeNotFinalizedDismissedSetting.selector, + ( + settings, + versionsMap, + clusterVersion, + upgradeNotFinalizedDismissed, + ): Alert => { + if (upgradeNotFinalizedDismissed) { + return undefined; + } + // Don't show this warning if nodes are on different versions, since there is + // already an alert for that (staggeredVersionWarningSelector). + if (!versionsMap || versionsMap.size !== 1 || !clusterVersion) { + return undefined; + } + // Don't show this warning if cluster.preserve_downgrade_option is set, + // because it's expected for the upgrade not be finalized on that case and there is + // an alert for that (clusterPreserveDowngradeOptionOvertimeSelector) + const clusterPreserveDowngradeOption = + settings["cluster.preserve_downgrade_option"]; + const value = clusterPreserveDowngradeOption?.value; + const lastUpdated = clusterPreserveDowngradeOption?.last_updated; + if (value && lastUpdated) { + return undefined; + } + + const nodesVersion = versionsMap.keys().next().value; + // Prod: node version is 23.1 and cluster version is 23.1. + // Dev: node version is 23.1 and cluster version is 23.1-2. + if (clusterVersion.startsWith(nodesVersion)) { + return undefined; + } + + return { + level: AlertLevel.WARNING, + title: "Upgrade not finalized.", + text: `All nodes are running on version ${nodesVersion}, but the cluster is on version ${clusterVersion}.`, + dismiss: (dispatch: AppDispatch) => { + dispatch(upgradeNotFinalizedDismissedSetting.set(true)); + return Promise.resolve(); + }, + }; + }, +); + /** * Selector which returns an array of all active alerts which should be * displayed in the overview list page, these should be non-critical alerts. @@ -570,6 +635,7 @@ export const clusterPreserveDowngradeOptionOvertimeSelector = createSelector( export const overviewListAlertsSelector = createSelector( staggeredVersionWarningSelector, clusterPreserveDowngradeOptionOvertimeSelector, + upgradeNotFinalizedWarningSelector, (...alerts: Alert[]): Alert[] => { return _.without(alerts, null, undefined); }, diff --git a/pkg/ui/workspaces/db-console/src/redux/clusterSettings/clusterSettings.selectors.ts b/pkg/ui/workspaces/db-console/src/redux/clusterSettings/clusterSettings.selectors.ts index a73b080f5d07..d6d4152e0552 100644 --- a/pkg/ui/workspaces/db-console/src/redux/clusterSettings/clusterSettings.selectors.ts +++ b/pkg/ui/workspaces/db-console/src/redux/clusterSettings/clusterSettings.selectors.ts @@ -84,3 +84,13 @@ export const selectIndexRecommendationsEnabled = createSelector( return util.greaterOrEqualThanVersion(value, [22, 2, 0]); }, ); + +export const selectClusterSettingVersion = createSelector( + selectClusterSettings, + (settings): string => { + if (!settings) { + return ""; + } + return settings["version"].value; + }, +); diff --git a/pkg/ui/workspaces/db-console/src/redux/nodes.spec.ts b/pkg/ui/workspaces/db-console/src/redux/nodes.spec.ts index cb5c2afc93d8..f005047a4a4f 100644 --- a/pkg/ui/workspaces/db-console/src/redux/nodes.spec.ts +++ b/pkg/ui/workspaces/db-console/src/redux/nodes.spec.ts @@ -19,7 +19,7 @@ import { selectStoreIDsByNodeID, LivenessStatus, sumNodeStats, - numNodesByVersionsSelector, + numNodesByVersionsTagSelector, } from "./nodes"; import { nodesReducerObj, livenessReducerObj } from "./apiReducers"; import { createAdminUIStore } from "./state"; @@ -185,7 +185,7 @@ describe("node data selectors", function () { }); }); - describe("numNodesByVersionsSelector", () => { + describe("numNodesByVersionsTagSelector", () => { it("correctly returns the different binary versions and the number of associated nodes", () => { const data = [ { @@ -214,7 +214,7 @@ describe("node data selectors", function () { ["v22.1", 2], ["v21.1.7", 1], ]); - expect(numNodesByVersionsSelector(state)).toEqual(expectedResult); + expect(numNodesByVersionsTagSelector(state)).toEqual(expectedResult); }); }); }); diff --git a/pkg/ui/workspaces/db-console/src/redux/nodes.ts b/pkg/ui/workspaces/db-console/src/redux/nodes.ts index 06699628f0f1..d8c5ae71f2ec 100644 --- a/pkg/ui/workspaces/db-console/src/redux/nodes.ts +++ b/pkg/ui/workspaces/db-console/src/redux/nodes.ts @@ -515,7 +515,7 @@ export const versionsSelector = createSelector(validateNodesSelector, nodes => .value(), ); -export const numNodesByVersionsSelector = createSelector( +export const numNodesByVersionsTagSelector = createSelector( validateNodesSelector, nodes => { if (!nodes) { @@ -527,6 +527,26 @@ export const numNodesByVersionsSelector = createSelector( }, ); +export const numNodesByVersionsSelector = createSelector( + validateNodesSelector, + nodes => { + if (!nodes) { + return new Map(); + } + return new Map( + Object.entries( + _.countBy(nodes, node => { + const serverVersion = node?.desc?.ServerVersion; + if (serverVersion) { + return `${serverVersion.major_val}.${serverVersion.minor_val}`; + } + return ""; + }), + ), + ); + }, +); + // Select the current build version of the cluster, returning undefined if the // cluster's version is currently staggered. export const singleVersionSelector = createSelector(