[pve-devel] [PATCH v3 pve-manager 1/5] fix #5366: ui: ceph: services: parse and display build commit

Max Carrara m.carrara at proxmox.com
Wed Jul 24 17:05:07 CEST 2024


The build commit is displayed and taken into account when comparing
monitor and manager versions in the client. Specifically, the
shortened build commit is now displayed in parentheses next to the
version for both monitors and managers like so:

  18.2.2 (build: abcd1234)

Should the build commit of the running service differ from the one
that's installed on the host, the newer build commit will also be
shown in parentheses:

  18.2.2 (build: abcd1234 -> 5678fedc)

The icon displayed for running a service with an outdated build is the
same as for running an outdated version. The conditional display of
icons related to cluster health remains the same otherwise.

The Ceph summary view also displays the hash and will show a warning
if a service is running with a build commit that doesn't match the one
that's advertised by the host.

This requires the introduction of two helper functions:

1. `PVE.Utils.parseCephBuildCommit`, which can be used to get the full
  hash "eccf199d..." in parentheses from a string like the following:

  ceph version 17.2.7 (eccf199d63457659c09677399928203b7903c888) quincy (stable)

2. `PVE.Utils.renderCephBuildCommit`, which is used to determine how
   to render a service's current build commit and which accompanying
   icon to choose.

Signed-off-by: Max Carrara <m.carrara at proxmox.com>
Fixes: https://bugzilla.proxmox.com/show_bug.cgi?id=5366
---
Changes v2 --> v3:
  * add new `renderCephBuildCommit` helper function (thanks Thomas!)
  * add docstrings for helpers
  * use less ambiguous variable names (thanks Thomas!)
  * put 'build: ' in front of build commit when rendering (thanks Thomas!)
  * handle no rendered build commit being available in MGR / MON lists,
    returning the icon + version without the commit instead
  * make the modified logic in Services.js more readable
  * reword message about differing builds in the overview
  * reword commit title & message
  * add 'Fixes' trailer
  * remove outdated R-b and T-b trailers

Changes v1 --> v2:
  * use camelCase instead of snake_case (thanks Lukas!)
  * use more descriptive variable names (thanks Lukas!)
  * use `let` instead of `const` for variables where applicable (thanks Lukas!)

 www/manager6/Utils.js            | 107 +++++++++++++++++++++++++++++++
 www/manager6/ceph/ServiceList.js |  33 +++++++---
 www/manager6/ceph/Services.js    |  19 +++++-
 3 files changed, 148 insertions(+), 11 deletions(-)

