From d23961141de69b9683054a06a99e7a20ba1bb012 Mon Sep 17 00:00:00 2001 From: "tao.gan" Date: Wed, 15 Apr 2026 13:42:52 +0800 Subject: [PATCH] [storage]: support cleanAllVmMetadata param Resolves: ZSV-11867 Change-Id: I6e6b616875706f67706d726d617367637863717a --- ...VmInstanceMetadataOnPrimaryStorageMsg.java | 10 +++ ...InstanceMetadataOnPrimaryStorageReply.java | 9 +++ .../vm/APICleanupVmInstanceMetadataEvent.java | 10 +++ .../vm/APICleanupVmInstanceMetadataMsg.java | 14 +++- .../primary/local/LocalStorageBase.java | 66 +++++++++++++++++++ .../primary/local/LocalStorageKvmBackend.java | 4 ++ .../nfs/NfsPrimaryStorageKVMBackend.java | 2 + .../NfsPrimaryStorageKVMBackendCommands.java | 2 + .../sdk/CleanupVmInstanceMetadataAction.java | 5 +- .../sdk/CleanupVmInstanceMetadataResult.java | 8 +++ 10 files changed, 128 insertions(+), 2 deletions(-) diff --git a/header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageMsg.java b/header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageMsg.java index 4e508032775..0255ed9acd0 100644 --- a/header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageMsg.java +++ b/header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageMsg.java @@ -49,4 +49,14 @@ public String getHostUuid() { public void setHostUuid(String hostUuid) { this.hostUuid = hostUuid; } + + private boolean cleanAllVmMetadata; + + public boolean isCleanAllVmMetadata() { + return cleanAllVmMetadata; + } + + public void setCleanAllVmMetadata(boolean cleanAllVmMetadata) { + this.cleanAllVmMetadata = cleanAllVmMetadata; + } } diff --git a/header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageReply.java b/header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageReply.java index 05bba3ac430..5f5fcb79ce9 100644 --- a/header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageReply.java +++ b/header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageReply.java @@ -3,4 +3,13 @@ import org.zstack.header.message.MessageReply; public class CleanupVmInstanceMetadataOnPrimaryStorageReply extends MessageReply { + private int cleanedCount; + + public int getCleanedCount() { + return cleanedCount; + } + + public void setCleanedCount(int cleanedCount) { + this.cleanedCount = cleanedCount; + } } diff --git a/header/src/main/java/org/zstack/header/vm/APICleanupVmInstanceMetadataEvent.java b/header/src/main/java/org/zstack/header/vm/APICleanupVmInstanceMetadataEvent.java index 60a441a626d..fa1273d1b24 100644 --- a/header/src/main/java/org/zstack/header/vm/APICleanupVmInstanceMetadataEvent.java +++ b/header/src/main/java/org/zstack/header/vm/APICleanupVmInstanceMetadataEvent.java @@ -43,6 +43,16 @@ public void setFailedVmUuids(List failedVmUuids) { this.failedVmUuids = failedVmUuids; } + private List failedPrimaryStorageUuids; + + public List getFailedPrimaryStorageUuids() { + return failedPrimaryStorageUuids; + } + + public void setFailedPrimaryStorageUuids(List failedPrimaryStorageUuids) { + this.failedPrimaryStorageUuids = failedPrimaryStorageUuids; + } + public static APICleanupVmInstanceMetadataEvent __example__() { APICleanupVmInstanceMetadataEvent evt = new APICleanupVmInstanceMetadataEvent(); evt.totalCleaned = 5; diff --git a/header/src/main/java/org/zstack/header/vm/APICleanupVmInstanceMetadataMsg.java b/header/src/main/java/org/zstack/header/vm/APICleanupVmInstanceMetadataMsg.java index e75d807c3c0..af724d4f957 100644 --- a/header/src/main/java/org/zstack/header/vm/APICleanupVmInstanceMetadataMsg.java +++ b/header/src/main/java/org/zstack/header/vm/APICleanupVmInstanceMetadataMsg.java @@ -14,9 +14,12 @@ isAction = true ) public class APICleanupVmInstanceMetadataMsg extends APIMessage { - @APIParam(resourceType = VmInstanceVO.class, nonempty = true) + @APIParam(resourceType = VmInstanceVO.class, required = false) private List vmUuids; + @APIParam(required = false) + private boolean cleanAllVmMetadata; + public List getVmUuids() { return vmUuids; } @@ -25,9 +28,18 @@ public void setVmUuids(List vmUuids) { this.vmUuids = vmUuids; } + public boolean isCleanAllVmMetadata() { + return cleanAllVmMetadata; + } + + public void setCleanAllVmMetadata(boolean cleanAllVmMetadata) { + this.cleanAllVmMetadata = cleanAllVmMetadata; + } + public static APICleanupVmInstanceMetadataMsg __example__() { APICleanupVmInstanceMetadataMsg msg = new APICleanupVmInstanceMetadataMsg(); msg.vmUuids = java.util.Arrays.asList(uuid(), uuid()); + msg.cleanAllVmMetadata = false; return msg; } } diff --git a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java index 1642c1c1097..30561655d83 100755 --- a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java +++ b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java @@ -63,6 +63,7 @@ import java.io.File; import java.util.*; import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; @@ -3558,6 +3559,11 @@ public void done(ErrorCodeList errorCodeList) { @Override protected void handle(final CleanupVmInstanceMetadataOnPrimaryStorageMsg msg) { + if (msg.isCleanAllVmMetadata()) { + handleCleanAllVmMetadataOnLocalStorage(msg); + return; + } + thdf.chainSubmit(new ChainTask(msg) { @Override public String getSyncSignature() { @@ -3623,4 +3629,64 @@ public String getName() { } }); } + + private void handleCleanAllVmMetadataOnLocalStorage(final CleanupVmInstanceMetadataOnPrimaryStorageMsg msg) { + CleanupVmInstanceMetadataOnPrimaryStorageReply reply = new CleanupVmInstanceMetadataOnPrimaryStorageReply(); + + List connectedHostUuids = SQL.New( + "select h.hostUuid from LocalStorageHostRefVO h, HostVO host" + + " where h.primaryStorageUuid = :psUuid" + + " and h.hostUuid = host.uuid" + + " and host.status = :hstatus", String.class) + .param("psUuid", self.getUuid()) + .param("hstatus", HostStatus.Connected) + .list(); + if (connectedHostUuids.isEmpty()) { + logger.warn(String.format("[MetadataCleanup] cleanAll: no connected host found for local ps[uuid:%s]", self.getUuid())); + reply.setCleanedCount(0); + bus.reply(msg, reply); + return; + } + + AtomicInteger totalCleaned = new AtomicInteger(0); + new While<>(connectedHostUuids).all((hostUuid, com) -> { + final LocalStorageHypervisorBackend bkd; + try { + LocalStorageHypervisorFactory f = getHypervisorBackendFactoryByHostUuid(hostUuid); + bkd = f.getHypervisorBackend(self); + } catch (Exception e) { + logger.warn(String.format("[MetadataCleanup] cleanAll: failed to prepare backend for host[uuid:%s] on ps[uuid:%s]: %s", + hostUuid, self.getUuid(), e.getMessage())); + com.addError(operr("failed to prepare backend for host[uuid:%s]: %s", hostUuid, e.getMessage())); + com.done(); + return; + } + bkd.handle(msg, hostUuid, new ReturnValueCompletion(com) { + @Override + public void success(CleanupVmInstanceMetadataOnPrimaryStorageReply returnValue) { + totalCleaned.addAndGet(returnValue.getCleanedCount()); + com.done(); + } + + @Override + public void fail(ErrorCode errorCode) { + logger.warn(String.format("[MetadataCleanup] cleanAll: failed on host[uuid:%s] on ps[uuid:%s]: %s", + hostUuid, self.getUuid(), errorCode)); + com.addError(errorCode); + com.done(); + } + }); + }).run(new WhileDoneCompletion(msg) { + @Override + public void done(ErrorCodeList errorCodeList) { + if (!errorCodeList.getCauses().isEmpty() && errorCodeList.getCauses().size() == connectedHostUuids.size()) { + reply.setError(operr("failed to cleanup all vm metadata from all hosts on local primary storage[uuid:%s], causes: %s", + self.getUuid(), errorCodeList)); + } else { + reply.setCleanedCount(totalCleaned.get()); + } + bus.reply(msg, reply); + } + }); + } } diff --git a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java index 93b88a397c9..2e2ecb8c6cc 100755 --- a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java +++ b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java @@ -946,9 +946,11 @@ public static class ScanVmMetadataRsp extends AgentResponse { public static class CleanupVmMetadataCmd extends AgentCommand { public String metadataPath; + public boolean cleanAllVmMetadata; } public static class CleanupVmMetadataRsp extends AgentResponse { + public int cleanedCount; } public static class PrefixRebaseBackingFilesCmd extends LocalStorageKvmBackend.AgentCommand { @@ -3945,11 +3947,13 @@ public void fail(ErrorCode errorCode) { void handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion) { CleanupVmMetadataCmd cmd = new CleanupVmMetadataCmd(); cmd.metadataPath = msg.getMetadataPath(); + cmd.cleanAllVmMetadata = msg.isCleanAllVmMetadata(); httpCall(CLEANUP_VM_METADATA_PATH, hostUuid, cmd, CleanupVmMetadataRsp.class, new ReturnValueCompletion(completion) { @Override public void success(CleanupVmMetadataRsp rsp) { CleanupVmInstanceMetadataOnPrimaryStorageReply reply = new CleanupVmInstanceMetadataOnPrimaryStorageReply(); + reply.setCleanedCount(rsp.cleanedCount); completion.success(reply); } diff --git a/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.java b/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.java index 445497e0871..0c24ab41c7a 100755 --- a/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.java +++ b/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.java @@ -2170,6 +2170,7 @@ public void handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg msg, String host CleanupVmMetadataCmd cmd = new CleanupVmMetadataCmd(); cmd.setUuid(msg.getPrimaryStorageUuid()); cmd.metadataPath = msg.getMetadataPath(); + cmd.cleanAllVmMetadata = msg.isCleanAllVmMetadata(); KVMHostAsyncHttpCallMsg hmsg = new KVMHostAsyncHttpCallMsg(); hmsg.setCommand(cmd); @@ -2191,6 +2192,7 @@ public void run(MessageReply reply) { } CleanupVmInstanceMetadataOnPrimaryStorageReply r = new CleanupVmInstanceMetadataOnPrimaryStorageReply(); + r.setCleanedCount(rsp.cleanedCount); completion.success(r); } }); diff --git a/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackendCommands.java b/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackendCommands.java index 0901af4cadb..bc1ee619212 100755 --- a/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackendCommands.java +++ b/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackendCommands.java @@ -990,9 +990,11 @@ public static class ScanVmMetadataRsp extends NfsPrimaryStorageAgentResponse { public static class CleanupVmMetadataCmd extends NfsPrimaryStorageAgentCommand { public String metadataPath; + public boolean cleanAllVmMetadata; } public static class CleanupVmMetadataRsp extends NfsPrimaryStorageAgentResponse { + public int cleanedCount; } public static class PrefixRebaseBackingFilesCmd extends NfsPrimaryStorageAgentCommand { diff --git a/sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.java b/sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.java index 46586cab3c4..f3b58267e2e 100644 --- a/sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.java +++ b/sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.java @@ -25,9 +25,12 @@ public Result throwExceptionIfError() { } } - @Param(required = true, nonempty = true, nullElements = false, emptyString = true, noTrim = false) + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.util.List vmUuids; + @Param(required = false) + public boolean cleanAllVmMetadata; + @Param(required = false) public java.util.List systemTags; diff --git a/sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.java b/sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.java index 879a409cc59..d7e01cbeef9 100644 --- a/sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.java +++ b/sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.java @@ -27,4 +27,12 @@ public java.util.List getFailedVmUuids() { return this.failedVmUuids; } + public java.util.List failedPrimaryStorageUuids; + public void setFailedPrimaryStorageUuids(java.util.List failedPrimaryStorageUuids) { + this.failedPrimaryStorageUuids = failedPrimaryStorageUuids; + } + public java.util.List getFailedPrimaryStorageUuids() { + return this.failedPrimaryStorageUuids; + } + }