diff --git a/conf/serviceConfig/primaryStorage.xml b/conf/serviceConfig/primaryStorage.xml
index 337ce4eaac3..a0e663bef3a 100755
--- a/conf/serviceConfig/primaryStorage.xml
+++ b/conf/serviceConfig/primaryStorage.xml
@@ -81,7 +81,16 @@
org.zstack.header.storage.primary.APICleanUpStorageTrashOnPrimaryStorageMsg
+
org.zstack.header.storage.primary.APIAddStorageProtocolMsg
+
+
+ org.zstack.header.storage.primary.APITakeoverPrimaryStorageMsg
+
+
+
+ org.zstack.header.storage.primary.APICheckPrimaryStorageConsistencyMsg
+
diff --git a/header/src/main/java/org/zstack/header/storage/primary/APICheckPrimaryStorageConsistencyEvent.java b/header/src/main/java/org/zstack/header/storage/primary/APICheckPrimaryStorageConsistencyEvent.java
new file mode 100644
index 00000000000..def327c3a48
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/APICheckPrimaryStorageConsistencyEvent.java
@@ -0,0 +1,29 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.rest.RestResponse;
+
+@RestResponse(fieldsTo = {"all"})
+public class APICheckPrimaryStorageConsistencyEvent extends APIEvent {
+ private boolean consistent;
+
+ public boolean isConsistent() {
+ return consistent;
+ }
+
+ public void setConsistent(boolean consistent) {
+ this.consistent = consistent;
+ }
+
+ public APICheckPrimaryStorageConsistencyEvent() {
+ }
+
+ public APICheckPrimaryStorageConsistencyEvent(String apiId) {
+ super(apiId);
+ }
+
+ public static APICheckPrimaryStorageConsistencyEvent __example__() {
+ APICheckPrimaryStorageConsistencyEvent event = new APICheckPrimaryStorageConsistencyEvent();
+ return event;
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/storage/primary/APICheckPrimaryStorageConsistencyEventDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/storage/primary/APICheckPrimaryStorageConsistencyEventDoc_zh_cn.groovy
new file mode 100644
index 00000000000..3bd97b9f452
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/APICheckPrimaryStorageConsistencyEventDoc_zh_cn.groovy
@@ -0,0 +1,29 @@
+package org.zstack.header.storage.primary
+
+import org.zstack.header.errorcode.ErrorCode
+
+doc {
+
+ title "检查存储一致性返回"
+
+ field {
+ name "consistent"
+ desc "是否一直"
+ type "boolean"
+ since "5.0.0"
+ }
+ field {
+ name "success"
+ desc ""
+ type "boolean"
+ since "5.0.0"
+ }
+ ref {
+ name "error"
+ path "org.zstack.header.storage.primary.APICheckPrimaryStorageConsistencyEvent.error"
+ desc "错误码,若不为null,则表示操作失败, 操作成功时该字段为null"
+ type "ErrorCode"
+ since "5.0.0"
+ clz ErrorCode.class
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/APICheckPrimaryStorageConsistencyMsg.java b/header/src/main/java/org/zstack/header/storage/primary/APICheckPrimaryStorageConsistencyMsg.java
new file mode 100644
index 00000000000..450bc5f3a9a
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/APICheckPrimaryStorageConsistencyMsg.java
@@ -0,0 +1,36 @@
+package org.zstack.header.storage.primary;
+
+import org.springframework.http.HttpMethod;
+import org.zstack.header.message.APIMessage;
+import org.zstack.header.message.APIParam;
+import org.zstack.header.rest.RestRequest;
+
+@RestRequest(
+ path = "/primary-storage/{uuid}/consistency",
+ responseClass = APICheckPrimaryStorageConsistencyEvent.class,
+ method = HttpMethod.PUT,
+ isAction = true
+)
+public class APICheckPrimaryStorageConsistencyMsg extends APIMessage implements PrimaryStorageMessage {
+ @APIParam(resourceType = PrimaryStorageVO.class)
+ private String uuid;
+
+ @Override
+ public String getPrimaryStorageUuid() {
+ return uuid;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public static APICheckPrimaryStorageConsistencyMsg __example__() {
+ APICheckPrimaryStorageConsistencyMsg msg = new APICheckPrimaryStorageConsistencyMsg();
+ msg.setUuid(uuid(PrimaryStorageVO.class));
+ return msg;
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/storage/primary/APICheckPrimaryStorageConsistencyMsgDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/storage/primary/APICheckPrimaryStorageConsistencyMsgDoc_zh_cn.groovy
new file mode 100644
index 00000000000..03f019d6349
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/APICheckPrimaryStorageConsistencyMsgDoc_zh_cn.groovy
@@ -0,0 +1,58 @@
+package org.zstack.header.storage.primary
+
+import org.zstack.header.storage.primary.APICheckPrimaryStorageConsistencyEvent
+
+doc {
+ title "CheckPrimaryStorageConsistency"
+
+ category "storage.primary"
+
+ desc """检查存储一致性"""
+
+ rest {
+ request {
+ url "PUT /v1/primary-storage/{uuid}/consistency"
+
+ header (Authorization: 'OAuth the-session-uuid')
+
+ clz APICheckPrimaryStorageConsistencyMsg.class
+
+ desc """"""
+
+ params {
+
+ column {
+ name "uuid"
+ enclosedIn "checkPrimaryStorageConsistency"
+ desc "主存储的UUID"
+ location "url"
+ type "String"
+ optional false
+ since "5.0.0"
+ }
+ column {
+ name "systemTags"
+ enclosedIn ""
+ desc "系统标签"
+ location "body"
+ type "List"
+ optional true
+ since "5.0.0"
+ }
+ column {
+ name "userTags"
+ enclosedIn ""
+ desc "用户标签"
+ location "body"
+ type "List"
+ optional true
+ since "5.0.0"
+ }
+ }
+ }
+
+ response {
+ clz APICheckPrimaryStorageConsistencyEvent.class
+ }
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/storage/primary/APITakeoverPrimaryStorageEvent.java b/header/src/main/java/org/zstack/header/storage/primary/APITakeoverPrimaryStorageEvent.java
new file mode 100644
index 00000000000..cd2d17a4ece
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/APITakeoverPrimaryStorageEvent.java
@@ -0,0 +1,39 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.rest.RestResponse;
+
+import java.util.Collections;
+
+@RestResponse(allTo = "inventory")
+public class APITakeoverPrimaryStorageEvent extends APIEvent {
+ private PrimaryStorageInventory inventory;
+
+ public APITakeoverPrimaryStorageEvent() {
+ }
+
+ public APITakeoverPrimaryStorageEvent(String apiId) {
+ super(apiId);
+ }
+
+ public PrimaryStorageInventory getInventory() {
+ return inventory;
+ }
+
+ public void setInventory(PrimaryStorageInventory inventory) {
+ this.inventory = inventory;
+ }
+
+ public static APITakeoverPrimaryStorageEvent __example__() {
+ APITakeoverPrimaryStorageEvent event = new APITakeoverPrimaryStorageEvent();
+
+ PrimaryStorageInventory ps = new PrimaryStorageInventory();
+ ps.setName("PS1");
+ ps.setUrl("/zstack_ps");
+ ps.setType("LocalStorage");
+ ps.setAttachedClusterUuids(Collections.singletonList(uuid()));
+
+ event.setInventory(ps);
+ return event;
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/storage/primary/APITakeoverPrimaryStorageEventDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/storage/primary/APITakeoverPrimaryStorageEventDoc_zh_cn.groovy
new file mode 100644
index 00000000000..bbb6428845a
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/APITakeoverPrimaryStorageEventDoc_zh_cn.groovy
@@ -0,0 +1,32 @@
+package org.zstack.header.storage.primary
+
+import org.zstack.header.storage.primary.PrimaryStorageInventory
+import org.zstack.header.errorcode.ErrorCode
+
+doc {
+
+ title "接管主存储返回"
+
+ ref {
+ name "inventory"
+ path "org.zstack.header.storage.primary.APITakeoverPrimaryStorageEvent.inventory"
+ desc "主存储信息"
+ type "PrimaryStorageInventory"
+ since "5.0.0"
+ clz PrimaryStorageInventory.class
+ }
+ field {
+ name "success"
+ desc ""
+ type "boolean"
+ since "5.0.0"
+ }
+ ref {
+ name "error"
+ path "org.zstack.header.storage.primary.APITakeoverPrimaryStorageEvent.error"
+ desc "错误码,若不为null,则表示操作失败, 操作成功时该字段为null"
+ type "ErrorCode"
+ since "5.0.0"
+ clz ErrorCode.class
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/APITakeoverPrimaryStorageMsg.java b/header/src/main/java/org/zstack/header/storage/primary/APITakeoverPrimaryStorageMsg.java
new file mode 100644
index 00000000000..069ae4b99b1
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/APITakeoverPrimaryStorageMsg.java
@@ -0,0 +1,36 @@
+package org.zstack.header.storage.primary;
+
+import org.springframework.http.HttpMethod;
+import org.zstack.header.message.APIMessage;
+import org.zstack.header.message.APIParam;
+import org.zstack.header.rest.RestRequest;
+
+@RestRequest(
+ path = "/primary-storage/{uuid}/takeover",
+ responseClass = APITakeoverPrimaryStorageEvent.class,
+ method = HttpMethod.PUT,
+ isAction = true
+)
+public class APITakeoverPrimaryStorageMsg extends APIMessage implements PrimaryStorageMessage {
+ @APIParam(resourceType = PrimaryStorageVO.class)
+ private String uuid;
+
+ @Override
+ public String getPrimaryStorageUuid() {
+ return uuid;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public static APITakeoverPrimaryStorageMsg __example__() {
+ APITakeoverPrimaryStorageMsg msg = new APITakeoverPrimaryStorageMsg();
+ msg.setUuid(uuid(PrimaryStorageVO.class));
+ return msg;
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/storage/primary/APITakeoverPrimaryStorageMsgDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/storage/primary/APITakeoverPrimaryStorageMsgDoc_zh_cn.groovy
new file mode 100644
index 00000000000..9a1fbec7335
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/APITakeoverPrimaryStorageMsgDoc_zh_cn.groovy
@@ -0,0 +1,58 @@
+package org.zstack.header.storage.primary
+
+import org.zstack.header.storage.primary.APITakeoverPrimaryStorageEvent
+
+doc {
+ title "TakeoverPrimaryStorage"
+
+ category "storage.primary"
+
+ desc """接管主存储"""
+
+ rest {
+ request {
+ url "PUT /v1/primary-storage/{uuid}/takeover"
+
+ header (Authorization: 'OAuth the-session-uuid')
+
+ clz APITakeoverPrimaryStorageMsg.class
+
+ desc """"""
+
+ params {
+
+ column {
+ name "uuid"
+ enclosedIn "takeoverPrimaryStorage"
+ desc "主存储的UUID"
+ location "url"
+ type "String"
+ optional false
+ since "5.0.0"
+ }
+ column {
+ name "systemTags"
+ enclosedIn ""
+ desc "系统标签"
+ location "body"
+ type "List"
+ optional true
+ since "5.0.0"
+ }
+ column {
+ name "userTags"
+ enclosedIn ""
+ desc "用户标签"
+ location "body"
+ type "List"
+ optional true
+ since "5.0.0"
+ }
+ }
+ }
+
+ response {
+ clz APITakeoverPrimaryStorageEvent.class
+ }
+ }
+}
\ No newline at end of file
diff --git a/sdk/src/main/java/SourceClassMap.java b/sdk/src/main/java/SourceClassMap.java
index 146b132c459..e785d1156e2 100644
--- a/sdk/src/main/java/SourceClassMap.java
+++ b/sdk/src/main/java/SourceClassMap.java
@@ -552,6 +552,7 @@ public class SourceClassMap {
put("org.zstack.storage.primary.local.APIGetLocalStorageHostDiskCapacityReply$HostDiskCapacity", "org.zstack.sdk.HostDiskCapacity");
put("org.zstack.storage.primary.local.LocalStorageResourceRefInventory", "org.zstack.sdk.LocalStorageResourceRefInventory");
put("org.zstack.storage.primary.sharedblock.SharedBlockCandidateStruct", "org.zstack.sdk.SharedBlockCandidateStruct");
+ put("org.zstack.storage.primary.sharedblock.SharedBlockGroupLunInfo", "org.zstack.sdk.SharedBlockGroupLunInfo");
put("org.zstack.storage.primary.sharedblock.SharedBlockGroupPrimaryStorageHostRefInventory", "org.zstack.sdk.SharedBlockGroupPrimaryStorageHostRefInventory");
put("org.zstack.storage.primary.sharedblock.SharedBlockGroupPrimaryStorageInventory", "org.zstack.sdk.SharedBlockGroupPrimaryStorageInventory");
put("org.zstack.storage.primary.sharedblock.SharedBlockGroupType", "org.zstack.sdk.SharedBlockGroupType");
@@ -1075,6 +1076,7 @@ public class SourceClassMap {
put("org.zstack.sdk.SftpBackupStorageInventory", "org.zstack.storage.backup.sftp.SftpBackupStorageInventory");
put("org.zstack.sdk.ShareableVolumeVmInstanceRefInventory", "org.zstack.mevoco.ShareableVolumeVmInstanceRefInventory");
put("org.zstack.sdk.SharedBlockCandidateStruct", "org.zstack.storage.primary.sharedblock.SharedBlockCandidateStruct");
+ put("org.zstack.sdk.SharedBlockGroupLunInfo", "org.zstack.storage.primary.sharedblock.SharedBlockGroupLunInfo");
put("org.zstack.sdk.SharedBlockGroupPrimaryStorageHostRefInventory", "org.zstack.storage.primary.sharedblock.SharedBlockGroupPrimaryStorageHostRefInventory");
put("org.zstack.sdk.SharedBlockGroupPrimaryStorageInventory", "org.zstack.storage.primary.sharedblock.SharedBlockGroupPrimaryStorageInventory");
put("org.zstack.sdk.SharedBlockGroupType", "org.zstack.storage.primary.sharedblock.SharedBlockGroupType");
diff --git a/sdk/src/main/java/org/zstack/sdk/CheckPrimaryStorageConsistencyAction.java b/sdk/src/main/java/org/zstack/sdk/CheckPrimaryStorageConsistencyAction.java
new file mode 100644
index 00000000000..e98639541de
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/CheckPrimaryStorageConsistencyAction.java
@@ -0,0 +1,101 @@
+package org.zstack.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.zstack.sdk.*;
+
+public class CheckPrimaryStorageConsistencyAction 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.CheckPrimaryStorageConsistencyResult 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 = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String uuid;
+
+ @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.CheckPrimaryStorageConsistencyResult value = res.getResult(org.zstack.sdk.CheckPrimaryStorageConsistencyResult.class);
+ ret.value = value == null ? new org.zstack.sdk.CheckPrimaryStorageConsistencyResult() : 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 = "PUT";
+ info.path = "/primary-storage/{uuid}/consistency";
+ info.needSession = true;
+ info.needPoll = true;
+ info.parameterName = "checkPrimaryStorageConsistency";
+ return info;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/CheckPrimaryStorageConsistencyResult.java b/sdk/src/main/java/org/zstack/sdk/CheckPrimaryStorageConsistencyResult.java
new file mode 100644
index 00000000000..b9a8be8eaac
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/CheckPrimaryStorageConsistencyResult.java
@@ -0,0 +1,14 @@
+package org.zstack.sdk;
+
+
+
+public class CheckPrimaryStorageConsistencyResult {
+ public boolean consistent;
+ public void setConsistent(boolean consistent) {
+ this.consistent = consistent;
+ }
+ public boolean getConsistent() {
+ return this.consistent;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/GetSharedBlockGroupInfosAction.java b/sdk/src/main/java/org/zstack/sdk/GetSharedBlockGroupInfosAction.java
new file mode 100644
index 00000000000..2d0779fb0a7
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/GetSharedBlockGroupInfosAction.java
@@ -0,0 +1,94 @@
+package org.zstack.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class GetSharedBlockGroupInfosAction 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.GetSharedBlockGroupLunsResult 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 = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String clusterUuid;
+
+ @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;
+
+
+ private Result makeResult(ApiResult res) {
+ Result ret = new Result();
+ if (res.error != null) {
+ ret.error = res.error;
+ return ret;
+ }
+
+ org.zstack.sdk.GetSharedBlockGroupLunsResult value = res.getResult(org.zstack.sdk.GetSharedBlockGroupLunsResult.class);
+ ret.value = value == null ? new org.zstack.sdk.GetSharedBlockGroupLunsResult() : 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 = "GET";
+ info.path = "/primary-storage/sharedblockgroup/infos";
+ info.needSession = true;
+ info.needPoll = false;
+ info.parameterName = "";
+ return info;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/GetSharedBlockGroupLunsAction.java b/sdk/src/main/java/org/zstack/sdk/GetSharedBlockGroupLunsAction.java
new file mode 100644
index 00000000000..af7b8df3789
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/GetSharedBlockGroupLunsAction.java
@@ -0,0 +1,95 @@
+package org.zstack.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.zstack.sdk.*;
+
+public class GetSharedBlockGroupLunsAction 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.GetSharedBlockGroupLunsResult 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 = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String clusterUuid;
+
+ @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;
+
+
+ private Result makeResult(ApiResult res) {
+ Result ret = new Result();
+ if (res.error != null) {
+ ret.error = res.error;
+ return ret;
+ }
+
+ org.zstack.sdk.GetSharedBlockGroupLunsResult value = res.getResult(org.zstack.sdk.GetSharedBlockGroupLunsResult.class);
+ ret.value = value == null ? new org.zstack.sdk.GetSharedBlockGroupLunsResult() : 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 = "GET";
+ info.path = "/primary-storage/sharedblockgroup/luns";
+ info.needSession = true;
+ info.needPoll = false;
+ info.parameterName = "";
+ return info;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/GetSharedBlockGroupLunsResult.java b/sdk/src/main/java/org/zstack/sdk/GetSharedBlockGroupLunsResult.java
new file mode 100644
index 00000000000..f4b859f0cc8
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/GetSharedBlockGroupLunsResult.java
@@ -0,0 +1,14 @@
+package org.zstack.sdk;
+
+
+
+public class GetSharedBlockGroupLunsResult {
+ public java.util.Map lunInfos;
+ public void setLunInfos(java.util.Map lunInfos) {
+ this.lunInfos = lunInfos;
+ }
+ public java.util.Map getLunInfos() {
+ return this.lunInfos;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/SharedBlockGroupLunInfo.java b/sdk/src/main/java/org/zstack/sdk/SharedBlockGroupLunInfo.java
new file mode 100644
index 00000000000..5357827f3e0
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/SharedBlockGroupLunInfo.java
@@ -0,0 +1,31 @@
+package org.zstack.sdk;
+
+
+
+public class SharedBlockGroupLunInfo {
+
+ public java.util.List candidateLuns;
+ public void setCandidateLuns(java.util.List candidateLuns) {
+ this.candidateLuns = candidateLuns;
+ }
+ public java.util.List getCandidateLuns() {
+ return this.candidateLuns;
+ }
+
+ public boolean sharedGroupComplete;
+ public void setSharedGroupComplete(boolean sharedGroupComplete) {
+ this.sharedGroupComplete = sharedGroupComplete;
+ }
+ public boolean getSharedGroupComplete() {
+ return this.sharedGroupComplete;
+ }
+
+ public java.util.Map existLunWwidsByHost;
+ public void setExistLunWwidsByHost(java.util.Map existLunWwidsByHost) {
+ this.existLunWwidsByHost = existLunWwidsByHost;
+ }
+ public java.util.Map getExistLunWwidsByHost() {
+ return this.existLunWwidsByHost;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/TakeoverPrimaryStorageAction.java b/sdk/src/main/java/org/zstack/sdk/TakeoverPrimaryStorageAction.java
new file mode 100644
index 00000000000..f168002ef64
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/TakeoverPrimaryStorageAction.java
@@ -0,0 +1,101 @@
+package org.zstack.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.zstack.sdk.*;
+
+public class TakeoverPrimaryStorageAction 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.TakeoverPrimaryStorageResult 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 = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String uuid;
+
+ @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.TakeoverPrimaryStorageResult value = res.getResult(org.zstack.sdk.TakeoverPrimaryStorageResult.class);
+ ret.value = value == null ? new org.zstack.sdk.TakeoverPrimaryStorageResult() : 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 = "PUT";
+ info.path = "/primary-storage/{uuid}/takeover";
+ info.needSession = true;
+ info.needPoll = true;
+ info.parameterName = "takeoverPrimaryStorage";
+ return info;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/TakeoverPrimaryStorageResult.java b/sdk/src/main/java/org/zstack/sdk/TakeoverPrimaryStorageResult.java
new file mode 100644
index 00000000000..f6fc1d6b138
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/TakeoverPrimaryStorageResult.java
@@ -0,0 +1,14 @@
+package org.zstack.sdk;
+
+import org.zstack.sdk.PrimaryStorageInventory;
+
+public class TakeoverPrimaryStorageResult {
+ public PrimaryStorageInventory inventory;
+ public void setInventory(PrimaryStorageInventory inventory) {
+ this.inventory = inventory;
+ }
+ public PrimaryStorageInventory getInventory() {
+ return this.inventory;
+ }
+
+}
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 b7f8cfbc24d..bbdf3dcbc79 100755
--- a/storage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.java
+++ b/storage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.java
@@ -935,11 +935,23 @@ protected void handleApiMessage(APIMessage msg) {
handle((APICleanUpStorageTrashOnPrimaryStorageMsg) msg);
} else if (msg instanceof APIAddStorageProtocolMsg) {
handle((APIAddStorageProtocolMsg) msg);
+ } else if (msg instanceof APITakeoverPrimaryStorageMsg) {
+ handle((APITakeoverPrimaryStorageMsg) msg);
+ } else if (msg instanceof APICheckPrimaryStorageConsistencyMsg) {
+ handle((APICheckPrimaryStorageConsistencyMsg) msg);
} else {
bus.dealWithUnknownMessage(msg);
}
}
+ protected void handle(APITakeoverPrimaryStorageMsg msg) {
+ throw new OperationFailureException(operr("operation not supported"));
+ }
+
+ protected void handle(APICheckPrimaryStorageConsistencyMsg msg) {
+ throw new OperationFailureException(operr("operation not supported"));
+ }
+
private void handle(APIAddStorageProtocolMsg msg) {
APIAddStorageProtocolEvent evt = new APIAddStorageProtocolEvent(msg.getId());
addStorageProtocol(msg, new Completion(msg) {
diff --git a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
index 07c05b73b9e..03ca61684b0 100644
--- a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
+++ b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
@@ -5282,6 +5282,33 @@ abstract class ApiHelper {
}
+ def checkPrimaryStorageConsistency(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.CheckPrimaryStorageConsistencyAction.class) Closure c) {
+ def a = new org.zstack.sdk.CheckPrimaryStorageConsistencyAction()
+ 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 checkScsiLunClusterStatus(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.CheckScsiLunClusterStatusAction.class) Closure c) {
def a = new org.zstack.sdk.CheckScsiLunClusterStatusAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
@@ -17648,6 +17675,33 @@ abstract class ApiHelper {
}
+ def getSharedBlockGroupInfos(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.GetSharedBlockGroupInfosAction.class) Closure c) {
+ def a = new org.zstack.sdk.GetSharedBlockGroupInfosAction()
+ 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 getSignatureServerEncryptPublicKey(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.GetSignatureServerEncryptPublicKeyAction.class) Closure c) {
def a = new org.zstack.sdk.GetSignatureServerEncryptPublicKeyAction()
@@ -30484,6 +30538,33 @@ abstract class ApiHelper {
}
+ def takeoverPrimaryStorage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.TakeoverPrimaryStorageAction.class) Closure c) {
+ def a = new org.zstack.sdk.TakeoverPrimaryStorageAction()
+ 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 triggerGCJob(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.TriggerGCJobAction.class) Closure c) {
def a = new org.zstack.sdk.TriggerGCJobAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid