diff --git a/conf/serviceConfig/vmInstance.xml b/conf/serviceConfig/vmInstance.xml
index 730951e0ece..7008547ed19 100755
--- a/conf/serviceConfig/vmInstance.xml
+++ b/conf/serviceConfig/vmInstance.xml
@@ -267,6 +267,9 @@
org.zstack.header.vm.APICleanupVmInstanceMetadataMsg
+
+ org.zstack.header.vm.APICleanupAllVmInstanceMetadataMsg
+
org.zstack.header.vm.APIRegisterVmInstanceFromMetadataMsg
diff --git a/header/src/main/java/org/zstack/header/storage/primary/CleanupAllVmMetadataOnPrimaryStorageMsg.java b/header/src/main/java/org/zstack/header/storage/primary/CleanupAllVmMetadataOnPrimaryStorageMsg.java
new file mode 100644
index 00000000000..d635e79827a
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/CleanupAllVmMetadataOnPrimaryStorageMsg.java
@@ -0,0 +1,25 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.NeedReplyMessage;
+
+public class CleanupAllVmMetadataOnPrimaryStorageMsg extends NeedReplyMessage implements PrimaryStorageMessage {
+ private String primaryStorageUuid;
+ private String metadataDir;
+
+ @Override
+ public String getPrimaryStorageUuid() {
+ return primaryStorageUuid;
+ }
+
+ public void setPrimaryStorageUuid(String primaryStorageUuid) {
+ this.primaryStorageUuid = primaryStorageUuid;
+ }
+
+ public String getMetadataDir() {
+ return metadataDir;
+ }
+
+ public void setMetadataDir(String metadataDir) {
+ this.metadataDir = metadataDir;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/CleanupAllVmMetadataOnPrimaryStorageReply.java b/header/src/main/java/org/zstack/header/storage/primary/CleanupAllVmMetadataOnPrimaryStorageReply.java
new file mode 100644
index 00000000000..ef419a34d57
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/CleanupAllVmMetadataOnPrimaryStorageReply.java
@@ -0,0 +1,6 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.MessageReply;
+
+public class CleanupAllVmMetadataOnPrimaryStorageReply extends MessageReply {
+}
diff --git a/header/src/main/java/org/zstack/header/vm/APICleanupAllVmInstanceMetadataEvent.java b/header/src/main/java/org/zstack/header/vm/APICleanupAllVmInstanceMetadataEvent.java
new file mode 100644
index 00000000000..263c9058f53
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/APICleanupAllVmInstanceMetadataEvent.java
@@ -0,0 +1,33 @@
+package org.zstack.header.vm;
+
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.rest.RestResponse;
+
+import java.util.List;
+
+@RestResponse(fieldsTo = {"all"})
+public class APICleanupAllVmInstanceMetadataEvent extends APIEvent {
+ private List failedPrimaryStorageUuids;
+
+ public APICleanupAllVmInstanceMetadataEvent() {
+ super(null);
+ }
+
+ public APICleanupAllVmInstanceMetadataEvent(String apiId) {
+ super(apiId);
+ }
+
+ public List getFailedPrimaryStorageUuids() {
+ return failedPrimaryStorageUuids;
+ }
+
+ public void setFailedPrimaryStorageUuids(List failedPrimaryStorageUuids) {
+ this.failedPrimaryStorageUuids = failedPrimaryStorageUuids;
+ }
+
+ public static APICleanupAllVmInstanceMetadataEvent __example__() {
+ APICleanupAllVmInstanceMetadataEvent evt = new APICleanupAllVmInstanceMetadataEvent();
+ evt.failedPrimaryStorageUuids = java.util.Collections.emptyList();
+ return evt;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/APICleanupAllVmInstanceMetadataEventDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/vm/APICleanupAllVmInstanceMetadataEventDoc_zh_cn.groovy
new file mode 100644
index 00000000000..77b75fc7964
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/APICleanupAllVmInstanceMetadataEventDoc_zh_cn.groovy
@@ -0,0 +1,29 @@
+package org.zstack.header.vm
+
+import org.zstack.header.errorcode.ErrorCode
+
+doc {
+
+ title "清理全部云主机元数据返回"
+
+ field {
+ name "failedPrimaryStorageUuids"
+ desc "清理失败的主存储UUID列表;具体失败原因汇总见 error 字段,逐条详情见 mn / agent 日志"
+ type "List"
+ since "5.0.0"
+ }
+ field {
+ name "success"
+ desc "操作是否成功;任一主存储清理失败则为 false"
+ type "boolean"
+ since "5.0.0"
+ }
+ ref {
+ name "error"
+ path "org.zstack.header.vm.APICleanupAllVmInstanceMetadataEvent.error"
+ desc "错误码;success=false 时聚合所有失败主存储的失败原因"
+ type "ErrorCode"
+ since "5.0.0"
+ clz ErrorCode.class
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/APICleanupAllVmInstanceMetadataMsg.java b/header/src/main/java/org/zstack/header/vm/APICleanupAllVmInstanceMetadataMsg.java
new file mode 100644
index 00000000000..fc224268da2
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/APICleanupAllVmInstanceMetadataMsg.java
@@ -0,0 +1,34 @@
+package org.zstack.header.vm;
+
+import org.springframework.http.HttpMethod;
+import org.zstack.header.message.APIMessage;
+import org.zstack.header.message.APIParam;
+import org.zstack.header.rest.RestRequest;
+import org.zstack.header.storage.primary.PrimaryStorageVO;
+
+import java.util.List;
+
+@RestRequest(
+ path = "/vm-instances/metadata",
+ method = HttpMethod.DELETE,
+ responseClass = APICleanupAllVmInstanceMetadataEvent.class,
+ isAction = true
+)
+public class APICleanupAllVmInstanceMetadataMsg extends APIMessage {
+ @APIParam(resourceType = PrimaryStorageVO.class, required = false)
+ private List primaryStorageUuids;
+
+ public List getPrimaryStorageUuids() {
+ return primaryStorageUuids;
+ }
+
+ public void setPrimaryStorageUuids(List primaryStorageUuids) {
+ this.primaryStorageUuids = primaryStorageUuids;
+ }
+
+ public static APICleanupAllVmInstanceMetadataMsg __example__() {
+ APICleanupAllVmInstanceMetadataMsg msg = new APICleanupAllVmInstanceMetadataMsg();
+ msg.primaryStorageUuids = java.util.Arrays.asList(uuid(), uuid());
+ return msg;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/APICleanupAllVmInstanceMetadataMsgDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/vm/APICleanupAllVmInstanceMetadataMsgDoc_zh_cn.groovy
new file mode 100644
index 00000000000..9d0fc0fefc2
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/APICleanupAllVmInstanceMetadataMsgDoc_zh_cn.groovy
@@ -0,0 +1,58 @@
+package org.zstack.header.vm
+
+import org.zstack.header.vm.APICleanupAllVmInstanceMetadataEvent
+
+doc {
+ title "清理全部云主机元数据"
+
+ category "云主机"
+
+ desc """清理一个或多个主存储上保存的全部云主机元数据文件,仅管理员可调用。当 primaryStorageUuids 为空(未传或传空列表)时,将清理系统中所有 Enabled+Connected 且支持云主机元数据的主存储;否则仅清理列表中指定的主存储。"""
+
+ rest {
+ request {
+ url "DELETE /v1/vm-instances/metadata"
+
+ header (Authorization: 'OAuth the-session-uuid')
+
+ clz APICleanupAllVmInstanceMetadataMsg.class
+
+ desc """"""
+
+ params {
+
+ column {
+ name "primaryStorageUuids"
+ enclosedIn "cleanupAllVmInstanceMetadata"
+ desc "需要清理云主机元数据的主存储UUID列表;为空时清理所有 Enabled+Connected 主存储上的元数据"
+ location "body"
+ type "List"
+ optional true
+ since "5.0.0"
+ }
+ column {
+ name "systemTags"
+ enclosedIn ""
+ desc "系统标签"
+ location "query"
+ type "List"
+ optional true
+ since "5.0.0"
+ }
+ column {
+ name "userTags"
+ enclosedIn ""
+ desc "用户标签"
+ location "query"
+ type "List"
+ optional true
+ since "5.0.0"
+ }
+ }
+ }
+
+ response {
+ clz APICleanupAllVmInstanceMetadataEvent.class
+ }
+ }
+}
\ No newline at end of file
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 eea5f8beb92..86e5f195da2 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
@@ -72,6 +72,8 @@
import static org.zstack.utils.CollectionUtils.toMap;
import static org.zstack.utils.CollectionUtils.transformAndRemoveNull;
+import java.util.concurrent.atomic.AtomicInteger;
+
/**
* Created by frank on 6/30/2015.
*/
@@ -907,6 +909,8 @@ public void handleLocalMessage(Message msg) {
handle((CommitVolumeSnapshotOnPrimaryStorageMsg) msg);
} else if (msg instanceof PullVolumeSnapshotOnPrimaryStorageMsg) {
handle((PullVolumeSnapshotOnPrimaryStorageMsg) msg);
+ } else if (msg instanceof CleanupAllVmMetadataOnPrimaryStorageMsg) {
+ handle((CleanupAllVmMetadataOnPrimaryStorageMsg) msg);
} else {
super.handleLocalMessage(msg);
}
@@ -3625,4 +3629,64 @@ public String getName() {
}
});
}
+
+ @Override
+ protected void handle(final CleanupAllVmMetadataOnPrimaryStorageMsg msg) {
+ CleanupAllVmMetadataOnPrimaryStorageReply reply = new CleanupAllVmMetadataOnPrimaryStorageReply();
+
+ List connectedHostUuids = getConnectedLocalStorageHostUuids();
+ if (connectedHostUuids.isEmpty()) {
+ logger.warn(String.format("[MetadataCleanup] cleanAll: no connected host found for local ps[uuid:%s]", self.getUuid()));
+ bus.reply(msg, reply);
+ return;
+ }
+
+ 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("host[uuid:%s] backend prepare failed: %s", hostUuid, e.getMessage()));
+ com.done();
+ return;
+ }
+ bkd.handle(msg, hostUuid, new ReturnValueCompletion(com) {
+ @Override
+ public void success(CleanupAllVmMetadataOnPrimaryStorageReply returnValue) {
+ 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(operr("host[uuid:%s]: %s", hostUuid, errorCode.getDescription()));
+ com.done();
+ }
+ });
+ }).run(new WhileDoneCompletion(msg) {
+ @Override
+ public void done(ErrorCodeList errorCodeList) {
+ if (!errorCodeList.getCauses().isEmpty()) {
+ reply.setError(operr("local primary storage[uuid:%s] cleanAll failed on %d/%d host(s): %s",
+ self.getUuid(), errorCodeList.getCauses().size(), connectedHostUuids.size(), errorCodeList));
+ }
+ bus.reply(msg, reply);
+ }
+ });
+ }
+
+ private List getConnectedLocalStorageHostUuids() {
+ return 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();
+ }
}
diff --git a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageHypervisorBackend.java b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageHypervisorBackend.java
index d8226d932b2..58d5653610a 100755
--- a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageHypervisorBackend.java
+++ b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageHypervisorBackend.java
@@ -132,5 +132,7 @@ public LocalStorageHypervisorBackend(PrimaryStorageVO self) {
abstract void handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
+ abstract void handle(CleanupAllVmMetadataOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
+
abstract void handle(RebaseVolumeBackingFileOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
}
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 5b4324495b2..60fbd471a37 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
@@ -950,6 +950,13 @@ public static class CleanupVmMetadataCmd extends AgentCommand {
public static class CleanupVmMetadataRsp extends AgentResponse {
}
+ public static class CleanupAllVmMetadataCmd extends AgentCommand {
+ public String metadataDir;
+ }
+
+ public static class CleanupAllVmMetadataRsp extends AgentResponse {
+ }
+
public static class PrefixRebaseBackingFilesCmd extends LocalStorageKvmBackend.AgentCommand {
public List filePaths;
public String oldPrefix;
@@ -996,6 +1003,7 @@ public static class PrefixRebaseBackingFilesRsp extends LocalStorageKvmBackend.A
public static final String GET_VM_INSTANCE_METADATA_PATH = "/localstorage/vm/metadata/get";
public static final String SCAN_VM_METADATA_PATH = "/localstorage/vm/metadata/scan";
public static final String CLEANUP_VM_METADATA_PATH = "/localstorage/vm/metadata/cleanup";
+ public static final String CLEANUP_ALL_VM_METADATA_PATH = "/localstorage/vm/metadata/cleanup-all";
public static final String PREFIX_REBASE_BACKING_FILES_PATH = "/localstorage/snapshot/prefixrebasebackingfiles";
public LocalStorageKvmBackend() {
@@ -3955,6 +3963,25 @@ public void fail(ErrorCode errorCode) {
});
}
+ @Override
+ void handle(CleanupAllVmMetadataOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion) {
+ CleanupAllVmMetadataCmd cmd = new CleanupAllVmMetadataCmd();
+ cmd.metadataDir = msg.getMetadataDir();
+
+ httpCall(CLEANUP_ALL_VM_METADATA_PATH, hostUuid, cmd, CleanupAllVmMetadataRsp.class, new ReturnValueCompletion(completion) {
+ @Override
+ public void success(CleanupAllVmMetadataRsp rsp) {
+ CleanupAllVmMetadataOnPrimaryStorageReply reply = new CleanupAllVmMetadataOnPrimaryStorageReply();
+ completion.success(reply);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ completion.fail(errorCode);
+ }
+ });
+ }
+
@Override
void handle(RebaseVolumeBackingFileOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion) {
PrefixRebaseBackingFilesCmd cmd = new PrefixRebaseBackingFilesCmd();
diff --git a/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java b/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java
index 6b0142e5a63..7ac88ed5139 100755
--- a/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java
+++ b/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java
@@ -136,6 +136,8 @@ protected void handleLocalMessage(Message msg) {
handle((PullVolumeSnapshotOnPrimaryStorageMsg) msg);
} else if (msg instanceof RebaseVolumeBackingFileOnPrimaryStorageMsg) {
handle((RebaseVolumeBackingFileOnPrimaryStorageMsg) msg);
+ } else if (msg instanceof CleanupAllVmMetadataOnPrimaryStorageMsg) {
+ handle((CleanupAllVmMetadataOnPrimaryStorageMsg) msg);
} else {
super.handleLocalMessage(msg);
}
@@ -2089,4 +2091,42 @@ public void fail(ErrorCode errorCode) {
}
});
}
+
+ @Override
+ protected void handle(CleanupAllVmMetadataOnPrimaryStorageMsg msg) {
+ CleanupAllVmMetadataOnPrimaryStorageReply reply = new CleanupAllVmMetadataOnPrimaryStorageReply();
+ List connectedHosts = factory.getConnectedHostForOperation(getSelfInventory());
+ if (connectedHosts.isEmpty()) {
+ reply.setError(operr("no connected host found for NFS primary storage[uuid:%s]", self.getUuid()));
+ bus.reply(msg, reply);
+ return;
+ }
+ cleanupAllOnHostWithFallback(msg, reply, connectedHosts, 0);
+ }
+
+ private void cleanupAllOnHostWithFallback(CleanupAllVmMetadataOnPrimaryStorageMsg msg,
+ CleanupAllVmMetadataOnPrimaryStorageReply reply,
+ List connectedHosts, int idx) {
+ if (idx >= connectedHosts.size()) {
+ reply.setError(operr("failed to cleanup all vm metadata on NFS primary storage[uuid:%s] after trying %d connected host(s)",
+ self.getUuid(), connectedHosts.size()));
+ bus.reply(msg, reply);
+ return;
+ }
+ String hostUuid = connectedHosts.get(idx).getUuid();
+ final NfsPrimaryStorageBackend backend = getBackendByHostUuid(hostUuid);
+ backend.handle(msg, hostUuid, new ReturnValueCompletion(msg) {
+ @Override
+ public void success(CleanupAllVmMetadataOnPrimaryStorageReply r) {
+ bus.reply(msg, r);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ logger.warn(String.format("[MetadataCleanup] cleanAll: NFS ps[uuid:%s] failed on host[uuid:%s]: %s; trying next connected host",
+ self.getUuid(), hostUuid, errorCode));
+ cleanupAllOnHostWithFallback(msg, reply, connectedHosts, idx + 1);
+ }
+ });
+ }
}
diff --git a/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.java b/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.java
index 35a240a6221..b0f2acced33 100755
--- a/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.java
+++ b/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.java
@@ -101,6 +101,8 @@ public interface NfsPrimaryStorageBackend {
void handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
+ void handle(CleanupAllVmMetadataOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
+
void handle(RebaseVolumeBackingFileOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
class BitsInfo {
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..caa0b8ae003 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
@@ -138,6 +138,7 @@ public class NfsPrimaryStorageKVMBackend implements NfsPrimaryStorageBackend,
public static final String GET_VM_INSTANCE_METADATA_PATH = "/nfsprimarystorage/vm/metadata/get";
public static final String SCAN_VM_METADATA_PATH = "/nfsprimarystorage/vm/metadata/scan";
public static final String CLEANUP_VM_METADATA_PATH = "/nfsprimarystorage/vm/metadata/cleanup";
+ public static final String CLEANUP_ALL_VM_METADATA_PATH = "/nfsprimarystorage/vm/metadata/cleanup-all";
public static final String NFS_PREFIX_REBASE_BACKING_FILES_PATH = "/nfsprimarystorage/snapshot/prefixrebasebackingfiles";
//////////////// For unit test //////////////////////////
@@ -2196,6 +2197,37 @@ public void run(MessageReply reply) {
});
}
+ @Override
+ public void handle(CleanupAllVmMetadataOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion) {
+ CleanupAllVmMetadataCmd cmd = new CleanupAllVmMetadataCmd();
+ cmd.setUuid(msg.getPrimaryStorageUuid());
+ cmd.metadataDir = msg.getMetadataDir();
+
+ KVMHostAsyncHttpCallMsg hmsg = new KVMHostAsyncHttpCallMsg();
+ hmsg.setCommand(cmd);
+ hmsg.setPath(CLEANUP_ALL_VM_METADATA_PATH);
+ hmsg.setHostUuid(hostUuid);
+ bus.makeTargetServiceIdByResourceUuid(hmsg, HostConstant.SERVICE_ID, hostUuid);
+ bus.send(hmsg, new CloudBusCallBack(completion) {
+ @Override
+ public void run(MessageReply reply) {
+ if (!reply.isSuccess()) {
+ completion.fail(reply.getError());
+ return;
+ }
+
+ CleanupAllVmMetadataRsp rsp = ((KVMHostAsyncHttpCallReply) reply).toResponse(CleanupAllVmMetadataRsp.class);
+ if (!rsp.isSuccess()) {
+ completion.fail(operr("failed to cleanup all vm metadata on nfs via host[uuid:%s]: %s", hostUuid, rsp.getError()));
+ return;
+ }
+
+ CleanupAllVmMetadataOnPrimaryStorageReply r = new CleanupAllVmMetadataOnPrimaryStorageReply();
+ completion.success(r);
+ }
+ });
+ }
+
@Override
public void handle(RebaseVolumeBackingFileOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion) {
NfsPrimaryStorageKVMBackendCommands.PrefixRebaseBackingFilesCmd cmd = new NfsPrimaryStorageKVMBackendCommands.PrefixRebaseBackingFilesCmd();
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..bce75ba2249 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
@@ -995,6 +995,13 @@ public static class CleanupVmMetadataCmd extends NfsPrimaryStorageAgentCommand {
public static class CleanupVmMetadataRsp extends NfsPrimaryStorageAgentResponse {
}
+ public static class CleanupAllVmMetadataCmd extends NfsPrimaryStorageAgentCommand {
+ public String metadataDir;
+ }
+
+ public static class CleanupAllVmMetadataRsp extends NfsPrimaryStorageAgentResponse {
+ }
+
public static class PrefixRebaseBackingFilesCmd extends NfsPrimaryStorageAgentCommand {
public List filePaths;
public String oldPrefix;
diff --git a/sdk/src/main/java/org/zstack/sdk/CleanupAllVmInstanceMetadataAction.java b/sdk/src/main/java/org/zstack/sdk/CleanupAllVmInstanceMetadataAction.java
new file mode 100644
index 00000000000..254be3cfa04
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/CleanupAllVmInstanceMetadataAction.java
@@ -0,0 +1,101 @@
+package org.zstack.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.zstack.sdk.*;
+
+public class CleanupAllVmInstanceMetadataAction extends AbstractAction {
+
+ private static final HashMap parameterMap = new HashMap<>();
+
+ private static final HashMap nonAPIParameterMap = new HashMap<>();
+
+ public static class Result {
+ public ErrorCode error;
+ public org.zstack.sdk.CleanupAllVmInstanceMetadataResult value;
+
+ public Result throwExceptionIfError() {
+ if (error != null) {
+ throw new ApiException(
+ String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details)
+ );
+ }
+
+ return this;
+ }
+ }
+
+ @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.util.List primaryStorageUuids;
+
+ @Param(required = false)
+ public java.util.List systemTags;
+
+ @Param(required = false)
+ public java.util.List userTags;
+
+ @Param(required = false)
+ public String sessionId;
+
+ @Param(required = false)
+ public String accessKeyId;
+
+ @Param(required = false)
+ public String accessKeySecret;
+
+ @Param(required = false)
+ public String requestIp;
+
+ @NonAPIParam
+ public long timeout = -1;
+
+ @NonAPIParam
+ public long pollingInterval = -1;
+
+
+ private Result makeResult(ApiResult res) {
+ Result ret = new Result();
+ if (res.error != null) {
+ ret.error = res.error;
+ return ret;
+ }
+
+ org.zstack.sdk.CleanupAllVmInstanceMetadataResult value = res.getResult(org.zstack.sdk.CleanupAllVmInstanceMetadataResult.class);
+ ret.value = value == null ? new org.zstack.sdk.CleanupAllVmInstanceMetadataResult() : value;
+
+ return ret;
+ }
+
+ public Result call() {
+ ApiResult res = ZSClient.call(this);
+ return makeResult(res);
+ }
+
+ public void call(final Completion completion) {
+ ZSClient.call(this, new InternalCompletion() {
+ @Override
+ public void complete(ApiResult res) {
+ completion.complete(makeResult(res));
+ }
+ });
+ }
+
+ protected Map getParameterMap() {
+ return parameterMap;
+ }
+
+ protected Map getNonAPIParameterMap() {
+ return nonAPIParameterMap;
+ }
+
+ protected RestInfo getRestInfo() {
+ RestInfo info = new RestInfo();
+ info.httpMethod = "DELETE";
+ info.path = "/vm-instances/metadata";
+ info.needSession = true;
+ info.needPoll = true;
+ info.parameterName = "cleanupAllVmInstanceMetadata";
+ return info;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/CleanupAllVmInstanceMetadataResult.java b/sdk/src/main/java/org/zstack/sdk/CleanupAllVmInstanceMetadataResult.java
new file mode 100644
index 00000000000..48497a3ad45
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/CleanupAllVmInstanceMetadataResult.java
@@ -0,0 +1,14 @@
+package org.zstack.sdk;
+
+
+
+public class CleanupAllVmInstanceMetadataResult {
+ public java.util.List failedPrimaryStorageUuids;
+ public void setFailedPrimaryStorageUuids(java.util.List failedPrimaryStorageUuids) {
+ this.failedPrimaryStorageUuids = failedPrimaryStorageUuids;
+ }
+ public java.util.List getFailedPrimaryStorageUuids() {
+ return this.failedPrimaryStorageUuids;
+ }
+
+}
diff --git a/storage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.java b/storage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.java
index d54bc3d9c85..a23c4f40b40 100755
--- a/storage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.java
+++ b/storage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.java
@@ -429,6 +429,8 @@ protected void handleLocalMessage(Message msg) {
handle((GetVmInstanceMetadataFromPrimaryStorageMsg) msg);
} else if (msg instanceof CleanupVmInstanceMetadataOnPrimaryStorageMsg) {
handle((CleanupVmInstanceMetadataOnPrimaryStorageMsg) msg);
+ } else if (msg instanceof CleanupAllVmMetadataOnPrimaryStorageMsg) {
+ handle((CleanupAllVmMetadataOnPrimaryStorageMsg) msg);
} else if (msg instanceof RebaseVolumeBackingFileOnPrimaryStorageMsg) {
handle((RebaseVolumeBackingFileOnPrimaryStorageMsg) msg);
} else {
@@ -1821,6 +1823,12 @@ protected void handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg msg) {
bus.reply(msg, reply);
}
+ protected void handle(CleanupAllVmMetadataOnPrimaryStorageMsg msg) {
+ CleanupAllVmMetadataOnPrimaryStorageReply reply = new CleanupAllVmMetadataOnPrimaryStorageReply();
+ reply.setError(operr("operation not supported"));
+ bus.reply(msg, reply);
+ }
+
protected void handle(RebaseVolumeBackingFileOnPrimaryStorageMsg msg) {
RebaseVolumeBackingFileOnPrimaryStorageReply reply = new RebaseVolumeBackingFileOnPrimaryStorageReply();
reply.setError(operr("operation not supported"));
diff --git a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
index 7160cd1d93d..3f112821b84 100644
--- a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
+++ b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
@@ -5606,6 +5606,33 @@ abstract class ApiHelper {
}
+ def cleanupAllVmInstanceMetadata(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.CleanupAllVmInstanceMetadataAction.class) Closure c) {
+ def a = new org.zstack.sdk.CleanupAllVmInstanceMetadataAction()
+ a.sessionId = Test.currentEnvSpec?.session?.uuid
+ c.resolveStrategy = Closure.OWNER_FIRST
+ c.delegate = a
+ c()
+
+
+ if (System.getProperty("apipath") != null) {
+ if (a.apiId == null) {
+ a.apiId = Platform.uuid
+ }
+
+ def tracker = new ApiPathTracker(a.apiId)
+ def out = errorOut(a.call())
+ def path = tracker.getApiPath()
+ if (!path.isEmpty()) {
+ Test.apiPaths[a.class.name] = path.join(" --->\n")
+ }
+
+ return out
+ } else {
+ return errorOut(a.call())
+ }
+ }
+
+
def cleanupBillingUsage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.CleanupBillingUsageAction.class) Closure c) {
def a = new org.zstack.sdk.CleanupBillingUsageAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid