From 2604101eb2214c9b307e8363a43bac34605afc57 Mon Sep 17 00:00:00 2001 From: Yi-Ya Chen Date: Tue, 14 Jan 2025 16:16:56 +0800 Subject: [PATCH] refactor: move logic to node model Signed-off-by: Yi-Ya Chen (cherry picked from commit 43b10b250ef1dc89982a54677c53de040b009f4d) --- pkg/harvester/list/harvesterhci.io.host.vue | 36 +--------------- pkg/harvester/models/harvester/node.js | 48 ++++++++++++++++++++- 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/pkg/harvester/list/harvesterhci.io.host.vue b/pkg/harvester/list/harvesterhci.io.host.vue index 4bee3f4c..6ad60496 100644 --- a/pkg/harvester/list/harvesterhci.io.host.vue +++ b/pkg/harvester/list/harvesterhci.io.host.vue @@ -3,7 +3,7 @@ import ResourceTable from '@shell/components/ResourceTable'; import Loading from '@shell/components/Loading'; import { STATE, NAME, AGE } from '@shell/config/table-headers'; import { - CAPI, METRIC, NODE, SCHEMA, LONGHORN, POD, MANAGEMENT, NORMAN + CAPI, METRIC, NODE, SCHEMA, LONGHORN, POD } from '@shell/config/types'; import { allHash } from '@shell/utils/promise'; import metricPoller from '@shell/mixins/metric-poller'; @@ -62,42 +62,8 @@ export default { _hash.machines = this.$store.dispatch(`${ inStore }/findAll`, { type: CAPI.MACHINE }); } - if ( - this.$store.getters['rancher/schemaFor'](NORMAN.PRINCIPAL) && - this.$store.getters['rancher/schemaFor'](NORMAN.CLUSTER_ROLE_TEMPLATE_BINDING) - ) { - _hash.normanPrincipal = this.$store.dispatch('rancher/findAll', { type: NORMAN.PRINCIPAL }); - _hash.clusterRoleTemplateBinding = this.$store.dispatch(`management/findAll`, { type: MANAGEMENT.CLUSTER_ROLE_TEMPLATE_BINDING }); - } - const hash = await allHash(_hash); - // Remove delete action if current user role is cluster member - if (hash.normanPrincipal && hash.clusterRoleTemplateBinding) { - const role = hash.clusterRoleTemplateBinding.find( - (template) => template.userPrincipalName === hash.normanPrincipal[0]?.id - ); - const isClusterMember = role?.roleTemplateName === 'cluster-member'; - - if (isClusterMember) { - hash.nodes = hash.nodes.map((node) => { - const updatedActions = node.availableActions.map((action) => { - return action.action === 'promptRemove' ? { ...action, enabled: false } : action; - }); - - // keep availableActions non-enumerable - Object.defineProperty(node, 'availableActions', { - value: updatedActions, - writable: true, - enumerable: false, - configurable: true, - }); - - return node; - }); - } - } - this.rows = hash.nodes; }, diff --git a/pkg/harvester/models/harvester/node.js b/pkg/harvester/models/harvester/node.js index b265db35..dd7c9b69 100644 --- a/pkg/harvester/models/harvester/node.js +++ b/pkg/harvester/models/harvester/node.js @@ -1,5 +1,5 @@ import pickBy from 'lodash/pickBy'; -import { CAPI, LONGHORN, POD, NODE } from '@shell/config/types'; +import { CAPI, LONGHORN, POD, NODE, NORMAN } from '@shell/config/types'; import { CAPI as CAPI_ANNOTATIONS } from '@shell/config/labels-annotations.js'; import { HCI as HCI_ANNOTATIONS } from '@pkg/harvester/config/labels-annotations'; import { clone } from '@shell/utils/object'; @@ -25,7 +25,17 @@ const HEALTHY = 'healthy'; const WARNING = 'warning'; export default class HciNode extends HarvesterResource { + constructor(...args) { + super(...args); + this._roleBasedActions = []; + this._initialized = false; // flag to prevent repeated initialization + } + get _availableActions() { + if (!this._initialized) { + this.setupRoleBasedActions(); + } + const cordon = { action: 'cordon', enabled: this.hasAction('cordon') && !this.isCordoned, @@ -108,10 +118,44 @@ export default class HciNode extends HarvesterResource { shutDown, powerOn, reboot, - ...super._availableActions + ...this._roleBasedActions || [] ]; } + async setupRoleBasedActions() { + const baseActions = super._availableActions || []; + + // access control is only available on the multiple cluster Harvester + if (this.$rootGetters['isStandaloneHarvester']) { + this._roleBasedActions = baseActions; + } else { + this._roleBasedActions = await this._updateRoleBasedActions(baseActions); + } + + this._initialized = true; + } + + async _updateRoleBasedActions(actions) { + const hasSchema = (type) => this.$rootGetters['rancher/schemaFor'](type); + + if (!hasSchema(NORMAN.PRINCIPAL) || !hasSchema(NORMAN.CLUSTER_ROLE_TEMPLATE_BINDING)) return actions; + + try { + const templates = await this.$dispatch('rancher/findAll', { type: NORMAN.CLUSTER_ROLE_TEMPLATE_BINDING }, { root: true }); + const [currentUser] = this.$rootGetters['rancher/all'](NORMAN.PRINCIPAL) || []; + const userRole = templates.find((template) => template.userPrincipalId === currentUser?.id); + + if (userRole?.roleTemplateId === 'cluster-member') { + return actions.filter((action) => action.action !== 'promptRemove'); + } + } catch (error) { + // eslint-disable-next-line no-console + console.error('Error fetching role-based actions:', error); + } + + return actions; + } + promptRemove(resources = this) { this.$dispatch('promptModal', { resources,