refactor: add customized migration plan delete model (#996) (#997)

* refactor: add customized migration plan delete model



* refactor: copilot review



* refactor: copilot review



---------


(cherry picked from commit fb6ffa3c0f)

Signed-off-by: Andy Lee <andy.lee@suse.com>
Co-authored-by: Andy Lee <andy.lee@suse.com>
This commit is contained in:
mergify[bot]
2026-07-14 17:40:44 +08:00
committed by GitHub
co-authored by Andy Lee
parent a65b3f443e
commit 45f72749f5
4 changed files with 355 additions and 13 deletions
@@ -46,6 +46,10 @@ export default class ForkliftPlan extends HarvesterResource {
}
get stateDescription() {
if (this.metadata?.deletionTimestamp) {
return null;
}
const messages = [];
const conditions = this.status?.conditions || [];
@@ -67,7 +71,7 @@ export default class ForkliftPlan extends HarvesterResource {
get stateObj() {
return {
error: this.planFailed || this.planCritical,
transitioning: this.isMigrating,
transitioning: this.isMigrating || this.isPendingMigrationStart || !!this.metadata?.deletionTimestamp,
message: this.stateDescription,
};
}
@@ -78,6 +82,14 @@ export default class ForkliftPlan extends HarvesterResource {
return !!migration?.started && !migration?.completed;
}
// Right after creating a plan, controller status can lag briefly.
// Treat this window as in-progress so we don't flash a succeeded badge.
get isPendingMigrationStart() {
const vmCount = this.spec?.vms?.length || 0;
return vmCount > 0 && !this.planFailed && !this.planCritical && !this.planCanceled && !this.planSucceeded && !this.isMigrating;
}
get planCanceled() {
const history = this.status?.migration?.history || [];
@@ -98,6 +110,10 @@ export default class ForkliftPlan extends HarvesterResource {
}
get stateDisplay() {
if (this.metadata?.deletionTimestamp) {
return 'Terminating';
}
if (this.planFailed) {
return this.t('harvester.addons.vmMigration.plan.states.error');
}
@@ -114,10 +130,18 @@ export default class ForkliftPlan extends HarvesterResource {
return this.t('harvester.addons.vmMigration.plan.states.inProgress');
}
if (this.isPendingMigrationStart) {
return this.t('harvester.addons.vmMigration.plan.states.inProgress');
}
return this.t('harvester.addons.vmMigration.plan.states.active');
}
get stateBackground() {
if (this.metadata?.deletionTimestamp) {
return 'bg-info';
}
if (this.planFailed) {
return 'bg-error';
}
@@ -134,6 +158,10 @@ export default class ForkliftPlan extends HarvesterResource {
return 'bg-info';
}
if (this.isPendingMigrationStart) {
return 'bg-info';
}
return 'bg-success';
}
@@ -255,15 +283,4 @@ export default class ForkliftPlan extends HarvesterResource {
async deletePlan() {
await this.remove();
}
/**
* Deleting a Plan cascades via ownerReferences set at creation time.
* Kubernetes GC will automatically delete: Migration, NetworkMap, StorageMap.
* Use foreground propagation to ensure children are deleted before the parent.
*/
remove(opt = {}) {
opt.params = { ...(opt.params || {}), propagationPolicy: 'Foreground' };
return this._remove(opt);
}
}