diff --git a/www/manager6/Utils.js b/www/manager6/Utils.js
index db86fa9a..1d42be34 100644
--- a/www/manager6/Utils.js
+++ b/www/manager6/Utils.js
@@ -128,6 +128,113 @@ Ext.define('PVE.Utils', {
 	return undefined;
     },
 
+    /**
+     * Parses a Ceph build commit from its version string.
+     *
+     * @param {object} service
+     * @param {string} service.ceph_version - The long form of a Ceph version string
+     * @returns {(undefined|string)} The matched build commit or `undefined`
+     */
+    parseCephBuildCommit: function(service) {
+	if (service.ceph_version) {
+	    // See PVE/Ceph/Tools.pm - get_local_version
+	    const match = service.ceph_version.match(
+		/^ceph.*\sv?(?:\d+(?:\.\d+)+)\s+(?:\(([a-zA-Z0-9]+)\))/,
+	    );
+	    if (match) {
+		return match[1];
+	    }
+	}
+
+	return undefined;
+    },
+
+    /**
+     * Determines how Ceph build commits should be rendered and which icon
+     * should be chosen depending on the Ceph versions and build commits given.
+     *
+     * Should the two build commits be identical, the commit is shortened.
+     * Should they differ, they're rendered as e.g.:
+     *
+     *	    0558a7146 -> b72f4fd04
+     *
+     *	Note that the arrow `->` is rendered as a Font Awesome icon.
+     *
+     * @param {Object} versionInfo
+     * @param {string} versionInfo.runningVersion - The version of the currently
+     *	    running Ceph service
+     * @param {string} versionInfo.installedVersion - The version of the Ceph
+     *	    service (or its executable) as reported by the node
+     * @param {string} versionInfo.runningBuildCommit - The build commit of the
+     *	    currently running Ceph service
+     * @param {string} versionInfo.installedBuildCommit - The build commit of the
+     *	    Ceph service (or its executable) as reported by the node
+     * @param {string} versionInfo.maxVersion - The highest version of the
+     *	    Ceph service in the cluster
+     * @param {boolean} versionInfo.hasMixedVersions - Whether different
+     *	    versions of the service are currently running in the cluster
+     * @param {number} [buildCommitLength] - (Optional) The length to which to
+     *	    shorten the rendered build commit(s), `9` by default
+     * @returns {Object} - An object containing the selected `icon`, whether the
+     *	    current build commit has `changed` and the build commit (or build
+     *	    commit changes) as `renderedBuildCommit`
+     */
+    renderCephBuildCommit: function(versionInfo, buildCommitLength) {
+	buildCommitLength ??= 9;
+
+	versionInfo = versionInfo ?? {};
+
+	let runningVersion = versionInfo.runningVersion ?? '';
+	let installedVersion = versionInfo.installedVersion ?? '';
+
+	let runningBuildCommit = versionInfo.runningBuildCommit ?? '';
+	let installedBuildCommit = versionInfo.installedBuildCommit ?? '';
+
+	let maxVersion = versionInfo.maxVersion ?? '';
+	let hasMixedVersions = versionInfo.hasMixedVersions ?? false;
+
+	let hasBuildCommits = runningBuildCommit !== '' && installedBuildCommit !== '';
+	let hasRunningBuildCommitChanged = hasBuildCommits &&
+	    runningBuildCommit !== installedBuildCommit;
+
+	let icon = '';
+
+	if (PVE.Utils.compare_ceph_versions(maxVersion, installedVersion) > 0) {
+	    icon = PVE.Utils.get_ceph_icon_html('HEALTH_UPGRADE');
+	} else if (PVE.Utils.compare_ceph_versions(installedVersion, runningVersion) > 0) {
+	    icon = PVE.Utils.get_ceph_icon_html('HEALTH_OLD');
+	} else if (hasMixedVersions && !hasRunningBuildCommitChanged) {
+	    icon = PVE.Utils.get_ceph_icon_html('HEALTH_OK');
+	}
+
+	if (!hasBuildCommits) {
+	    return {
+		icon: icon,
+		changed: hasRunningBuildCommitChanged,
+		renderedBuildCommit: (runningBuildCommit || installedBuildCommit)
+		    .substring(0, buildCommitLength),
+	    };
+	}
+
+	let renderedBuildCommit = runningBuildCommit.substring(0, buildCommitLength);
+
+	if (hasRunningBuildCommitChanged) {
+	    const arrow = '<i class="fa fa-fw fa-long-arrow-right"></i>';
+	    icon ||= PVE.Utils.get_ceph_icon_html('HEALTH_OLD');
+
+	    let buildCommitFrom = runningBuildCommit.substring(0, buildCommitLength);
+	    let buildCommitTo = installedBuildCommit.substring(0, buildCommitLength);
+
+	    renderedBuildCommit = `${buildCommitFrom}${arrow}${buildCommitTo}`;
+	}
+
+	return {
+	    icon: icon,
+	    changed: hasRunningBuildCommitChanged,
+	    renderedBuildCommit: renderedBuildCommit,
+	};
+    },
+
     compare_ceph_versions: function(a, b) {
 	let avers = [];
 	let bvers = [];
diff --git a/www/manager6/ceph/ServiceList.js b/www/manager6/ceph/ServiceList.js
index 2dd80c14..20dfb5d0 100644
--- a/www/manager6/ceph/ServiceList.js
+++ b/www/manager6/ceph/ServiceList.js
@@ -103,21 +103,34 @@ Ext.define('PVE.node.CephServiceController', {
 	if (value === undefined) {
 	    return '';
 	}
+
 	let view = this.getView();
-	let host = rec.data.host, nodev = [0];
+	let host = rec.data.host;
+
+	let nodeVersion = [0];
+	let nodeBuildCommit = '';
+
 	if (view.nodeversions[host] !== undefined) {
-	    nodev = view.nodeversions[host].version.parts;
+	    nodeVersion = view.nodeversions[host].version.parts;
+	    nodeBuildCommit = view.nodeversions[host].buildcommit;
 	}
 
-	let icon = '';
-	if (PVE.Utils.compare_ceph_versions(view.maxversion, nodev) > 0) {
-	    icon = PVE.Utils.get_ceph_icon_html('HEALTH_UPGRADE');
-	} else if (PVE.Utils.compare_ceph_versions(nodev, value) > 0) {
-	    icon = PVE.Utils.get_ceph_icon_html('HEALTH_OLD');
-	} else if (view.mixedversions) {
-	    icon = PVE.Utils.get_ceph_icon_html('HEALTH_OK');
+	let versionInfo = {
+	    runningVersion: value,
+	    installedVersion: nodeVersion,
+	    runningBuildCommit: PVE.Utils.parseCephBuildCommit(rec.data) ?? '',
+	    installedBuildCommit: nodeBuildCommit,
+	    maxVersion: view.maxversion,
+	    hasMixedVersions: view.mixedversions,
+	};
+
+	let { icon, renderedBuildCommit } = PVE.Utils.renderCephBuildCommit(versionInfo, 9);
+
+	if (renderedBuildCommit) {
+	    return `${icon}${value} (build: ${renderedBuildCommit})`;
 	}
-	return icon + value;
+
+	return `${icon}${value}`;
     },
 
     getMaxVersions: function(store, records, success) {
diff --git a/www/manager6/ceph/Services.js b/www/manager6/ceph/Services.js
index dfafee43..ff6f80e9 100644
--- a/www/manager6/ceph/Services.js
+++ b/www/manager6/ceph/Services.js
@@ -155,6 +155,7 @@ Ext.define('PVE.ceph.Services', {
 		    title: metadata[type][id].name || name,
 		    host: host,
 		    version: PVE.Utils.parse_ceph_version(metadata[type][id]),
+		    buildcommit: PVE.Utils.parseCephBuildCommit(metadata[type][id]),
 		    service: metadata[type][id].service,
 		    addr: metadata[type][id].addr || metadata[type][id].addrs || Proxmox.Utils.unknownText,
 		};
@@ -181,7 +182,15 @@ Ext.define('PVE.ceph.Services', {
 		}
 
 		if (result.version) {
-		    result.statuses.push(gettext('Version') + ": " + result.version);
+		    let installedBuildCommit = metadata.node[host]?.buildcommit ?? '';
+		    let runningBuildCommit = result.buildcommit ?? '';
+
+		    let statusLine = gettext('Version') + `: ${result.version}`;
+		    if (runningBuildCommit) {
+			statusLine += ` (build: ${runningBuildCommit.substring(0, 9)})`;
+		    }
+
+		    result.statuses.push(statusLine);
 
 		    if (PVE.Utils.compare_ceph_versions(result.version, maxversion) !== 0) {
 			let host_version = metadata.node[host]?.version?.parts || metadata.version?.[host] || "";
@@ -202,6 +211,14 @@ Ext.define('PVE.ceph.Services', {
 				gettext('Other cluster members use a newer version of this service, please upgrade and restart'),
 			    );
 			}
+		    } else if (installedBuildCommit !== "" && runningBuildCommit !== installedBuildCommit) {
+			if (result.health > healthstates.HEALTH_OLD) {
+			    result.health = healthstates.HEALTH_OLD;
+			}
+			result.messages.push(
+			    PVE.Utils.get_ceph_icon_html('HEALTH_OLD', true) +
+			    gettext('A newer build of this release was installed but old build still running, please restart'),
+			);
 		    }
 		}
 
-- 
2.39.2





More information about the pve-devel mailing list