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

* refactor: add customized migration plan delete model

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

* refactor: copilot review

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

* refactor: copilot review

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
2026-07-14 17:36:25 +08:00
committed by GitHub
parent e0436bff28
commit fb6ffa3c0f
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);
}
}