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