mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2025-12-13 13:11:43 +00:00
show volume encryption in vm detail volume tab
Signed-off-by: andy.lee <andy.lee@suse.com>
This commit is contained in:
parent
958e97f769
commit
db21093670
@ -114,7 +114,7 @@ export default {
|
||||
|
||||
<div
|
||||
data-testid="input-hec-bus"
|
||||
class="col span-3"
|
||||
class="col span-6"
|
||||
>
|
||||
<InputOrDisplay
|
||||
:name="t('harvester.virtualMachine.volume.bus')"
|
||||
|
||||
@ -8,6 +8,9 @@ import { PVC } from '@shell/config/types';
|
||||
import { formatSi, parseSi } from '@shell/utils/units';
|
||||
import { HCI } from '../../../../types';
|
||||
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: 'HarvesterEditVMImage',
|
||||
@ -15,7 +18,7 @@ export default {
|
||||
emits: ['update'],
|
||||
|
||||
components: {
|
||||
UnitInput, LabeledInput, LabeledSelect, InputOrDisplay
|
||||
UnitInput, LabeledInput, LabeledSelect, InputOrDisplay, LabelValue
|
||||
},
|
||||
|
||||
props: {
|
||||
@ -75,6 +78,14 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
encryptionValue() {
|
||||
return ucFirst(String(this.value.isEncrypted));
|
||||
},
|
||||
|
||||
isView() {
|
||||
return this.mode === _VIEW;
|
||||
},
|
||||
|
||||
imagesOption() {
|
||||
return this.images.filter(c => c.isReady).sort((a, b) => a.creationTimestamp > b.creationTimestamp ? -1 : 1).map( (I) => {
|
||||
return {
|
||||
@ -272,7 +283,7 @@ export default {
|
||||
<div class="row mb-20">
|
||||
<div
|
||||
data-testid="input-hevi-bus"
|
||||
class="col span-3"
|
||||
class="col span-6"
|
||||
>
|
||||
<InputOrDisplay
|
||||
:name="t('harvester.virtualMachine.volume.bus')"
|
||||
@ -288,6 +299,15 @@ export default {
|
||||
/>
|
||||
</InputOrDisplay>
|
||||
</div>
|
||||
<div
|
||||
v-if="isView"
|
||||
class="col span-6"
|
||||
>
|
||||
<LabelValue
|
||||
:name="t('harvester.virtualMachine.volume.encryption')"
|
||||
:value="encryptionValue"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -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 {
|
||||
<div class="row mb-20">
|
||||
<div
|
||||
data-testid="input-hev-bus"
|
||||
class="col span-3"
|
||||
class="col span-6"
|
||||
>
|
||||
<InputOrDisplay :name="t('harvester.virtualMachine.volume.bus')" :value="value.bus" :mode="mode">
|
||||
<LabeledSelect
|
||||
@ -228,6 +238,15 @@ export default {
|
||||
/>
|
||||
</InputOrDisplay>
|
||||
</div>
|
||||
<div
|
||||
v-if="isView"
|
||||
class="col span-6"
|
||||
>
|
||||
<LabelValue
|
||||
:name="t('harvester.virtualMachine.volume.encryption')"
|
||||
:value="encryptionValue"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 }}
|
||||
<i v-if="lockIconTooltipMessage(scope.row)" v-tooltip="lockIconTooltipMessage(scope.row)" class="icon icon-lock" />
|
||||
<i
|
||||
v-if="lockIconTooltipMessage(scope.row)"
|
||||
v-tooltip="lockIconTooltipMessage(scope.row)"
|
||||
class="icon icon-lock"
|
||||
:class="{'green-icon': scope.row.encryptedVolumeType === 'all', 'yellow-icon': scope.row.encryptedVolumeType === 'partial'}"
|
||||
/>
|
||||
</router-link>
|
||||
<span v-else>
|
||||
{{ 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;
|
||||
|
||||
@ -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
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user