-
Notifications
You must be signed in to change notification settings - Fork 0
<fix>[compute]: hard delete host file if created state vm destroyed #3889
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: zsv_5.0.0
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,15 +16,21 @@ | |
| import org.zstack.header.vm.VmDeletionStruct; | ||
| import org.zstack.header.vm.VmInstanceConstant; | ||
| import org.zstack.header.vm.VmInstanceDeletionPolicyManager.VmInstanceDeletionPolicy; | ||
| import org.zstack.header.vm.VmInstanceInventory; | ||
| import org.zstack.header.vm.VmInstanceState; | ||
| import org.zstack.header.vm.VmInstanceVO; | ||
| import org.zstack.header.vm.VmInstanceVO_; | ||
| import org.zstack.header.vm.additions.VmHostFileDeletionMsg; | ||
| import org.zstack.header.vm.additions.VmHostFileVO; | ||
| import org.zstack.header.vm.additions.VmHostFileVO_; | ||
| import org.zstack.utils.CollectionUtils; | ||
| import org.zstack.utils.Utils; | ||
| import org.zstack.utils.logging.CLogger; | ||
|
|
||
| import java.util.HashSet; | ||
| import java.util.List; | ||
| import java.util.Set; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| import static org.zstack.core.Platform.operr; | ||
| import static org.zstack.utils.CollectionDSL.list; | ||
|
|
@@ -44,8 +50,9 @@ public class VmHostFileCascadeExtension extends AbstractAsyncCascadeExtension { | |
| public void asyncCascade(CascadeAction action, Completion completion) { | ||
| if (action.isActionCode(CascadeConstant.DELETION_CHECK_CODE)) { | ||
| handleDeletionCheck(action, completion); | ||
| } else if (action.isActionCode(CascadeConstant.DELETION_DELETE_CODE, CascadeConstant.DELETION_FORCE_DELETE_CODE) | ||
| || action.isActionCode(CascadeConstant.VM_INSTANCE_EXPUNGE_CODE)) { | ||
| } else if (action.isActionCode(CascadeConstant.VM_INSTANCE_EXPUNGE_CODE)) { | ||
| handleDeletion(action, completion); | ||
| } else if (action.isActionCode(CascadeConstant.DELETION_DELETE_CODE, CascadeConstant.DELETION_FORCE_DELETE_CODE)) { | ||
| if (shouldDeferVmAssociatedDeletion(action)) { | ||
| completion.success(); | ||
| return; | ||
|
|
@@ -65,6 +72,13 @@ private boolean shouldDeferVmAssociatedDeletion(CascadeAction action) { | |
| if (!VmInstanceVO.class.getSimpleName().equals(action.getParentIssuer())) { | ||
| return false; | ||
| } | ||
| if (hasCreatedVmInDeletionContext(action)) { | ||
| logger.info(String.format( | ||
| "VmHostFileCascadeExtension: skip deferring host-file deletion for Created VM(s): %s; " | ||
| + "destroy uses DBOnly hard-delete without expunge, host files must be removed in this cascade", | ||
| formatCreatedVmUuidsFromContext(action))); | ||
| return false; | ||
|
Comment on lines
+75
to
+80
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 不要因为一个 这里是按 action 维度放开 defer:只要 🤖 Prompt for AI Agents |
||
| } | ||
| Object raw = action.getParentIssuerContext(); | ||
| if (!(raw instanceof List)) { | ||
| return false; | ||
|
|
@@ -82,6 +96,37 @@ private boolean shouldDeferVmAssociatedDeletion(CascadeAction action) { | |
| return false; | ||
| } | ||
|
|
||
| private boolean hasCreatedVmInDeletionContext(CascadeAction action) { | ||
| Object raw = action.getParentIssuerContext(); | ||
| if (!(raw instanceof List)) { | ||
| return false; | ||
| } | ||
| for (Object o : (List<?>) raw) { | ||
| if (!(o instanceof VmDeletionStruct)) { | ||
| continue; | ||
| } | ||
| VmInstanceInventory inv = ((VmDeletionStruct) o).getInventory(); | ||
| if (inv != null && VmInstanceState.Created.toString().equals(inv.getState())) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| private String formatCreatedVmUuidsFromContext(CascadeAction action) { | ||
| Object raw = action.getParentIssuerContext(); | ||
| if (!(raw instanceof List)) { | ||
| return "[]"; | ||
| } | ||
| return ((List<?>) raw).stream() | ||
| .filter(VmDeletionStruct.class::isInstance) | ||
| .map(VmDeletionStruct.class::cast) | ||
| .map(VmDeletionStruct::getInventory) | ||
| .filter(inv -> inv != null && VmInstanceState.Created.toString().equals(inv.getState())) | ||
| .map(VmInstanceInventory::getUuid) | ||
| .collect(Collectors.joining(", ")); | ||
| } | ||
|
|
||
| private List<VmHostFileVO> voFromAction(CascadeAction action) { | ||
| if (VmInstanceVO.class.getSimpleName().equals(action.getParentIssuer())) { | ||
| List<VmDeletionStruct> vmDeletionStructs = action.getParentIssuerContext(); | ||
|
|
@@ -111,11 +156,22 @@ private void handleDeletion(CascadeAction action, Completion completion) { | |
| return; | ||
| } | ||
|
|
||
| Set<String> createdVmUuids = findVmUuidsInCreatedState( | ||
| voList.stream().map(VmHostFileVO::getVmInstanceUuid).collect(Collectors.toSet())); | ||
| if (!createdVmUuids.isEmpty()) { | ||
| logger.info(String.format( | ||
| "VmHostFileCascadeExtension: deleting VmHostFile row(s) for Created VM(s) %s with forceDelete=true " | ||
| + "(same as expunge path; avoids leftovers when VM row is hard-deleted)", | ||
| String.join(", ", createdVmUuids))); | ||
| } | ||
|
|
||
| new While<>(voList).each((vo, whileCompletion) -> { | ||
| VmHostFileDeletionMsg msg = new VmHostFileDeletionMsg(); | ||
| msg.setUuid(vo.getUuid()); | ||
| msg.setForceDelete(action.isActionCode(CascadeConstant.DELETION_FORCE_DELETE_CODE) | ||
| || CascadeConstant.VM_INSTANCE_EXPUNGE_CODE.equals(action.getActionCode())); | ||
| boolean force = action.isActionCode(CascadeConstant.DELETION_FORCE_DELETE_CODE) | ||
| || CascadeConstant.VM_INSTANCE_EXPUNGE_CODE.equals(action.getActionCode()) | ||
| || createdVmUuids.contains(vo.getVmInstanceUuid()); | ||
| msg.setForceDelete(force); | ||
| bus.makeLocalServiceId(msg, VmInstanceConstant.SECURE_BOOT_SERVICE_ID); | ||
| bus.send(msg, new CloudBusCallBack(whileCompletion) { | ||
| @Override | ||
|
|
@@ -143,6 +199,17 @@ public void done(ErrorCodeList errorCodeList) { | |
| }); | ||
| } | ||
|
|
||
| private Set<String> findVmUuidsInCreatedState(Set<String> vmUuids) { | ||
| if (vmUuids.isEmpty()) { | ||
| return new HashSet<>(); | ||
| } | ||
| return new HashSet<>(Q.New(VmInstanceVO.class) | ||
| .in(VmInstanceVO_.uuid, vmUuids) | ||
| .eq(VmInstanceVO_.state, VmInstanceState.Created) | ||
| .select(VmInstanceVO_.uuid) | ||
| .listValues()); | ||
| } | ||
|
|
||
| private void handleDeletionCleanup(CascadeAction action, Completion completion) { | ||
| completion.success(); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
不要让一个
CreatedVM 带着整批 backup file 一起绕过 defer。这里同样是 action 级别的开关:只要这批
VmDeletionStruct里出现CreatedVM,就会让整批 action 继续走handleDeletion(...),后面会给所有resourceUuid对应的VmHostBackupFileVO发删除消息。若同批还包含删除策略仍应Delay/Never的非CreatedVM,它们的 backup file 也会被提前清理。建议只对CreatedVM 对应的 backup rows 放开 defer,其余资源继续沿用原策略。🤖 Prompt for AI Agents