From 9a89f45a2a2833cfd617a52420fff4a08e72b1b4 Mon Sep 17 00:00:00 2001 From: Francesco Torchia Date: Sun, 1 Dec 2024 15:13:19 +0100 Subject: [PATCH 1/5] Add unsupported server version check Signed-off-by: Francesco Torchia --- pkg/harvester/l10n/en-us.yaml | 5 ++ .../pages/c/_cluster/unsupported/index.vue | 85 +++++++++++++++++++ pkg/harvester/routing/harvester-routing.js | 17 ++++ .../store/harvester-store/actions.ts | 13 +++ 4 files changed, 120 insertions(+) create mode 100644 pkg/harvester/pages/c/_cluster/unsupported/index.vue diff --git a/pkg/harvester/l10n/en-us.yaml b/pkg/harvester/l10n/en-us.yaml index edec8730..4ea5e043 100644 --- a/pkg/harvester/l10n/en-us.yaml +++ b/pkg/harvester/l10n/en-us.yaml @@ -39,6 +39,11 @@ generic: basic: Basic loading: Loading... +unsupported: + serverVersion: 'Current version: {serverVersion}' + description: Harvester ui only supports Harvester cluster versions greater or equal to 1.3.0 + learnMore: Learn more about Harvester from the Harvester Web Site or read the Harvester Docs + nav: group: networks: Networks diff --git a/pkg/harvester/pages/c/_cluster/unsupported/index.vue b/pkg/harvester/pages/c/_cluster/unsupported/index.vue new file mode 100644 index 00000000..1eca2759 --- /dev/null +++ b/pkg/harvester/pages/c/_cluster/unsupported/index.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/pkg/harvester/routing/harvester-routing.js b/pkg/harvester/routing/harvester-routing.js index 2d79e800..19cd6f69 100644 --- a/pkg/harvester/routing/harvester-routing.js +++ b/pkg/harvester/routing/harvester-routing.js @@ -15,8 +15,25 @@ import HarvesterAirgapUpdgrade from '../pages/c/_cluster/airgapupgrade/index.vue import HarvesterMembers from '../pages/c/_cluster/members/index.vue'; import ProjectNamespaces from '../pages/c/_cluster/projectsnamespaces.vue'; import HarvesterAlertmanagerReceiver from '../pages/c/_cluster/alertmanagerconfig/_alertmanagerconfigid/receiver.vue'; +import HarvesterUnsupported from '../pages/c/_cluster/unsupported/index.vue'; const routes = [ + { + route: { + name: `${ PRODUCT_NAME }-c-cluster-unsupported-standalone`, + path: `/:product`, + component: HarvesterUnsupported + }, + parent: 'blank' + }, + { + route: { + name: `${ PRODUCT_NAME }-c-cluster-unsupported`, + path: `/:product`, + component: HarvesterUnsupported + }, + parent: 'plain' + }, { name: `${ PRODUCT_NAME }-c-cluster-support`, path: `/:product/c/:cluster/support`, diff --git a/pkg/harvester/store/harvester-store/actions.ts b/pkg/harvester/store/harvester-store/actions.ts index c97b1163..55d83f8e 100644 --- a/pkg/harvester/store/harvester-store/actions.ts +++ b/pkg/harvester/store/harvester-store/actions.ts @@ -101,6 +101,19 @@ export default { const res: any = await allHash(hash); + const isHarvesterVersionSupported = rootGetters['harvester-common/getFeatureEnabled']('supportHarvesterClusterVersion'); + + if (!isHarvesterVersionSupported) { + const product = rootGetters['productId']; + + this.$router?.push({ + name: `${ product }-c-cluster-unsupported${ id === 'local' ? '-standalone' : '' }`, + params: { product } + }); + + return; + } + await dispatch('cleanNamespaces', null, { root: true }); commit('updateNamespaces', { From fbd384d92302a315a1e55e2fa525daa328964b54 Mon Sep 17 00:00:00 2001 From: Francesco Torchia Date: Sun, 1 Dec 2024 17:36:58 +0100 Subject: [PATCH 2/5] Remove Harvester Manager Signed-off-by: Francesco Torchia --- pkg/harvester/config/harvester-manager.js | 86 ------ .../harvesterhci.io.management.cluster.vue | 166 ----------- pkg/harvester/index.ts | 4 - pkg/harvester/l10n/en-us.yaml | 31 -- .../harvesterhci.io.management.cluster.vue | 279 ------------------ .../harvesterhci.io.management.cluster.js | 223 -------------- 6 files changed, 789 deletions(-) delete mode 100644 pkg/harvester/config/harvester-manager.js delete mode 100644 pkg/harvester/edit/harvesterhci.io.management.cluster.vue delete mode 100644 pkg/harvester/list/harvesterhci.io.management.cluster.vue delete mode 100644 pkg/harvester/models/harvesterhci.io.management.cluster.js diff --git a/pkg/harvester/config/harvester-manager.js b/pkg/harvester/config/harvester-manager.js deleted file mode 100644 index e65a51f2..00000000 --- a/pkg/harvester/config/harvester-manager.js +++ /dev/null @@ -1,86 +0,0 @@ -import { HCI, MANAGEMENT, CAPI } from '@shell/config/types'; -import { HARVESTER, MULTI_CLUSTER } from '@shell/store/features'; -import { allHash } from '@shell/utils/promise'; -import { BLANK_CLUSTER } from '@shell/store/store-types.js'; - -export const PRODUCT_NAME = 'harvester-manager'; - -export const NAME = 'harvesterManager'; - -const harvesterClustersLocation = { - name: 'c-cluster-product-resource', - params: { - cluster: BLANK_CLUSTER, - product: NAME, - resource: HCI.CLUSTER - } -}; - -export function init($plugin, store) { - const { - product, - basicType, - spoofedType, - configureType - } = $plugin.DSL(store, NAME); - - product({ - ifHaveType: CAPI.RANCHER_CLUSTER, - ifFeature: [MULTI_CLUSTER, HARVESTER], - inStore: 'management', - icon: 'harvester', - removable: false, - showClusterSwitcher: false, - weight: 100, - to: harvesterClustersLocation, - category: 'hci', - }); - - configureType(HCI.CLUSTER, { showListMasthead: false }); - - basicType([HCI.CLUSTER]); - spoofedType({ - labelKey: 'harvesterManager.cluster.label', - name: HCI.CLUSTER, - type: HCI.CLUSTER, - namespaced: false, - weight: -1, - route: { - name: 'c-cluster-product-resource', - params: { - product: NAME, - resource: HCI.CLUSTER, - } - }, - exact: false, - schemas: [ - { - id: HCI.CLUSTER, - type: 'schema', - collectionMethods: [], - resourceFields: {}, - attributes: { namespaced: true }, - }, - ], - group: 'Root', - getInstances: async() => { - const hash = { - rancherClusters: store.dispatch('management/findAll', { type: CAPI.RANCHER_CLUSTER }), - clusters: store.dispatch('management/findAll', { type: MANAGEMENT.CLUSTER }), - }; - - if (store.getters['management/schemaFor'](MANAGEMENT.NODE)) { - hash.nodes = store.dispatch('management/findAll', { type: MANAGEMENT.NODE }); - } - - const res = await allHash(hash); - - return res.rancherClusters.map((c) => { - return { - ...c, - type: HCI.CLUSTER, - }; - }); - }, - }); -} diff --git a/pkg/harvester/edit/harvesterhci.io.management.cluster.vue b/pkg/harvester/edit/harvesterhci.io.management.cluster.vue deleted file mode 100644 index d9ff48dd..00000000 --- a/pkg/harvester/edit/harvesterhci.io.management.cluster.vue +++ /dev/null @@ -1,166 +0,0 @@ - - - diff --git a/pkg/harvester/index.ts b/pkg/harvester/index.ts index 77b25077..12412b83 100644 --- a/pkg/harvester/index.ts +++ b/pkg/harvester/index.ts @@ -20,10 +20,6 @@ export default function (plugin: IPlugin) { // Built-in icon plugin.metadata.icon = require('./icon.svg'); - - if (isDev && !isSingleVirtualCluster) { - plugin.addProduct(require('./config/harvester-manager')); - } plugin.addProduct(require('./config/harvester-cluster')); diff --git a/pkg/harvester/l10n/en-us.yaml b/pkg/harvester/l10n/en-us.yaml index 4ea5e043..666f7c9e 100644 --- a/pkg/harvester/l10n/en-us.yaml +++ b/pkg/harvester/l10n/en-us.yaml @@ -1,34 +1,3 @@ -harvesterManager: - manage: Manage - tableHeaders: - kubernetesVersion: Kubernetes Version - harvesterVersion: Harvester Version - cluster: - label: Harvester Clusters - none: There are no Harvester Clusters - learnMore: Learn more about Harvester from the Harvester Web Site or read the 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 version greater or equal to 1.3.0 - plugins: - loadError: Error loading harvester plugin - rke: - templateError: Incorrect template format - affinity: - thisPodNamespace: This VM's namespace - matchExpressions: - inNamespaces: "Workloads in these namespaces" - vmAffinityTitle: VM Scheduling - namespaces: - placeholder: e.g. default,system,base - label: Namespaces - addLabel: Add Workload Selector - topologyKey: - placeholder: 'topology.kubernetes.io/zone' - vGpu: - title: VGPUs - label: VGPU type - placeholder: 'Please select a VGPU' - generic: tip: Tip resourceExternalLinkTips: 'External Link' diff --git a/pkg/harvester/list/harvesterhci.io.management.cluster.vue b/pkg/harvester/list/harvesterhci.io.management.cluster.vue deleted file mode 100644 index 65182dc2..00000000 --- a/pkg/harvester/list/harvesterhci.io.management.cluster.vue +++ /dev/null @@ -1,279 +0,0 @@ - - - - - diff --git a/pkg/harvester/models/harvesterhci.io.management.cluster.js b/pkg/harvester/models/harvesterhci.io.management.cluster.js deleted file mode 100644 index 06574c47..00000000 --- a/pkg/harvester/models/harvesterhci.io.management.cluster.js +++ /dev/null @@ -1,223 +0,0 @@ -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 { colorForState, stateDisplay, STATES_ENUM } from '@shell/plugins/dashboard-store/resource-class'; - -export default class HciCluster extends ProvCluster { - get isSupportedHarvester() { - return this._isSupportedHarvester === undefined ? true : this._isSupportedHarvester; - } - - get harvesterVersion() { - return this._harvesterVersion; - } - - get stateObj() { - if (!this.isSupportedHarvester) { - return { error: true, message: this.t('harvesterManager.cluster.supportMessage') }; - } - - return this._stateObj; - } - - applyDefaults() { - if ( !this.spec ) { - this['spec'] = { agentEnvVars: [] }; - this['metadata'] = { namespace: DEFAULT_WORKSPACE }; - } - } - - get isReady() { - // If the Connected condition exists, use that (2.6+) - if ( this.hasCondition('Connected') ) { - return this.isCondition('Connected'); - } - - // Otherwise use Ready (older) - return this.isCondition('Ready'); - } - - get canEdit() { - return false; - } - - get stateColor() { - if (!this.isSupportedHarvester) { - return colorForState(STATES_ENUM.DENIED); - } - - return colorForState(this.state); - } - - get stateDisplay() { - if (!this.isSupportedHarvester) { - return stateDisplay(STATES_ENUM.DENIED); - } - - 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`, - 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; - } - - const url = `/k8s/clusters/${ this.status.clusterName }/v1`; - - try { - const setting = await this.$dispatch('request', { url: `${ url }/${ HCI.SETTING }s/server-version` }); - - 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 - } - } -} From fe0dc396dc0ac8e383e278b829186bc4f9b3de74 Mon Sep 17 00:00:00 2001 From: Francesco Torchia Date: Sun, 1 Dec 2024 18:29:56 +0100 Subject: [PATCH 3/5] Compatibility, "catalog.cattle.io/rancher-version": ">= 2.10.1-0" Signed-off-by: Francesco Torchia --- pkg/harvester/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/harvester/package.json b/pkg/harvester/package.json index 0ae17408..ca0a06ef 100644 --- a/pkg/harvester/package.json +++ b/pkg/harvester/package.json @@ -7,7 +7,7 @@ "annotations": { "catalog.cattle.io/display-name": "Harvester", "catalog.cattle.io/kube-version": ">= 1.16.0-0", - "catalog.cattle.io/rancher-version": ">= 2.10.0-0", + "catalog.cattle.io/rancher-version": ">= 2.10.1-0", "catalog.cattle.io/ui-extensions-version": ">= 3.0.0-0" } }, From b5af90e475d20c4aac1cb67ec48fd3b907336c29 Mon Sep 17 00:00:00 2001 From: Francesco Torchia Date: Wed, 4 Dec 2024 11:12:31 +0100 Subject: [PATCH 4/5] Fix catalog.cattle.io/ui-extensions-version annotation fro Prime usage Signed-off-by: Francesco Torchia --- pkg/harvester/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/harvester/package.json b/pkg/harvester/package.json index ca0a06ef..6670491b 100644 --- a/pkg/harvester/package.json +++ b/pkg/harvester/package.json @@ -8,7 +8,7 @@ "catalog.cattle.io/display-name": "Harvester", "catalog.cattle.io/kube-version": ">= 1.16.0-0", "catalog.cattle.io/rancher-version": ">= 2.10.1-0", - "catalog.cattle.io/ui-extensions-version": ">= 3.0.0-0" + "catalog.cattle.io/ui-extensions-version": ">= 3.0.0 < 4.0.0" } }, "icon": "https://raw.githubusercontent.com/harvester/harvester-ui-extension/main/pkg/harvester/icon.svg", From 0208a6505290d7fd57603e2c93a49ed0a036e290 Mon Sep 17 00:00:00 2001 From: Francesco Torchia Date: Wed, 4 Dec 2024 15:17:47 +0100 Subject: [PATCH 5/5] Update pkg/harvester/l10n/en-us.yaml Co-authored-by: Andy Lee --- pkg/harvester/l10n/en-us.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/harvester/l10n/en-us.yaml b/pkg/harvester/l10n/en-us.yaml index 666f7c9e..ffba1efd 100644 --- a/pkg/harvester/l10n/en-us.yaml +++ b/pkg/harvester/l10n/en-us.yaml @@ -10,7 +10,7 @@ generic: unsupported: serverVersion: 'Current version: {serverVersion}' - description: Harvester ui only supports Harvester cluster versions greater or equal to 1.3.0 + description: Harvester ui only supports Harvester cluster version greater or equal to 1.3.0. learnMore: Learn more about Harvester from the Harvester Web Site or read the Harvester Docs nav: