mirror of
https://github.com/harvester/harvester-ui-extension.git
synced 2026-10-01 03:36:04 +08:00
Latest changes from harvester/master
Signed-off-by: Francesco Torchia <francesco.torchia@suse.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import SYSTEM_NAMESPACES from '@shell/config/system-namespaces';
|
||||
import { get } from '@shell/utils/object';
|
||||
import { NAMESPACE } from '@shell/config/types';
|
||||
import { PRODUCT_NAME as HARVESTER_PRODUCT } from '@pkg/harvester/config/harvester';
|
||||
import { HCI } from '../../types';
|
||||
|
||||
const OBSCURE_NAMESPACE_PREFIX = [
|
||||
'c-', // cluster namespace
|
||||
@@ -37,15 +38,32 @@ export default class HciNamespace extends namespace {
|
||||
weight: -10,
|
||||
};
|
||||
|
||||
const editQuotaAction = {
|
||||
action: 'editNSQuota',
|
||||
label: this.t('harvester.modal.quota.editQuota'),
|
||||
icon: 'icon icon-storage',
|
||||
enabled: !!this?.actions?.updateResourceQuota && !!this?.actions?.deleteResourceQuota,
|
||||
weight: -11,
|
||||
};
|
||||
|
||||
if (remove > -1) {
|
||||
out.splice(remove, 1);
|
||||
}
|
||||
|
||||
insertAt(out, out.length - 1, promptRemove);
|
||||
insertAt(out, out.length - 5, editQuotaAction);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
editNSQuota(resources = this) {
|
||||
this.$dispatch('promptModal', {
|
||||
resources,
|
||||
snapshotSizeQuota: this.snapshotSizeQuota,
|
||||
component: 'HarvesterQuotaDialog'
|
||||
});
|
||||
}
|
||||
|
||||
promptRemove(resources = this) {
|
||||
this.$dispatch('promptModal', {
|
||||
resources,
|
||||
@@ -54,6 +72,17 @@ export default class HciNamespace extends namespace {
|
||||
});
|
||||
}
|
||||
|
||||
get nsResourceQuota() {
|
||||
const inStore = this.$rootGetters['currentProduct'].inStore;
|
||||
const allResQuotas = this.$rootGetters[`${ inStore }/all`](HCI.RESOURCE_QUOTA);
|
||||
|
||||
return allResQuotas.find( RQ => RQ.metadata.namespace === this.id);
|
||||
}
|
||||
|
||||
get snapshotSizeQuota() {
|
||||
return this.nsResourceQuota?.spec?.snapshotLimit?.namespaceTotalSnapshotSizeQuota;
|
||||
}
|
||||
|
||||
get isSystem() {
|
||||
const systemNamespaces = ['fleet-default'];
|
||||
|
||||
|
||||
@@ -59,6 +59,22 @@ export default class HciNode extends HarvesterResource {
|
||||
total: 1
|
||||
};
|
||||
|
||||
const enableCPUManager = {
|
||||
action: 'enableCPUManager',
|
||||
enabled: this.hasAction('enableCPUManager') && !this.isCPUManagerEnableInProgress && !this.isCPUManagerEnabled && !this.isEtcd, // witness node doesn't have CPU manager
|
||||
icon: 'icon icon-fw icon-os-management',
|
||||
label: this.t('harvester.action.enableCPUManager'),
|
||||
total: 1
|
||||
};
|
||||
|
||||
const disableCPUManager = {
|
||||
action: 'disableCPUManager',
|
||||
enabled: this.hasAction('disableCPUManager') && !this.isCPUManagerEnableInProgress && this.isCPUManagerEnabled && !this.isEtcd,
|
||||
icon: 'icon icon-fw icon-os-management',
|
||||
label: this.t('harvester.action.disableCPUManager'),
|
||||
total: 1
|
||||
};
|
||||
|
||||
const shutDown = {
|
||||
action: 'shutDown',
|
||||
enabled: this.hasAction('powerActionPossible') && this.hasAction('powerAction') && !this.isStopped && !!this.inventory,
|
||||
@@ -88,6 +104,8 @@ export default class HciNode extends HarvesterResource {
|
||||
uncordon,
|
||||
enableMaintenance,
|
||||
disableMaintenance,
|
||||
enableCPUManager,
|
||||
disableCPUManager,
|
||||
shutDown,
|
||||
powerOn,
|
||||
reboot,
|
||||
@@ -134,15 +152,12 @@ export default class HciNode extends HarvesterResource {
|
||||
|
||||
get consoleUrl() {
|
||||
const url = this.metadata?.annotations?.[HCI_ANNOTATIONS.HOST_CONSOLE_URL];
|
||||
const validator = /^[a-z]+:\/\//;
|
||||
|
||||
if (!url) {
|
||||
if (!url?.match(validator)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
||||
return `http://${ url }`;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
@@ -308,6 +323,14 @@ export default class HciNode extends HarvesterResource {
|
||||
this.doAction('disableMaintenanceMode', {});
|
||||
}
|
||||
|
||||
enableCPUManager() {
|
||||
this.doActionGrowl('enableCPUManager', {});
|
||||
}
|
||||
|
||||
disableCPUManager() {
|
||||
this.doActionGrowl('disableCPUManager', {});
|
||||
}
|
||||
|
||||
get isUnSchedulable() {
|
||||
return (
|
||||
this.metadata?.labels?.[HCI_ANNOTATIONS.NODE_SCHEDULABLE] === 'false' ||
|
||||
@@ -347,6 +370,28 @@ export default class HciNode extends HarvesterResource {
|
||||
);
|
||||
}
|
||||
|
||||
get isCPUManagerEnabled() {
|
||||
return this.metadata?.labels?.[HCI_ANNOTATIONS.CPU_MANAGER] === 'true';
|
||||
}
|
||||
|
||||
get isCPUManagerEnableInProgress() {
|
||||
return this.cpuManagerUpdateStatus === 'requested' || this.cpuManagerUpdateStatus === 'running';
|
||||
}
|
||||
|
||||
get isCPUManagerEnableFailed() {
|
||||
return this.cpuManagerUpdateStatus === 'failed';
|
||||
}
|
||||
|
||||
get cpuManagerUpdateStatus() {
|
||||
try {
|
||||
const cpuManagerUpdate = JSON.parse(this.metadata.annotations[HCI_ANNOTATIONS.NODE_CPU_MANAGER_UPDATE_STATUS] || '{}');
|
||||
|
||||
return cpuManagerUpdate.status || '';
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
get longhornDisks() {
|
||||
const inStore = this.$rootGetters['currentProduct'].inStore;
|
||||
const longhornNode = this.$rootGetters[`${ inStore }/byId`](
|
||||
|
||||
@@ -20,12 +20,10 @@ export default class HciPv extends HarvesterResource {
|
||||
const storageClassName =
|
||||
realMode === _CLONE ? this.spec.storageClassName : '';
|
||||
|
||||
this['spec'] = {
|
||||
accessModes,
|
||||
this['spec'] = {accessModes,
|
||||
storageClassName,
|
||||
volumeName: '',
|
||||
resources: { requests: { storage } }
|
||||
};
|
||||
resources: { requests: { storage } }};
|
||||
}
|
||||
|
||||
get availableActions() {
|
||||
@@ -98,7 +96,6 @@ export default class HciPv extends HarvesterResource {
|
||||
}
|
||||
|
||||
get stateDisplay() {
|
||||
const ownedBy = this?.metadata?.annotations?.[HCI_ANNOTATIONS.OWNED_BY];
|
||||
const volumeError = this.relatedPV?.metadata?.annotations?.[HCI_ANNOTATIONS.VOLUME_ERROR];
|
||||
const degradedVolume = volumeError === DEGRADED_ERROR;
|
||||
const status = this?.status?.phase === 'Bound' && !volumeError && this.isLonghornVolumeReady ? 'Ready' : 'Not Ready';
|
||||
@@ -107,7 +104,7 @@ export default class HciPv extends HarvesterResource {
|
||||
|
||||
if (findBy(conditions, 'type', 'Resizing')?.status === 'True') {
|
||||
return 'Resizing';
|
||||
} else if (ownedBy && !volumeError) {
|
||||
} else if (!!this.attachVM && !volumeError) {
|
||||
return 'In-use';
|
||||
} else if (degradedVolume) {
|
||||
return 'Degraded';
|
||||
@@ -179,17 +176,19 @@ export default class HciPv extends HarvesterResource {
|
||||
}
|
||||
|
||||
get attachVM() {
|
||||
const allVMs = this.$rootGetters['harvester/all'](HCI.VM);
|
||||
const ownedBy =
|
||||
get(this, `metadata.annotations."${ HCI_ANNOTATIONS.OWNED_BY }"`) || '';
|
||||
const allVMs = this.$rootGetters['harvester/all'](HCI.VM) || [];
|
||||
|
||||
const findAttachVM = (vm) => {
|
||||
const attachVolumes = vm.spec.template?.spec?.volumes || [];
|
||||
|
||||
if (vm.namespace === this.namespace && attachVolumes.length > 0) {
|
||||
return attachVolumes.find(vol => vol.persistentVolumeClaim?.claimName === this.name);
|
||||
}
|
||||
|
||||
if (!ownedBy) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const ownedId = JSON.parse(ownedBy)[0]?.refs?.[0];
|
||||
|
||||
return allVMs.find(D => D.id === ownedId);
|
||||
return allVMs.find(findAttachVM);
|
||||
}
|
||||
|
||||
get isAvailable() {
|
||||
|
||||
@@ -9,6 +9,10 @@ export default class HciUpgrade extends HarvesterResource {
|
||||
return this?.metadata?.labels?.[HCI.LATEST_UPGRADE] === 'true';
|
||||
}
|
||||
|
||||
get isUpgradeFailed() {
|
||||
return this?.metadata?.labels?.[HCI.UPGRADE_STATE] === 'Failed';
|
||||
}
|
||||
|
||||
get isUpgradeSucceeded() {
|
||||
return this?.metadata?.labels?.[HCI.UPGRADE_STATE] === 'Succeeded';
|
||||
}
|
||||
@@ -117,10 +121,10 @@ export default class HciUpgrade extends HarvesterResource {
|
||||
get upgradeImageMessage() {
|
||||
const conditions = this?.status?.conditions || [];
|
||||
const imageReady = conditions.find( cond => cond.type === 'ImageReady');
|
||||
const hasError = imageReady?.status === 'False';
|
||||
const success = imageReady?.status === 'True';
|
||||
const message = imageReady?.message || imageReady?.reason;
|
||||
|
||||
return hasError ? message : '';
|
||||
return success ? '' : message;
|
||||
}
|
||||
|
||||
get nodeUpgradeMessage() {
|
||||
|
||||
@@ -47,7 +47,7 @@ export default class HciVmImage extends HarvesterResource {
|
||||
{
|
||||
action: 'createFromImage',
|
||||
enabled: canCreateVM,
|
||||
icon: 'icon icon-fw icon-spinner',
|
||||
icon: 'icon icon-circle-plus',
|
||||
label: this.t('harvester.action.createVM'),
|
||||
disabled: !this.isReady,
|
||||
},
|
||||
@@ -74,7 +74,7 @@ export default class HciVmImage extends HarvesterResource {
|
||||
router.push({
|
||||
name: `${ HARVESTER_PRODUCT }-c-cluster-resource-create`,
|
||||
params: { resource: HCI.VM },
|
||||
query: { image: this.id }
|
||||
query: { image: this.id, fromPage: HCI.IMAGE }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -101,6 +101,10 @@ export default class HciVmImage extends HarvesterResource {
|
||||
const imported = this.getStatusConditionOfType('Imported');
|
||||
|
||||
if (imported?.status === 'Unknown') {
|
||||
if (this.spec.sourceType === 'restore') {
|
||||
return 'Restoring';
|
||||
}
|
||||
|
||||
if (this.spec.sourceType === 'download') {
|
||||
return 'Downloading';
|
||||
}
|
||||
@@ -131,7 +135,8 @@ export default class HciVmImage extends HarvesterResource {
|
||||
const conditions = this?.status?.conditions || [];
|
||||
const initialized = conditions.find( cond => cond.type === 'Initialized');
|
||||
const imported = conditions.find( cond => cond.type === 'Imported');
|
||||
const message = initialized?.message || imported?.message;
|
||||
const retryLimitExceeded = conditions.find( cond => cond.type === 'RetryLimitExceeded');
|
||||
const message = initialized?.message || imported?.message || retryLimitExceeded?.message;
|
||||
|
||||
return ucFirst(message);
|
||||
}
|
||||
@@ -167,6 +172,21 @@ export default class HciVmImage extends HarvesterResource {
|
||||
});
|
||||
}
|
||||
|
||||
get virtualSize() {
|
||||
const virtualSize = this.status?.virtualSize;
|
||||
|
||||
if (!virtualSize) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
return formatSi(virtualSize, {
|
||||
increment: 1024,
|
||||
maxPrecision: 2,
|
||||
suffix: 'B',
|
||||
firstSuffix: 'B',
|
||||
});
|
||||
}
|
||||
|
||||
getStatusConditionOfType(type, defaultValue = []) {
|
||||
const conditions = Array.isArray(get(this, 'status.conditions')) ? this.status.conditions : defaultValue;
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ export default class VirtVm extends HarvesterResource {
|
||||
{
|
||||
action: 'softrebootVM',
|
||||
enabled: !!this.actions?.softreboot,
|
||||
icon: 'icon icon-refresh',
|
||||
icon: 'icon icon-pipeline',
|
||||
label: this.t('harvester.action.softreboot')
|
||||
},
|
||||
{
|
||||
@@ -152,9 +152,15 @@ export default class VirtVm extends HarvesterResource {
|
||||
{
|
||||
action: 'takeVMSnapshot',
|
||||
enabled: !!this.actions?.backup,
|
||||
icon: 'icon icon-backup',
|
||||
icon: 'icon icon-snapshot',
|
||||
label: this.t('harvester.action.vmSnapshot')
|
||||
},
|
||||
{
|
||||
action: 'editVMQuota',
|
||||
enabled: !!this.actions?.updateResourceQuota && !!this.actions.deleteResourceQuota,
|
||||
icon: 'icon icon-storage',
|
||||
label: this.t('harvester.action.editVMQuota')
|
||||
},
|
||||
{
|
||||
action: 'restoreVM',
|
||||
enabled: !!this.actions?.restore,
|
||||
@@ -331,6 +337,14 @@ export default class VirtVm extends HarvesterResource {
|
||||
});
|
||||
}
|
||||
|
||||
editVMQuota(resources = this) {
|
||||
this.$dispatch('promptModal', {
|
||||
resources,
|
||||
snapshotSizeQuota: this.snapshotSizeQuota,
|
||||
component: 'HarvesterQuotaDialog'
|
||||
});
|
||||
}
|
||||
|
||||
unplugVolume(diskName) {
|
||||
const resources = this;
|
||||
|
||||
@@ -541,6 +555,17 @@ export default class VirtVm extends HarvesterResource {
|
||||
return null;
|
||||
}
|
||||
|
||||
get nsResourceQuota() {
|
||||
const inStore = this.productInStore;
|
||||
const allResQuotas = this.$rootGetters[`${ inStore }/all`](HCI.RESOURCE_QUOTA);
|
||||
|
||||
return allResQuotas.find( RQ => RQ.namespace === this.metadata.namespace);
|
||||
}
|
||||
|
||||
get snapshotSizeQuota() {
|
||||
return this.nsResourceQuota?.spec?.snapshotLimit?.vmTotalSnapshotSizeQuota?.[this.metadata.name];
|
||||
}
|
||||
|
||||
get vmi() {
|
||||
const inStore = this.productInStore;
|
||||
|
||||
@@ -646,6 +671,10 @@ export default class VirtVm extends HarvesterResource {
|
||||
return null;
|
||||
}
|
||||
|
||||
get isTerminating() {
|
||||
return !!this?.metadata?.deletionTimestamp;
|
||||
}
|
||||
|
||||
get otherState() {
|
||||
const state = (this.vmi &&
|
||||
[VMIPhase.Scheduling, VMIPhase.Scheduled].includes(
|
||||
@@ -685,18 +714,21 @@ export default class VirtVm extends HarvesterResource {
|
||||
|
||||
const allRestore = this.$rootGetters[`${ inStore }/all`](HCI.RESTORE);
|
||||
|
||||
return allRestore.find(O => O.id === id);
|
||||
const res = allRestore.find(O => O.id === id);
|
||||
|
||||
if (res) {
|
||||
const allBackups = this.$rootGetters[`${ inStore }/all`](HCI.BACKUP);
|
||||
|
||||
res.fromSnapshot = !!allBackups
|
||||
.filter(b => b.spec?.type !== BACKUP_TYPE.BACKUP)
|
||||
.find(s => s.id === `${ res.spec?.virtualMachineBackupNamespace }/${ res.spec?.virtualMachineBackupName }`);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
get restoreProgress() {
|
||||
const inStore = this.productInStore;
|
||||
const allBackups = this.$rootGetters[`${ inStore }/all`](HCI.BACKUP);
|
||||
|
||||
const isSnapshotRestore = !!allBackups
|
||||
.filter(b => b.spec?.type !== BACKUP_TYPE.BACKUP)
|
||||
.find(s => s.id === `${ this.restoreResource?.spec?.virtualMachineBackupNamespace }/${ this.restoreResource?.spec?.virtualMachineBackupName }`);
|
||||
|
||||
if (isSnapshotRestore) {
|
||||
if (this.isVMError || this.isTerminating) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -726,7 +758,7 @@ export default class VirtVm extends HarvesterResource {
|
||||
return 'Restoring';
|
||||
}
|
||||
|
||||
if (this?.metadata?.deletionTimestamp) {
|
||||
if (this.isTerminating) {
|
||||
return 'Terminating';
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user