diff --git a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/container.vue b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/container.vue index 1c44ca1e..8372665a 100644 --- a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/container.vue +++ b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/container.vue @@ -114,7 +114,7 @@ export default {
c.isReady).sort((a, b) => a.creationTimestamp > b.creationTimestamp ? -1 : 1).map( (I) => { return { @@ -272,7 +283,7 @@ export default {
+
+ +
diff --git a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/volume.vue b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/volume.vue index 14914834..5b7e764b 100644 --- a/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/volume.vue +++ b/pkg/harvester/edit/kubevirt.io.virtualmachine/VirtualMachineVolume/type/volume.vue @@ -8,6 +8,9 @@ import LabeledSelect from '@shell/components/form/LabeledSelect'; import { PVC, STORAGE_CLASS } from '@shell/config/types'; import { formatSi, parseSi } from '@shell/utils/units'; import { VOLUME_TYPE, InterfaceOption } from '../../../../config/harvester-map'; +import { _VIEW } from '@shell/config/query-params'; +import LabelValue from '@shell/components/LabelValue'; +import { ucFirst } from '@shell/utils/string'; export default { name: 'HarvesterEditVolume', @@ -15,7 +18,7 @@ export default { emits: ['update'], components: { - InputOrDisplay, Loading, LabeledInput, LabeledSelect, UnitInput, + InputOrDisplay, Loading, LabeledInput, LabeledSelect, UnitInput, LabelValue }, props: { @@ -61,6 +64,13 @@ export default { }, computed: { + encryptionValue() { + return ucFirst(String(this.value.isEncrypted)); + }, + + isView() { + return this.mode === _VIEW; + }, pvcsResource() { const allPVCs = this.$store.getters['harvester/all'](PVC) || []; @@ -215,7 +225,7 @@ export default {
+
+ +
diff --git a/pkg/harvester/l10n/en-us.yaml b/pkg/harvester/l10n/en-us.yaml index 90886ba9..a96279cb 100644 --- a/pkg/harvester/l10n/en-us.yaml +++ b/pkg/harvester/l10n/en-us.yaml @@ -596,6 +596,10 @@ harvester: addContainer: Add Container setFirst: Set as root volume saveVolume: Update Volume + encryption: Encryption + lockTooltip: + all: All volumes are encrypted + partial: Partial volumes are encrypted title: vmImage: Image Volume existingVolume: Existing Volume @@ -640,10 +644,6 @@ harvester: userTips: The user to be added must already exist; otherwise, the credentials will not take effect. duplicatedUser: User already exists. invalidUser: Invalid Username. - lockIconTooltip: - image: Encrypted Image - volume: Encrypted Volume - both: Encrypted Image and Encrypted Volume input: name: Name memory: Memory diff --git a/pkg/harvester/list/kubevirt.io.virtualmachine.vue b/pkg/harvester/list/kubevirt.io.virtualmachine.vue index f9b499f2..0501a210 100644 --- a/pkg/harvester/list/kubevirt.io.virtualmachine.vue +++ b/pkg/harvester/list/kubevirt.io.virtualmachine.vue @@ -173,15 +173,15 @@ export default { methods: { lockIconTooltipMessage(row) { - if (row.isVMImageEncrypted && row.isVolumeEncrypted) { - return this.t('harvester.virtualMachine.lockIconTooltip.both'); - } else if (row.isVMImageEncrypted) { - return this.t('harvester.virtualMachine.lockIconTooltip.image'); - } else if (row.isVolumeEncrypted) { - return this.t('harvester.virtualMachine.lockIconTooltip.volume'); + const message = ''; + + if (row.encryptedVolumeType === 'all') { + return this.t('harvester.virtualMachine.volume.lockTooltip.all'); + } else if (row.encryptedVolumeType === 'partial') { + return this.t('harvester.virtualMachine.volume.lockTooltip.partial'); } - return ''; + return message; } } }; @@ -213,7 +213,12 @@ export default { :to="scope.row.detailLocation" > {{ scope.row.metadata.name }} - + {{ scope.row.metadata.name }} @@ -234,6 +239,14 @@ export default { } } +.green-icon { + color: var(--success); +} + +.yellow-icon { + color: var(--warning); +} + .name-console { display: flex; align-items: center; diff --git a/pkg/harvester/mixins/harvester-vm/index.js b/pkg/harvester/mixins/harvester-vm/index.js index 6a521a7e..e668add3 100644 --- a/pkg/harvester/mixins/harvester-vm/index.js +++ b/pkg/harvester/mixins/harvester-vm/index.js @@ -418,8 +418,10 @@ export default { let size = '10Gi'; const imageResource = this.images.find( I => this.imageId === I.id); + const isIsoImage = /iso$/i.test(imageResource?.imageSuffix); const imageSize = Math.max(imageResource?.status?.size, imageResource?.status?.virtualSize); + const isEncrypted = imageResource?.isEncrypted || false; if (isIsoImage) { bus = 'sata'; @@ -447,6 +449,7 @@ export default { storageClassName: '', image: this.imageId, volumeMode: 'Block', + isEncrypted }); } else { out = _disks.map( (DISK, index) => { @@ -523,7 +526,11 @@ export default { minExponent: 3, }); - const volumeStatus = this.pvcs.find(P => P.id === `${ this.value.metadata.namespace }/${ volumeName }`)?.relatedPV?.metadata?.annotations?.[HCI_ANNOTATIONS.VOLUME_ERROR]; + const pvc = this.pvcs.find(P => P.id === `${ this.value.metadata.namespace }/${ volumeName }`); + + const volumeStatus = pvc?.relatedPV?.metadata?.annotations?.[HCI_ANNOTATIONS.VOLUME_ERROR]; + + const isEncrypted = pvc?.isEncrypted || false; return { id: randomStr(5), @@ -543,7 +550,8 @@ export default { hotpluggable, volumeStatus, dataSource, - namespace + namespace, + isEncrypted }; }); } diff --git a/pkg/harvester/models/harvester/persistentvolumeclaim.js b/pkg/harvester/models/harvester/persistentvolumeclaim.js index 645b1586..2394ca4f 100644 --- a/pkg/harvester/models/harvester/persistentvolumeclaim.js +++ b/pkg/harvester/models/harvester/persistentvolumeclaim.js @@ -214,7 +214,7 @@ export default class HciPv extends HarvesterResource { } get isEncrypted() { - return this.relatedPV?.spec.csi.volumeAttributes.encrypted || false; + return Boolean(this.relatedPV?.spec.csi.volumeAttributes.encrypted) || false; } get longhornVolume() { diff --git a/pkg/harvester/models/kubevirt.io.virtualmachine.js b/pkg/harvester/models/kubevirt.io.virtualmachine.js index 82652bd0..b274f887 100644 --- a/pkg/harvester/models/kubevirt.io.virtualmachine.js +++ b/pkg/harvester/models/kubevirt.io.virtualmachine.js @@ -574,27 +574,20 @@ export default class VirtVm extends HarvesterResource { return vmis.find(VMI => VMI.id === this.id); } - get isVMImageEncrypted() { - const inStore = this.productInStore; - const imageList = this.$rootGetters[`${ inStore }/all`](HCI.IMAGE); - const rootImage = imageList.find(image => this.rootImageId === image.id); - - return rootImage?.isEncrypted || false; - } - - get isVolumeEncrypted() { + get encryptedVolumeType() { const inStore = this.productInStore; const pvcs = this.$rootGetters[`${ inStore }/all`](PVC); - // filter out the root image PVC - const nonRootImagePVCs = pvcs.filter(pvc => !pvc.metadata.annotations[HCI_ANNOTATIONS.IMAGE_ID]); + const volumeClaimNames = this.spec.template.spec.volumes?.map(v => v.persistentVolumeClaim?.claimName).filter(v => !!v) || []; + const volumes = pvcs.filter(pvc => volumeClaimNames.includes(pvc.metadata.name)); - const volumeClaimNames = this.spec.template.spec.volumes?.map(v => v.persistentVolumeClaim?.claimName).map(v => v) || []; - - const pvcVolumes = nonRootImagePVCs.filter(pvc => volumeClaimNames.includes(pvc.metadata.name)); - - // if any non-rootImage PCV volume is encrypted, return true, otherwise return false - return pvcVolumes.some(pvcVol => pvcVol.isEncrypted) ; + if (volumes.every(vol => vol.isEncrypted)) { + return 'all'; + } else if (volumes.some(vol => vol.isEncrypted)) { + return 'partial'; + } else { + return 'none'; + } } get isError() {