From 56e7ce5c14434d29cb6d98f266ab1b138cf04b6e Mon Sep 17 00:00:00 2001 From: Francesco Torchia Date: Sun, 1 Dec 2024 15:15:25 +0100 Subject: [PATCH 1/2] Porting - disable Harvester legacy versions Signed-off-by: Francesco Torchia --- .../config/harvester-manager.js | 8 ++ .../harvesterhci.io.management.cluster.vue | 6 ++ pkg/harvester-manager/l10n/en-us.yaml | 6 +- .../harvesterhci.io.management.cluster.vue | 22 +++-- .../harvesterhci.io.management.cluster.js | 96 +++++++++---------- 5 files changed, 80 insertions(+), 58 deletions(-) diff --git a/pkg/harvester-manager/config/harvester-manager.js b/pkg/harvester-manager/config/harvester-manager.js index f4edbc76d94..cb67cd157ae 100644 --- a/pkg/harvester-manager/config/harvester-manager.js +++ b/pkg/harvester-manager/config/harvester-manager.js @@ -104,8 +104,16 @@ export function init($plugin, store) { headers(HCI.CLUSTER, [ STATE, NAME_COL, + { + name: 'harvesterVersion', + sort: 'harvesterVersion', + labelKey: 'harvesterManager.tableHeaders.harvesterVersion', + value: 'harvesterVersion', + getValue: (row) => row.harvesterVersion + }, { ...VERSION, + labelKey: 'harvesterManager.tableHeaders.kubernetesVersion', value: 'kubernetesVersion', getValue: (row) => row.kubernetesVersion }, diff --git a/pkg/harvester-manager/edit/harvesterhci.io.management.cluster.vue b/pkg/harvester-manager/edit/harvesterhci.io.management.cluster.vue index 4943a788a76..ae69b6b7f5b 100644 --- a/pkg/harvester-manager/edit/harvesterhci.io.management.cluster.vue +++ b/pkg/harvester-manager/edit/harvesterhci.io.management.cluster.vue @@ -111,6 +111,12 @@ export default { @finish="saveOverride" @error="e=>errors = e" > + + {{ t('harvesterManager.cluster.supportMessage') }} +
Harvester Web Site or read the the Harvester Docs + learnMore: Learn more about Harvester from the Harvester Web Site or read the Harvester Docs description: Harvester is a modern Hyperconverged infrastructure (HCI) solution built for bare metal servers using enterprise-grade open source technologies including Kubernetes, Kubevirt and Longhorn. + supportMessage: Harvester ui extension only supports Harvester cluster versions greater or equal to 1.3.0 plugins: loadError: Error loading harvester plugin extension: diff --git a/pkg/harvester-manager/list/harvesterhci.io.management.cluster.vue b/pkg/harvester-manager/list/harvesterhci.io.management.cluster.vue index 3aa785da89f..dbae4edc6f8 100644 --- a/pkg/harvester-manager/list/harvesterhci.io.management.cluster.vue +++ b/pkg/harvester-manager/list/harvesterhci.io.management.cluster.vue @@ -111,15 +111,23 @@ export default { }, rows() { - return this.hciClusters.filter((c) => { - const cluster = this.mgmtClusters.find((cluster) => cluster?.metadata?.name === c?.status?.clusterName); - - return isHarvesterCluster(cluster); - }); + return this.hciClusters + .filter((c) => { + const cluster = this.mgmtClusters.find((cluster) => cluster?.metadata?.name === c?.status?.clusterName); + + return isHarvesterCluster(cluster); + }) + .map((row) => { + if (row.isReady) { + row.setSupportedHarvesterVersion(); + } + + return row; + }); }, typeDisplay() { - return this.t(`typeLabel."${ HCI.CLUSTER }"`, { count: this.row?.length || 0 }); + return this.t(`typeLabel."${ HCI.CLUSTER }"`, { count: this.rows?.length || 0 }); }, }, @@ -183,7 +191,7 @@ export default { pkg === HARVESTER_NAME)) { - console.info('Harvester plugin built is built in, skipping load from external sources'); // eslint-disable-line no-console + async goToCluster() { + this.currentRouter().push({ + name: `${ VIRTUAL }-c-cluster-resource`, + params: { + cluster: this.status.clusterName, + product: VIRTUAL, + resource: HCI.DASHBOARD // Go directly to dashboard to avoid blip of components on screen + } + }); + } + async setSupportedHarvesterVersion() { + if (this._isSupportedHarvester !== undefined) { return; } - // Determine the plugin name and the url it can be fetched from - const { pkgUrl, pkgName } = await this._pkgDetails(); + const url = `/k8s/clusters/${ this.status.clusterName }/v1`; - console.info('Harvester plugin details: ', pkgName, pkgUrl); // eslint-disable-line no-console + try { + const setting = await this.$dispatch('request', { url: `${ url }/${ HCI.SETTING }s/server-version` }); - // Skip loading if we've previously loaded the correct one - if (!!plugins[pkgName]) { - console.info('Harvester plugin already loaded, no need to load', pkgName); // eslint-disable-line no-console - - return; + this._harvesterVersion = setting?.value; + this._isSupportedHarvester = this.$rootGetters['harvester-common/getFeatureEnabled']('supportHarvesterClusterVersion', setting?.value); + } catch (error) { + console.error('unable to get harvester version from settings/server-version', error); // eslint-disable-line no-console } - - console.info('Attempting to load Harvester plugin', pkgName); // eslint-disable-line no-console - - const res = await this.$rootState.$plugin.loadAsync(pkgName, pkgUrl); - - console.info('Loaded Harvester plugin', pkgName); // eslint-disable-line no-console - - return res; - } - - async goToCluster() { - await this.loadClusterPlugin() - .then(() => { - this.currentRouter().push({ - name: `${ VIRTUAL }-c-cluster-resource`, - params: { - cluster: this.status.clusterName, - product: VIRTUAL, - resource: HCI.DASHBOARD // Go directly to dashboard to avoid blip of components on screen - } - }); - }) - .catch((err) => { - const message = typeof error === 'object' ? JSON.stringify(err) : err; - - console.error('Failed to load harvester package: ', message); // eslint-disable-line no-console - - this.$dispatch('growl/error', { - title: this.t('harvesterManager.plugins.loadError'), - message, - timeout: 5000 - }, { root: true }); - }); } } From 87f2b7b90c270b716c77bffcd1f2044839aed170 Mon Sep 17 00:00:00 2001 From: Francesco Torchia Date: Sun, 1 Dec 2024 16:51:41 +0100 Subject: [PATCH 2/2] Remove legacy pkg download logic Signed-off-by: Francesco Torchia --- .../harvesterhci.io.management.cluster.js | 140 +----------------- 1 file changed, 2 insertions(+), 138 deletions(-) diff --git a/pkg/harvester-manager/models/harvesterhci.io.management.cluster.js b/pkg/harvester-manager/models/harvesterhci.io.management.cluster.js index 0c34dbdfdfa..5cc4c83af49 100644 --- a/pkg/harvester-manager/models/harvesterhci.io.management.cluster.js +++ b/pkg/harvester-manager/models/harvesterhci.io.management.cluster.js @@ -1,7 +1,6 @@ import ProvCluster from '@shell/models/provisioning.cattle.io.cluster'; -import { DEFAULT_WORKSPACE, HCI, MANAGEMENT } from '@shell/config/types'; -import { HARVESTER_NAME, HARVESTER_NAME as VIRTUAL } from '@shell/config/features'; -import { SETTING } from '@shell/config/settings'; +import { DEFAULT_WORKSPACE, HCI } from '@shell/config/types'; +import { HARVESTER_NAME as VIRTUAL } from '@shell/config/features'; import { colorForState, stateDisplay, STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class'; export default class HciCluster extends ProvCluster { @@ -58,141 +57,6 @@ export default class HciCluster extends ProvCluster { return stateDisplay(this.state); } - /** - * Fetch and cache the response for /ui-info - * - * Storing this in a cache means any changes to `ui-info` require a dashboard refresh... but it cuts out a http request every time we - * go to a cluster - * - * @param {string} clusterId - */ - async _getUiInfo(clusterId) { - if (!this._uiInfo) { - try { - const infoUrl = `/k8s/clusters/${ clusterId }/v1/harvester/ui-info`; - - this._uiInfo = await this.$dispatch('request', { url: infoUrl }); - } catch (e) { - console.info(`Failed to fetch harvester ui-info from ${ this.nameDisplay }, this may be an older cluster that cannot provide one`); // eslint-disable-line no-console - } - } - - return this._uiInfo; - } - - /** - * Determine the harvester plugin's package name and url for legacy clusters that don't provide the package (i.e. it's coming from - * outside the cluster) - */ - _legacyClusterPkgDetails() { - let uiOfflinePreferred = this.$rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_OFFLINE_PREFERRED)?.value; - // options: ['dynamic', 'true', 'false'] - - if (uiOfflinePreferred === 'dynamic') { - // We shouldn't need to worry about the version of the dashboard when embedded in harvester (aka in isSingleProduct) - const version = this.$rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.VERSION_RANCHER)?.value; - - if (version.endsWith('-head')) { - uiOfflinePreferred = 'false'; - } else { - uiOfflinePreferred = 'true'; - } - } - - // This is the version that's embedded in the dashboard - const pkgName = `${ HARVESTER_NAME }-1.0.3`; - - if (uiOfflinePreferred === 'true') { - // Embedded (aka give me the embedded plugin that was in the last rancher release) - const embeddedPath = `${ pkgName }/${ pkgName }.umd.min.js`; - - return { - pkgUrl: process.env.dev ? `${ process.env.api }/dashboard/${ embeddedPath }` : embeddedPath, - pkgName - }; - } - - if (uiOfflinePreferred === 'false') { - // Remote (aka give me the latest version of the embedded plugin that might not have been released yet) - const uiDashboardHarvesterRemotePlugin = this.$rootGetters['management/byId'](MANAGEMENT.SETTING, SETTING.UI_DASHBOARD_HARVESTER_LEGACY_PLUGIN)?.value; - const parts = uiDashboardHarvesterRemotePlugin?.replace('.umd.min.js', '').split('/'); - const pkgNameFromUrl = parts?.length > 1 ? parts[parts.length - 1] : null; - - if (!pkgNameFromUrl) { - throw new Error(`Unable to determine harvester plugin name from '${ uiDashboardHarvesterRemotePlugin }'`); - } - - return { - pkgUrl: uiDashboardHarvesterRemotePlugin, - pkgName: pkgNameFromUrl - }; - } - - throw new Error(`Unsupported value for ${ SETTING.UI_OFFLINE_PREFERRED }: 'uiOfflinePreferred'`); - } - - /** - * Determine the harvester plugin's package name and url for clusters that provide the plugin - */ - _supportedClusterPkgDetails(uiInfo, clusterId) { - let pkgName = `${ HARVESTER_NAME }-${ uiInfo['ui-plugin-bundled-version'] }`; - const fileName = `${ pkgName }.umd.min.js`; - let pkgUrl; - - if (uiInfo['ui-source'] === 'bundled' ) { // offline bundled - pkgUrl = `/k8s/clusters/${ clusterId }/v1/harvester/plugin-assets/${ fileName }`; - } else if (uiInfo['ui-source'] === 'external') { - if (uiInfo['ui-plugin-index']) { - pkgUrl = uiInfo['ui-plugin-index']; - - // When using an external address, the pkgName should also be get from the url - const names = pkgUrl.split('/'); - const jsName = names[names.length - 1]; - - pkgName = jsName?.split('.umd.min.js')[0]; - } else { - throw new Error('Harvester cluster requested the plugin at `ui-plugin-index` is used, however did not provide a value for it'); - } - } - - return { - pkgUrl, - pkgName - }; - } - - _overridePkgDetails() { - // Support loading the pkg from a locally, or other, address - // This helps testing of the harvester plugin when packaged up, instead of directly imported - const harvesterPkgUrl = process.env.harvesterPkgUrl; - - if (!harvesterPkgUrl) { - return; - } - const parts = harvesterPkgUrl.replace('.umd.min.js', '').split('/'); - const pkgNameFromUrl = parts.length > 1 ? parts[parts.length - 1] : null; - - if (pkgNameFromUrl) { - return { - pkgUrl: harvesterPkgUrl, - pkgName: pkgNameFromUrl - }; - } - } - - async _pkgDetails() { - const overridePkgDetails = this._overridePkgDetails(); - - if (overridePkgDetails) { - return overridePkgDetails; - } - - const clusterId = this.mgmt.id; - const uiInfo = await this._getUiInfo(clusterId); - - return uiInfo ? this._supportedClusterPkgDetails(uiInfo, clusterId) : this._legacyClusterPkgDetails(); - } - async goToCluster() { this.currentRouter().push({ name: `${ VIRTUAL }-c-cluster-resource`,