Add live migration progress awareness in migration tab (#271)

* Embedded VM migration detail in migration tab

Signed-off-by: Andy Lee <andy.lee@suse.com>

* update events condition

Signed-off-by: Andy Lee <andy.lee@suse.com>

---------

Signed-off-by: Andy Lee <andy.lee@suse.com>
This commit is contained in:
Andy Lee 2025-05-12 15:04:50 +08:00 committed by GitHub
parent 8410f75859
commit d16802365e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 75 additions and 2 deletions

View File

@ -33,7 +33,8 @@ const FEATURE_FLAGS = {
'efiPersistentState', 'efiPersistentState',
'untaggedNetworkSetting', 'untaggedNetworkSetting',
'skipSingleReplicaDetachedVol', 'skipSingleReplicaDetachedVol',
'thirdPartyStorage' 'thirdPartyStorage',
'liveMigrationProgress'
], ],
'v1.5.1': [], 'v1.5.1': [],
'v1.6.0': [] 'v1.6.0': []

View File

@ -17,6 +17,13 @@ export default {
default: () => { default: () => {
return {}; return {};
} }
},
vmimResource: {
type: Object,
required: true,
default: () => {
return {};
}
} }
}, },
@ -25,6 +32,12 @@ export default {
}, },
computed: { computed: {
liveMigrationProgressEnabled() {
return this.$store.getters['harvester-common/getFeatureEnabled']('liveMigrationProgress');
},
migrationPhase() {
return this.vmimResource?.status?.phase || 'N/A';
},
migrationState() { migrationState() {
return this.localResource?.status?.migrationState; return this.localResource?.status?.migrationState;
}, },
@ -58,6 +71,18 @@ export default {
<template> <template>
<div> <div>
<div
v-if="liveMigrationProgressEnabled"
class="row mb-20"
>
<div class="col span-6">
<LabelValue
:name="t('harvester.virtualMachine.detail.details.phase')"
:value="migrationPhase"
/>
</div>
</div>
<div class="row mb-20"> <div class="row mb-20">
<div class="col span-6"> <div class="col span-6">
<LabelValue <LabelValue

View File

@ -27,6 +27,8 @@ import { formatSi } from '@shell/utils/units';
const VM_METRICS_DETAIL_URL = '/api/v1/namespaces/cattle-monitoring-system/services/http:rancher-monitoring-grafana:80/proxy/d/harvester-vm-detail-1/vm-info-detail?orgId=1'; const VM_METRICS_DETAIL_URL = '/api/v1/namespaces/cattle-monitoring-system/services/http:rancher-monitoring-grafana:80/proxy/d/harvester-vm-detail-1/vm-info-detail?orgId=1';
const VM_MIGRATION_DETAIL_URL = '/api/v1/namespaces/cattle-monitoring-system/services/http:rancher-monitoring-grafana:80/proxy/d/harvester-vm-migration-details-1/harvester-vm-migration-details?orgId=1';
export default { export default {
name: 'VMIDetailsPage', name: 'VMIDetailsPage',
@ -63,6 +65,7 @@ export default {
hasResourceQuotaSchema: false, hasResourceQuotaSchema: false,
switchToCloud: false, switchToCloud: false,
VM_METRICS_DETAIL_URL, VM_METRICS_DETAIL_URL,
VM_MIGRATION_DETAIL_URL,
showVmMetrics: false, showVmMetrics: false,
}; };
}, },
@ -78,6 +81,7 @@ export default {
events: this.$store.dispatch(`${ inStore }/findAll`, { type: EVENT }), events: this.$store.dispatch(`${ inStore }/findAll`, { type: EVENT }),
allSSHs: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.SSH }), allSSHs: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.SSH }),
vmis: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.VMI }), vmis: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.VMI }),
vmims: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.VMIM }),
restore: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.RESTORE }), restore: this.$store.dispatch(`${ inStore }/findAll`, { type: HCI.RESTORE }),
}; };
@ -131,6 +135,31 @@ export default {
return this.$store.getters[`${ inStore }/all`](EVENT); return this.$store.getters[`${ inStore }/all`](EVENT);
}, },
vmim() {
const inStore = this.$store.getters['currentProduct'].inStore;
const vmimList = this.$store.getters[`${ inStore }/all`](HCI.VMIM) || [];
const migrationUid = this.vmi?.status?.migrationState?.migrationUid;
const vmim = vmimList.find((VMIM) => VMIM?.metadata?.uid === migrationUid);
return vmim;
},
migrationEvents() {
const migrationVMName = this.vmim?.metadata.name || '';
if (migrationVMName === '') {
return [];
}
return this.allEvents.filter((e) => {
const { creationTimestamp } = this.value?.metadata || {};
const involvedName = e?.involvedObject?.name;
return involvedName === migrationVMName && e.firstTimestamp >= creationTimestamp;
}).sort((a, b) => a.lastTimestamp > b.lastTimestamp);
},
events() { events() {
return this.allEvents.filter((e) => { return this.allEvents.filter((e) => {
const { name, creationTimestamp } = this.value?.metadata || {}; const { name, creationTimestamp } = this.value?.metadata || {};
@ -138,7 +167,6 @@ export default {
const pvcName = this.value.persistentVolumeClaimName || []; const pvcName = this.value.persistentVolumeClaimName || [];
const involvedName = e?.involvedObject?.name; const involvedName = e?.involvedObject?.name;
const matchPVC = pvcName.find((name) => name === involvedName); const matchPVC = pvcName.find((name) => name === involvedName);
return (involvedName === name || involvedName === podName || matchPVC) && e.firstTimestamp >= creationTimestamp; return (involvedName === name || involvedName === podName || matchPVC) && e.firstTimestamp >= creationTimestamp;
@ -157,6 +185,10 @@ export default {
vm: this.value.name vm: this.value.name
}; };
}, },
liveMigrationProgressEnabled() {
return this.$store.getters['harvester-common/getFeatureEnabled']('liveMigrationProgress');
},
}, },
methods: { methods: {
@ -346,6 +378,20 @@ export default {
<Migration <Migration
:value="value" :value="value"
:vmi-resource="vmi" :vmi-resource="vmi"
:vmim-resource="vmim"
/>
<DashboardMetrics
v-if="showVmMetrics && liveMigrationProgressEnabled"
:detail-url="VM_MIGRATION_DETAIL_URL"
graph-height="640px"
:has-summary-and-detail="false"
:vars="graphVars"
class="mb-30"
/>
<Events
v-if="liveMigrationProgressEnabled"
:resource="vmi"
:events="migrationEvents"
/> />
</Tab> </Tab>

View File

@ -745,6 +745,7 @@ harvester:
dedicatedResources: Dedicated Resources dedicatedResources: Dedicated Resources
down: Virtual machine not running down: Virtual machine not running
affinityRules: Affinity Rules affinityRules: Affinity Rules
phase: Phase
sourceNode: Source Node sourceNode: Source Node
targetNode: Target Node targetNode: Target Node
started: Started started: Started