vmInstanceMetadata) {
+ this.vmInstanceMetadata = vmInstanceMetadata == null ? new ArrayList<>() : vmInstanceMetadata;
+ }
+
+ public static APIScanVmInstanceMetadataFromPrimaryStorageEvent __example__() {
+ APIScanVmInstanceMetadataFromPrimaryStorageEvent evt = new APIScanVmInstanceMetadataFromPrimaryStorageEvent();
+ return evt;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEventDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEventDoc_zh_cn.groovy
new file mode 100644
index 00000000000..692e48f08a0
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEventDoc_zh_cn.groovy
@@ -0,0 +1,32 @@
+package org.zstack.header.storage.primary
+
+
+import org.zstack.header.errorcode.ErrorCode
+
+doc {
+
+ title "扫描主存储上的云主机元数据返回"
+
+ ref {
+ name "vmInstanceMetadata"
+ path "org.zstack.header.storage.primary.APIScanVmInstanceMetadataFromPrimaryStorageEvent.vmInstanceMetadata"
+ desc "云主机元数据摘要列表"
+ type "List"
+ since "5.0.0"
+ clz VmMetadataScanEntry.class
+ }
+ field {
+ name "success"
+ desc "操作是否成功"
+ type "boolean"
+ since "5.0.0"
+ }
+ ref {
+ name "error"
+ path "org.zstack.header.storage.primary.APIScanVmInstanceMetadataFromPrimaryStorageEvent.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/APIScanVmInstanceMetadataFromPrimaryStorageMsg.java b/header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.java
new file mode 100644
index 00000000000..411a568d5a0
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.java
@@ -0,0 +1,35 @@
+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/vm-instances/metadata/scan",
+ method = HttpMethod.GET,
+ responseClass = APIScanVmInstanceMetadataFromPrimaryStorageEvent.class
+)
+public class APIScanVmInstanceMetadataFromPrimaryStorageMsg extends APIMessage implements PrimaryStorageMessage {
+ @APIParam(resourceType = PrimaryStorageVO.class)
+ private String uuid;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ @Override
+ public String getPrimaryStorageUuid() {
+ return uuid;
+ }
+
+ public static APIScanVmInstanceMetadataFromPrimaryStorageMsg __example__() {
+ APIScanVmInstanceMetadataFromPrimaryStorageMsg msg = new APIScanVmInstanceMetadataFromPrimaryStorageMsg();
+ msg.setUuid(uuid());
+ return msg;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy
new file mode 100644
index 00000000000..090f2a36075
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy
@@ -0,0 +1,58 @@
+package org.zstack.header.storage.primary
+
+import org.zstack.header.storage.primary.APIScanVmInstanceMetadataFromPrimaryStorageEvent
+
+doc {
+ title "扫描主存储上的云主机元数据"
+
+ category "主存储"
+
+ desc """扫描指定主存储上所有云主机元数据文件,返回元数据摘要列表"""
+
+ rest {
+ request {
+ url "GET /v1/primary-storage/vm-instances/metadata/scan"
+
+ header (Authorization: 'OAuth the-session-uuid')
+
+ clz APIScanVmInstanceMetadataFromPrimaryStorageMsg.class
+
+ desc """"""
+
+ params {
+
+ column {
+ name "uuid"
+ enclosedIn ""
+ desc "主存储UUID"
+ location "query"
+ type "String"
+ optional false
+ 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 APIScanVmInstanceMetadataFromPrimaryStorageEvent.class
+ }
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 00000000000..7a23e2cdcd4
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageMsg.java
@@ -0,0 +1,52 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.NeedReplyMessage;
+
+public class CleanupVmInstanceMetadataOnPrimaryStorageMsg extends NeedReplyMessage implements PrimaryStorageMessage {
+ private String primaryStorageUuid;
+ private String vmUuid;
+ private String rootVolumeUuid;
+ private String metadataPath;
+ private String hostUuid;
+
+ @Override
+ public String getPrimaryStorageUuid() {
+ return primaryStorageUuid;
+ }
+
+ public void setPrimaryStorageUuid(String primaryStorageUuid) {
+ this.primaryStorageUuid = primaryStorageUuid;
+ }
+
+ public String getVmUuid() {
+ return vmUuid;
+ }
+
+ public void setVmUuid(String vmUuid) {
+ this.vmUuid = vmUuid;
+ }
+
+ public String getRootVolumeUuid() {
+ return rootVolumeUuid;
+ }
+
+ public void setRootVolumeUuid(String rootVolumeUuid) {
+ this.rootVolumeUuid = rootVolumeUuid;
+ }
+
+ public String getMetadataPath() {
+ return metadataPath;
+ }
+
+ public void setMetadataPath(String metadataPath) {
+ this.metadataPath = metadataPath;
+ }
+
+ public String getHostUuid() {
+ return hostUuid;
+ }
+
+ public void setHostUuid(String hostUuid) {
+ this.hostUuid = hostUuid;
+ }
+}
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
new file mode 100644
index 00000000000..05bba3ac430
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageReply.java
@@ -0,0 +1,6 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.MessageReply;
+
+public class CleanupVmInstanceMetadataOnPrimaryStorageReply extends MessageReply {
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageMsg.java b/header/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageMsg.java
new file mode 100644
index 00000000000..67ea49e5e18
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageMsg.java
@@ -0,0 +1,44 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.NeedReplyMessage;
+
+
+public class GetVmInstanceMetadataFromPrimaryStorageMsg extends NeedReplyMessage implements PrimaryStorageMessage {
+ private String primaryStorageUuid;
+ private String metadataPath;
+ private String rootVolumeUuid;
+ private String hostUuid;
+
+ @Override
+ public String getPrimaryStorageUuid() {
+ return primaryStorageUuid;
+ }
+
+ public void setPrimaryStorageUuid(String primaryStorageUuid) {
+ this.primaryStorageUuid = primaryStorageUuid;
+ }
+
+ public String getMetadataPath() {
+ return metadataPath;
+ }
+
+ public void setMetadataPath(String metadataPath) {
+ this.metadataPath = metadataPath;
+ }
+
+ public String getRootVolumeUuid() {
+ return rootVolumeUuid;
+ }
+
+ public void setRootVolumeUuid(String rootVolumeUuid) {
+ this.rootVolumeUuid = rootVolumeUuid;
+ }
+
+ public String getHostUuid() {
+ return hostUuid;
+ }
+
+ public void setHostUuid(String hostUuid) {
+ this.hostUuid = hostUuid;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageReply.java b/header/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageReply.java
new file mode 100644
index 00000000000..c164a99792d
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageReply.java
@@ -0,0 +1,15 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.MessageReply;
+
+public class GetVmInstanceMetadataFromPrimaryStorageReply extends MessageReply {
+ private String metadata;
+
+ public String getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(String metadata) {
+ this.metadata = metadata;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataMsg.java b/header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataMsg.java
new file mode 100644
index 00000000000..ed09f15eb4d
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataMsg.java
@@ -0,0 +1,21 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.NeedReplyMessage;
+import org.zstack.header.vm.VmInstanceMessage;
+
+public class ReadVmInstanceMetadataMsg extends NeedReplyMessage implements VmInstanceMessage {
+ private String uuid;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ @Override
+ public String getVmInstanceUuid() {
+ return uuid;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataReply.java b/header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataReply.java
new file mode 100644
index 00000000000..04462f849ad
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataReply.java
@@ -0,0 +1,15 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.MessageReply;
+
+public class ReadVmInstanceMetadataReply extends MessageReply {
+ private String vmMetadata;
+
+ public String getVmMetadata() {
+ return vmMetadata;
+ }
+
+ public void setVmMetadata(String vmMetadata) {
+ this.vmMetadata = vmMetadata;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageMsg.java b/header/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageMsg.java
new file mode 100644
index 00000000000..f9dd68d2934
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageMsg.java
@@ -0,0 +1,70 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.NeedReplyMessage;
+
+import java.util.List;
+
+/**
+ * 请求目标主存储对指定文件做 backing file 前缀替换(prefix rebase)。
+ *
+ * 各存储插件(LocalStorage / SharedBlock / NFS)自行选择 host、构造 agent command 并发送。
+ */
+public class RebaseVolumeBackingFileOnPrimaryStorageMsg extends NeedReplyMessage implements PrimaryStorageMessage {
+ private String primaryStorageUuid;
+
+ /**
+ * volume + snapshot 的 installPath 列表(已做路径替换的逻辑路径)。
+ * LocalStorage / NFS 下即绝对路径;SharedBlock 下为 sharedblock:// scheme 路径,由插件内部转绝对路径。
+ */
+ private List installPaths;
+
+ /** 旧路径前缀 */
+ private String oldPrefix;
+
+ /** 新路径前缀 */
+ private String newPrefix;
+
+ /** 注册请求指定的 hostUuid(LocalStorage 需要,其他存储可忽略) */
+ private String hostUuid;
+
+ @Override
+ public String getPrimaryStorageUuid() {
+ return primaryStorageUuid;
+ }
+
+ public void setPrimaryStorageUuid(String primaryStorageUuid) {
+ this.primaryStorageUuid = primaryStorageUuid;
+ }
+
+ public List getInstallPaths() {
+ return installPaths;
+ }
+
+ public void setInstallPaths(List installPaths) {
+ this.installPaths = installPaths;
+ }
+
+ public String getOldPrefix() {
+ return oldPrefix;
+ }
+
+ public void setOldPrefix(String oldPrefix) {
+ this.oldPrefix = oldPrefix;
+ }
+
+ public String getNewPrefix() {
+ return newPrefix;
+ }
+
+ public void setNewPrefix(String newPrefix) {
+ this.newPrefix = newPrefix;
+ }
+
+ public String getHostUuid() {
+ return hostUuid;
+ }
+
+ public void setHostUuid(String hostUuid) {
+ this.hostUuid = hostUuid;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageReply.java b/header/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageReply.java
new file mode 100644
index 00000000000..44043421f09
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageReply.java
@@ -0,0 +1,15 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.MessageReply;
+
+public class RebaseVolumeBackingFileOnPrimaryStorageReply extends MessageReply {
+ private int rebasedCount;
+
+ public int getRebasedCount() {
+ return rebasedCount;
+ }
+
+ public void setRebasedCount(int rebasedCount) {
+ this.rebasedCount = rebasedCount;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageMsg.java b/header/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageMsg.java
new file mode 100644
index 00000000000..052e77f7507
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageMsg.java
@@ -0,0 +1,25 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.NeedReplyMessage;
+
+public class ScanVmInstanceMetadataFromPrimaryStorageMsg 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/ScanVmInstanceMetadataFromPrimaryStorageReply.java b/header/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageReply.java
new file mode 100644
index 00000000000..a78db671a30
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageReply.java
@@ -0,0 +1,18 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.MessageReply;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ScanVmInstanceMetadataFromPrimaryStorageReply extends MessageReply {
+ private List vmInstanceMetadata = new ArrayList<>();
+
+ public List getVmInstanceMetadata() {
+ return vmInstanceMetadata;
+ }
+
+ public void setVmInstanceMetadata(List vmInstanceMetadata) {
+ this.vmInstanceMetadata = vmInstanceMetadata == null ? new ArrayList<>() : vmInstanceMetadata;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntry.java b/header/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntry.java
new file mode 100644
index 00000000000..9859bc2aca7
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntry.java
@@ -0,0 +1,94 @@
+package org.zstack.header.storage.primary;
+
+public class VmMetadataScanEntry {
+ private String vmUuid;
+ private String vmName;
+ private String vmCategory;
+ private String architecture;
+ private String schemaVersion;
+ private String metadataPath;
+ private String hostUuid;
+ private long sizeBytes;
+ private long lastUpdateTime;
+ private boolean incomplete;
+
+ public String getVmUuid() {
+ return vmUuid;
+ }
+
+ public void setVmUuid(String vmUuid) {
+ this.vmUuid = vmUuid;
+ }
+
+ public String getVmName() {
+ return vmName;
+ }
+
+ public void setVmName(String vmName) {
+ this.vmName = vmName;
+ }
+
+ public String getVmCategory() {
+ return vmCategory;
+ }
+
+ public void setVmCategory(String vmCategory) {
+ this.vmCategory = vmCategory;
+ }
+
+ public String getArchitecture() {
+ return architecture;
+ }
+
+ public void setArchitecture(String architecture) {
+ this.architecture = architecture;
+ }
+
+ public String getSchemaVersion() {
+ return schemaVersion;
+ }
+
+ public void setSchemaVersion(String schemaVersion) {
+ this.schemaVersion = schemaVersion;
+ }
+
+ public String getMetadataPath() {
+ return metadataPath;
+ }
+
+ public void setMetadataPath(String metadataPath) {
+ this.metadataPath = metadataPath;
+ }
+
+ public String getHostUuid() {
+ return hostUuid;
+ }
+
+ public void setHostUuid(String hostUuid) {
+ this.hostUuid = hostUuid;
+ }
+
+ public long getSizeBytes() {
+ return sizeBytes;
+ }
+
+ public void setSizeBytes(long sizeBytes) {
+ this.sizeBytes = sizeBytes;
+ }
+
+ public long getLastUpdateTime() {
+ return lastUpdateTime;
+ }
+
+ public void setLastUpdateTime(long lastUpdateTime) {
+ this.lastUpdateTime = lastUpdateTime;
+ }
+
+ public boolean isIncomplete() {
+ return incomplete;
+ }
+
+ public void setIncomplete(boolean incomplete) {
+ this.incomplete = incomplete;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntryDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntryDoc_zh_cn.groovy
new file mode 100644
index 00000000000..101eddf8515
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntryDoc_zh_cn.groovy
@@ -0,0 +1,4 @@
+package org.zstack.header.storage.primary
+
+class VmMetadataScanEntryDoc_zh_cn {
+}
diff --git a/header/src/main/java/org/zstack/header/storage/snapshot/APIDeleteVolumeSnapshotMsg.java b/header/src/main/java/org/zstack/header/storage/snapshot/APIDeleteVolumeSnapshotMsg.java
index 966a7d1030c..4711fa5de74 100755
--- a/header/src/main/java/org/zstack/header/storage/snapshot/APIDeleteVolumeSnapshotMsg.java
+++ b/header/src/main/java/org/zstack/header/storage/snapshot/APIDeleteVolumeSnapshotMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.*;
import org.zstack.header.rest.APINoSee;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -44,6 +45,7 @@
responseClass = APIDeleteVolumeSnapshotEvent.class
)
@DefaultTimeout(timeunit = TimeUnit.HOURS, value = 6)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "SnapshotUuidToVmUuidResolver", field = "uuid", updateOnFailure = true)
public class APIDeleteVolumeSnapshotMsg extends APIDeleteMessage implements DeleteVolumeSnapshotMessage {
/**
* @desc volume snapshot uuid
diff --git a/header/src/main/java/org/zstack/header/storage/snapshot/APIRevertVolumeFromSnapshotMsg.java b/header/src/main/java/org/zstack/header/storage/snapshot/APIRevertVolumeFromSnapshotMsg.java
index 744f13038b6..6ae3008e03e 100755
--- a/header/src/main/java/org/zstack/header/storage/snapshot/APIRevertVolumeFromSnapshotMsg.java
+++ b/header/src/main/java/org/zstack/header/storage/snapshot/APIRevertVolumeFromSnapshotMsg.java
@@ -8,6 +8,7 @@
import org.zstack.header.other.APIAuditor;
import org.zstack.header.rest.APINoSee;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import org.zstack.header.volume.VolumeVO;
import java.util.concurrent.TimeUnit;
@@ -46,6 +47,7 @@
responseClass = APIRevertVolumeFromSnapshotEvent.class
)
@DefaultTimeout(timeunit = TimeUnit.HOURS, value = 24)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "SnapshotUuidToVmUuidResolver", field = "uuid", updateOnFailure = true)
public class APIRevertVolumeFromSnapshotMsg extends APIMessage implements RevertVolumeSnapshotMessage, APIAuditor {
/**
* @desc volume snapshot uuid
diff --git a/header/src/main/java/org/zstack/header/storage/snapshot/APIShrinkVolumeSnapshotMsg.java b/header/src/main/java/org/zstack/header/storage/snapshot/APIShrinkVolumeSnapshotMsg.java
index d5f00be9237..f8a1a670023 100644
--- a/header/src/main/java/org/zstack/header/storage/snapshot/APIShrinkVolumeSnapshotMsg.java
+++ b/header/src/main/java/org/zstack/header/storage/snapshot/APIShrinkVolumeSnapshotMsg.java
@@ -6,6 +6,7 @@
import org.zstack.header.message.DefaultTimeout;
import org.zstack.header.rest.APINoSee;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.util.concurrent.TimeUnit;
@@ -20,6 +21,7 @@
isAction = true
)
@DefaultTimeout(timeunit = TimeUnit.HOURS, value = 24)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "SnapshotUuidToVmUuidResolver", field = "uuid")
public class APIShrinkVolumeSnapshotMsg extends APIMessage implements VolumeSnapshotMessage {
@APIParam(resourceType = VolumeSnapshotVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/storage/snapshot/APIUpdateVolumeSnapshotMsg.java b/header/src/main/java/org/zstack/header/storage/snapshot/APIUpdateVolumeSnapshotMsg.java
index 870a9ceacd4..6daf7b61649 100755
--- a/header/src/main/java/org/zstack/header/storage/snapshot/APIUpdateVolumeSnapshotMsg.java
+++ b/header/src/main/java/org/zstack/header/storage/snapshot/APIUpdateVolumeSnapshotMsg.java
@@ -5,6 +5,7 @@
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.APINoSee;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by frank on 6/14/2015.
@@ -15,6 +16,7 @@
isAction = true,
responseClass = APIUpdateVolumeSnapshotEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "SnapshotUuidToVmUuidResolver", field = "uuid")
public class APIUpdateVolumeSnapshotMsg extends APIMessage implements VolumeSnapshotMessage {
@APIParam(resourceType = VolumeSnapshotVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/storage/snapshot/group/APIDeleteVolumeSnapshotGroupMsg.java b/header/src/main/java/org/zstack/header/storage/snapshot/group/APIDeleteVolumeSnapshotGroupMsg.java
index 4afc5170734..cb1f8dde454 100644
--- a/header/src/main/java/org/zstack/header/storage/snapshot/group/APIDeleteVolumeSnapshotGroupMsg.java
+++ b/header/src/main/java/org/zstack/header/storage/snapshot/group/APIDeleteVolumeSnapshotGroupMsg.java
@@ -7,6 +7,7 @@
import org.zstack.header.rest.APINoSee;
import org.zstack.header.rest.RestRequest;
import org.zstack.header.storage.snapshot.SnapshotBackendOperation;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.util.concurrent.TimeUnit;
@@ -19,6 +20,7 @@
responseClass = APIDeleteVolumeSnapshotGroupEvent.class
)
@DefaultTimeout(timeunit = TimeUnit.HOURS, value = 3)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "SnapshotGroupUuidToVmUuidResolver", field = "uuid", updateOnFailure = true)
public class APIDeleteVolumeSnapshotGroupMsg extends APIDeleteMessage implements VolumeSnapshotGroupMessage {
@APIParam(resourceType = VolumeSnapshotGroupVO.class, successIfResourceNotExisting = true)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/storage/snapshot/group/APIRevertVmFromSnapshotGroupMsg.java b/header/src/main/java/org/zstack/header/storage/snapshot/group/APIRevertVmFromSnapshotGroupMsg.java
index d042ee6229f..28752daf8b0 100644
--- a/header/src/main/java/org/zstack/header/storage/snapshot/group/APIRevertVmFromSnapshotGroupMsg.java
+++ b/header/src/main/java/org/zstack/header/storage/snapshot/group/APIRevertVmFromSnapshotGroupMsg.java
@@ -14,6 +14,7 @@
import org.zstack.header.rest.RestRequest;
import org.zstack.header.storage.snapshot.SnapshotBackendOperation;
import org.zstack.header.vm.VmInstanceVO;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.util.concurrent.TimeUnit;
@@ -25,6 +26,7 @@
)
@DefaultTimeout(timeunit = TimeUnit.HOURS, value = 24)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "SnapshotGroupUuidToVmUuidResolver", field = "uuid", updateOnFailure = true)
public class APIRevertVmFromSnapshotGroupMsg extends APIMessage implements VolumeSnapshotGroupMessage, APIAuditor {
@APIParam(resourceType = VolumeSnapshotGroupVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/storage/snapshot/group/APIUngroupVolumeSnapshotGroupMsg.java b/header/src/main/java/org/zstack/header/storage/snapshot/group/APIUngroupVolumeSnapshotGroupMsg.java
index daa39380ac1..6428bde5269 100644
--- a/header/src/main/java/org/zstack/header/storage/snapshot/group/APIUngroupVolumeSnapshotGroupMsg.java
+++ b/header/src/main/java/org/zstack/header/storage/snapshot/group/APIUngroupVolumeSnapshotGroupMsg.java
@@ -5,6 +5,7 @@
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
import org.zstack.header.storage.snapshot.SnapshotBackendOperation;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by MaJin on 2019/7/9.
@@ -14,6 +15,7 @@
method = HttpMethod.DELETE,
responseClass = APIUngroupVolumeSnapshotGroupEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "SnapshotGroupUuidToVmUuidResolver", field = "uuid")
public class APIUngroupVolumeSnapshotGroupMsg extends APIMessage implements VolumeSnapshotGroupMessage {
@APIParam(resourceType = VolumeSnapshotGroupVO.class, successIfResourceNotExisting = true)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/storage/snapshot/group/APIUpdateVolumeSnapshotGroupMsg.java b/header/src/main/java/org/zstack/header/storage/snapshot/group/APIUpdateVolumeSnapshotGroupMsg.java
index 0cee28cd6ea..68deeb2b635 100644
--- a/header/src/main/java/org/zstack/header/storage/snapshot/group/APIUpdateVolumeSnapshotGroupMsg.java
+++ b/header/src/main/java/org/zstack/header/storage/snapshot/group/APIUpdateVolumeSnapshotGroupMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import org.zstack.header.storage.snapshot.SnapshotBackendOperation;
/**
@@ -15,6 +16,7 @@
isAction = true,
responseClass = APIUpdateVolumeSnapshotGroupEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "SnapshotGroupUuidToVmUuidResolver", field = "uuid")
public class APIUpdateVolumeSnapshotGroupMsg extends APIMessage implements VolumeSnapshotGroupMessage {
@APIParam(required = false)
private String name;
diff --git a/header/src/main/java/org/zstack/header/tag/APICreateSystemTagMsg.java b/header/src/main/java/org/zstack/header/tag/APICreateSystemTagMsg.java
index a02a6001cf1..aaa350d471a 100755
--- a/header/src/main/java/org/zstack/header/tag/APICreateSystemTagMsg.java
+++ b/header/src/main/java/org/zstack/header/tag/APICreateSystemTagMsg.java
@@ -2,6 +2,7 @@
import org.springframework.http.HttpMethod;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
*/
@@ -11,6 +12,7 @@
responseClass = APICreateSystemTagEvent.class,
parameterName = "params"
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "ResourceUuidToVmUuidResolver", field = "resourceUuid")
public class APICreateSystemTagMsg extends APIAbstractCreateTagMsg {
public static APICreateSystemTagMsg __example__() {
diff --git a/header/src/main/java/org/zstack/header/tag/APICreateSystemTagsMsg.java b/header/src/main/java/org/zstack/header/tag/APICreateSystemTagsMsg.java
index 170076094d9..c2fa8085b91 100644
--- a/header/src/main/java/org/zstack/header/tag/APICreateSystemTagsMsg.java
+++ b/header/src/main/java/org/zstack/header/tag/APICreateSystemTagsMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import org.zstack.header.vo.ResourceVO;
import java.util.List;
@@ -16,6 +17,7 @@
responseClass = APICreateSystemTagsEvent.class,
parameterName = "params"
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "ResourceUuidToVmUuidResolver", field = "resourceUuid")
public class APICreateSystemTagsMsg extends APIMessage {
@APIParam
private String resourceType;
diff --git a/header/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.java b/header/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.java
index b1159b20945..59597ac6901 100755
--- a/header/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.java
+++ b/header/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIDeleteMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
*/
@@ -12,6 +13,7 @@
method = HttpMethod.DELETE,
responseClass = APIDeleteTagEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "SystemTagUuidToVmUuidResolver", field = "uuid")
public class APIDeleteTagMsg extends APIDeleteMessage {
@APIParam
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/tag/APIUpdateSystemTagMsg.java b/header/src/main/java/org/zstack/header/tag/APIUpdateSystemTagMsg.java
index 2962ce07061..65173855747 100755
--- a/header/src/main/java/org/zstack/header/tag/APIUpdateSystemTagMsg.java
+++ b/header/src/main/java/org/zstack/header/tag/APIUpdateSystemTagMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by frank on 8/17/2015.
@@ -14,6 +15,7 @@
isAction = true,
method = HttpMethod.PUT
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "SystemTagUuidToVmUuidResolver", field = "uuid")
public class APIUpdateSystemTagMsg extends APIMessage {
@APIParam(resourceType = SystemTagVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIAttachIsoToVmInstanceMsg.java b/header/src/main/java/org/zstack/header/vm/APIAttachIsoToVmInstanceMsg.java
index c28f55a3c6c..e630c877e5c 100755
--- a/header/src/main/java/org/zstack/header/vm/APIAttachIsoToVmInstanceMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIAttachIsoToVmInstanceMsg.java
@@ -6,6 +6,7 @@
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.APINoSee;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by frank on 10/17/2015.
@@ -16,6 +17,7 @@
responseClass = APIAttachIsoToVmInstanceEvent.class,
parameterName = "null"
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "vmInstanceUuid")
public class APIAttachIsoToVmInstanceMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String vmInstanceUuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIAttachL3NetworkToVmMsg.java b/header/src/main/java/org/zstack/header/vm/APIAttachL3NetworkToVmMsg.java
index 7bab9be06f9..681a04c6b51 100755
--- a/header/src/main/java/org/zstack/header/vm/APIAttachL3NetworkToVmMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIAttachL3NetworkToVmMsg.java
@@ -6,6 +6,7 @@
import org.zstack.header.network.l3.L3NetworkVO;
import org.zstack.header.rest.APINoSee;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import org.zstack.utils.network.NicIpAddressInfo;
import java.util.List;
@@ -45,6 +46,7 @@
method = HttpMethod.POST,
responseClass = APIAttachL3NetworkToVmEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "vmInstanceUuid")
public class APIAttachL3NetworkToVmMsg extends APIMessage implements VmInstanceMessage {
/**
* @desc vm uuid
diff --git a/header/src/main/java/org/zstack/header/vm/APIAttachVmNicToVmMsg.java b/header/src/main/java/org/zstack/header/vm/APIAttachVmNicToVmMsg.java
index 05b86a2bedf..5313e83aa0e 100644
--- a/header/src/main/java/org/zstack/header/vm/APIAttachVmNicToVmMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIAttachVmNicToVmMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
@RestRequest(
path = "/vm-instances/{vmInstanceUuid}/nices/{vmNicUuid}",
@@ -11,6 +12,7 @@
responseClass = APIAttachVmNicToVmEvent.class,
parameterName = "params"
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "vmInstanceUuid")
public class APIAttachVmNicToVmMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmNicVO.class)
diff --git a/header/src/main/java/org/zstack/header/vm/APIChangeInstanceOfferingMsg.java b/header/src/main/java/org/zstack/header/vm/APIChangeInstanceOfferingMsg.java
index aa0e68f9211..d157868793f 100755
--- a/header/src/main/java/org/zstack/header/vm/APIChangeInstanceOfferingMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIChangeInstanceOfferingMsg.java
@@ -5,6 +5,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by frank on 7/16/2015.
@@ -15,6 +16,7 @@
method = HttpMethod.PUT,
responseClass = APIChangeInstanceOfferingEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "vmInstanceUuid")
public class APIChangeInstanceOfferingMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String vmInstanceUuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIChangeVmNicNetworkMsg.java b/header/src/main/java/org/zstack/header/vm/APIChangeVmNicNetworkMsg.java
index 60ded8149d2..bfedeb43306 100644
--- a/header/src/main/java/org/zstack/header/vm/APIChangeVmNicNetworkMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIChangeVmNicNetworkMsg.java
@@ -6,6 +6,7 @@
import org.zstack.header.network.l3.L3NetworkVO;
import org.zstack.header.rest.APINoSee;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.util.List;
import java.util.Map;
@@ -16,6 +17,7 @@
method = HttpMethod.POST,
responseClass = APIChangeVmNicNetworkEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "NicUuidToVmUuidResolver", field = "vmNicUuid")
public class APIChangeVmNicNetworkMsg extends APIMessage implements VmInstanceMessage{
@APIParam(resourceType = VmNicVO.class)
private String vmNicUuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIChangeVmNicStateMsg.java b/header/src/main/java/org/zstack/header/vm/APIChangeVmNicStateMsg.java
index 6c1594fed23..1a38b709b25 100644
--- a/header/src/main/java/org/zstack/header/vm/APIChangeVmNicStateMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIChangeVmNicStateMsg.java
@@ -9,6 +9,7 @@
import org.zstack.header.other.APIMultiAuditor;
import org.zstack.header.rest.APINoSee;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.util.ArrayList;
import java.util.List;
@@ -22,6 +23,7 @@
responseClass = APIChangeVmNicStateEvent.class,
isAction = true
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "NicUuidToVmUuidResolver", field = "vmNicUuid")
public class APIChangeVmNicStateMsg extends APIMessage implements VmInstanceMessage, APIMultiAuditor {
@APIParam(resourceType = VmNicVO.class)
private String vmNicUuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIConvertTemplatedVmInstanceToVmInstanceMsg.java b/header/src/main/java/org/zstack/header/vm/APIConvertTemplatedVmInstanceToVmInstanceMsg.java
index 1a128bfaf84..0327fdbc896 100644
--- a/header/src/main/java/org/zstack/header/vm/APIConvertTemplatedVmInstanceToVmInstanceMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIConvertTemplatedVmInstanceToVmInstanceMsg.java
@@ -7,6 +7,7 @@
import org.zstack.header.other.APIAuditor;
import org.zstack.header.rest.APINoSee;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
@RestRequest(
path = "/vm-instances/{templatedVmInstanceUuid}/convert-to-vmInstance",
@@ -14,6 +15,7 @@
responseClass = APIConvertTemplatedVmInstanceToVmInstanceEvent.class,
parameterName = "params"
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "templatedVmInstanceUuid")
public class APIConvertTemplatedVmInstanceToVmInstanceMsg extends APIMessage implements VmInstanceMessage, APIAuditor {
@APIParam(resourceType = TemplatedVmInstanceVO.class)
private String templatedVmInstanceUuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIConvertVmInstanceToTemplatedVmInstanceMsg.java b/header/src/main/java/org/zstack/header/vm/APIConvertVmInstanceToTemplatedVmInstanceMsg.java
index 2b9191824b7..d83709a1703 100644
--- a/header/src/main/java/org/zstack/header/vm/APIConvertVmInstanceToTemplatedVmInstanceMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIConvertVmInstanceToTemplatedVmInstanceMsg.java
@@ -6,6 +6,7 @@
import org.zstack.header.message.APIParam;
import org.zstack.header.other.APIAuditor;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
@RestRequest(
path = "/vm-instances/{vmInstanceUuid}/convert-to-templatedVmInstance",
@@ -13,6 +14,7 @@
responseClass = APIConvertVmInstanceToTemplatedVmInstanceEvent.class,
parameterName = "params"
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "vmInstanceUuid")
public class APIConvertVmInstanceToTemplatedVmInstanceMsg extends APIMessage implements VmInstanceMessage, APIAuditor {
@APIParam(resourceType = VmInstanceVO.class)
private String vmInstanceUuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIDeleteVmBootModeMsg.java b/header/src/main/java/org/zstack/header/vm/APIDeleteVmBootModeMsg.java
index a2b73a69527..27d27afa839 100644
--- a/header/src/main/java/org/zstack/header/vm/APIDeleteVmBootModeMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIDeleteVmBootModeMsg.java
@@ -4,12 +4,14 @@
import org.zstack.header.message.APIDeleteMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
@RestRequest(
path = "/vm-instances/{uuid}/bootmode",
method = HttpMethod.DELETE,
responseClass = APIDeleteVmBootModeEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APIDeleteVmBootModeMsg extends APIDeleteMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIDeleteVmConsolePasswordMsg.java b/header/src/main/java/org/zstack/header/vm/APIDeleteVmConsolePasswordMsg.java
index e9d6152c7ef..f7b0cb056a1 100755
--- a/header/src/main/java/org/zstack/header/vm/APIDeleteVmConsolePasswordMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIDeleteVmConsolePasswordMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by root on 8/2/16.
@@ -13,6 +14,7 @@
method = HttpMethod.DELETE,
responseClass = APIDeleteVmConsolePasswordEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APIDeleteVmConsolePasswordMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIDeleteVmHostnameMsg.java b/header/src/main/java/org/zstack/header/vm/APIDeleteVmHostnameMsg.java
index 611c1c13da4..89aaa4a1e95 100755
--- a/header/src/main/java/org/zstack/header/vm/APIDeleteVmHostnameMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIDeleteVmHostnameMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIDeleteMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by frank on 2/26/2016.
@@ -13,6 +14,7 @@
method = HttpMethod.DELETE,
responseClass = APIDeleteVmHostnameEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APIDeleteVmHostnameMsg extends APIDeleteMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIDeleteVmSshKeyMsg.java b/header/src/main/java/org/zstack/header/vm/APIDeleteVmSshKeyMsg.java
index 0372c7526ab..f10c7ed7e83 100755
--- a/header/src/main/java/org/zstack/header/vm/APIDeleteVmSshKeyMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIDeleteVmSshKeyMsg.java
@@ -3,6 +3,7 @@
import org.springframework.http.HttpMethod;
import org.zstack.header.message.APIMessage;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by luchukun on 8/4/16.
@@ -12,6 +13,7 @@
method = HttpMethod.DELETE,
responseClass = APIDeleteVmSshKeyEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APIDeleteVmSshKeyMsg extends APIMessage implements VmInstanceMessage {
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIDeleteVmStaticIpMsg.java b/header/src/main/java/org/zstack/header/vm/APIDeleteVmStaticIpMsg.java
index 15d11f96647..2f1312fb903 100755
--- a/header/src/main/java/org/zstack/header/vm/APIDeleteVmStaticIpMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIDeleteVmStaticIpMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIDeleteMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by frank on 2/26/2016.
@@ -13,6 +14,7 @@
method = HttpMethod.DELETE,
responseClass = APIDeleteVmStaticIpEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "vmInstanceUuid")
public class APIDeleteVmStaticIpMsg extends APIDeleteMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String vmInstanceUuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIDestroyVmInstanceMsg.java b/header/src/main/java/org/zstack/header/vm/APIDestroyVmInstanceMsg.java
index b93c5eb4361..9fa37d94788 100755
--- a/header/src/main/java/org/zstack/header/vm/APIDestroyVmInstanceMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIDestroyVmInstanceMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIDeleteMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.util.List;
@@ -41,6 +42,7 @@
method = HttpMethod.DELETE,
responseClass = APIDestroyVmInstanceEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APIDestroyVmInstanceMsg extends APIDeleteMessage implements VmInstanceMessage {
/**
* @desc vm uuid
diff --git a/header/src/main/java/org/zstack/header/vm/APIDetachIsoFromVmInstanceMsg.java b/header/src/main/java/org/zstack/header/vm/APIDetachIsoFromVmInstanceMsg.java
index 52d17b61fec..3cffd78123a 100755
--- a/header/src/main/java/org/zstack/header/vm/APIDetachIsoFromVmInstanceMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIDetachIsoFromVmInstanceMsg.java
@@ -7,6 +7,7 @@
import org.zstack.header.message.APIParam;
import org.zstack.header.other.APIAuditor;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by frank on 10/17/2015.
@@ -16,6 +17,7 @@
method = HttpMethod.DELETE,
responseClass = APIDetachIsoFromVmInstanceEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "vmInstanceUuid")
public class APIDetachIsoFromVmInstanceMsg extends APIMessage implements VmInstanceMessage, APIAuditor {
@APIParam(resourceType = VmInstanceVO.class)
private String vmInstanceUuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIDetachL3NetworkFromVmMsg.java b/header/src/main/java/org/zstack/header/vm/APIDetachL3NetworkFromVmMsg.java
index 0d2c7d2d38f..e226e8f962b 100755
--- a/header/src/main/java/org/zstack/header/vm/APIDetachL3NetworkFromVmMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIDetachL3NetworkFromVmMsg.java
@@ -9,6 +9,7 @@
import org.zstack.header.other.APIMultiAuditor;
import org.zstack.header.rest.APINoSee;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.util.ArrayList;
import java.util.List;
@@ -21,6 +22,7 @@
method = HttpMethod.DELETE,
responseClass = APIDetachL3NetworkFromVmEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "NicUuidToVmUuidResolver", field = "vmNicUuid")
public class APIDetachL3NetworkFromVmMsg extends APIMessage implements VmInstanceMessage, APIMultiAuditor {
@APIParam(resourceType = VmNicVO.class)
private String vmNicUuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIMigrateVmMsg.java b/header/src/main/java/org/zstack/header/vm/APIMigrateVmMsg.java
index e6ed3bbf44b..1fa0f34f2f5 100755
--- a/header/src/main/java/org/zstack/header/vm/APIMigrateVmMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIMigrateVmMsg.java
@@ -6,6 +6,7 @@
import org.zstack.header.message.APIParam;
import org.zstack.header.message.DefaultTimeout;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.util.concurrent.TimeUnit;
@@ -44,6 +45,7 @@
)
@SkipVmTracer(replyClass = APIMigrateVmEvent.class)
@DefaultTimeout(timeunit = TimeUnit.HOURS, value = 1)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "VmUuidDirectResolver", field = "vmInstanceUuid")
public class APIMigrateVmMsg extends APIMessage implements VmInstanceMessage, MigrateVmMessage, CheckAttachedVolumesMessage {
/**
* @desc vm uuid
diff --git a/header/src/main/java/org/zstack/header/vm/APIRecoverVmInstanceMsg.java b/header/src/main/java/org/zstack/header/vm/APIRecoverVmInstanceMsg.java
index 7de84b5dccd..fd0f4c44622 100755
--- a/header/src/main/java/org/zstack/header/vm/APIRecoverVmInstanceMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIRecoverVmInstanceMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by frank on 11/12/2015.
@@ -14,6 +15,7 @@
method = HttpMethod.PUT,
responseClass = APIRecoverVmInstanceEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APIRecoverVmInstanceMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIReimageVmInstanceMsg.java b/header/src/main/java/org/zstack/header/vm/APIReimageVmInstanceMsg.java
index 53ad2c26f4f..dc78a69c631 100755
--- a/header/src/main/java/org/zstack/header/vm/APIReimageVmInstanceMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIReimageVmInstanceMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by miao on 11/3/16.
@@ -15,6 +16,7 @@
responseClass = APIReimageVmInstanceEvent.class,
category = "vmInstance"
)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "VmUuidDirectResolver", field = "vmInstanceUuid")
public class APIReimageVmInstanceMsg extends APIMessage implements VmInstanceMessage {
public String getVmInstanceUuid() {
return vmInstanceUuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APISetVmBootModeMsg.java b/header/src/main/java/org/zstack/header/vm/APISetVmBootModeMsg.java
index 0aa6e025c3c..e96b38cd64b 100644
--- a/header/src/main/java/org/zstack/header/vm/APISetVmBootModeMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APISetVmBootModeMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
@RestRequest(
path = "/vm-instances/{uuid}/actions",
@@ -11,6 +12,7 @@
isAction = true,
responseClass = APISetVmBootModeEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APISetVmBootModeMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APISetVmBootOrderMsg.java b/header/src/main/java/org/zstack/header/vm/APISetVmBootOrderMsg.java
index fb3d980e807..7400901f35c 100755
--- a/header/src/main/java/org/zstack/header/vm/APISetVmBootOrderMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APISetVmBootOrderMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.util.List;
@@ -18,6 +19,7 @@
method = HttpMethod.PUT,
responseClass = APISetVmBootOrderEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APISetVmBootOrderMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APISetVmBootVolumeMsg.java b/header/src/main/java/org/zstack/header/vm/APISetVmBootVolumeMsg.java
index a72619161e0..bf1d090f845 100644
--- a/header/src/main/java/org/zstack/header/vm/APISetVmBootVolumeMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APISetVmBootVolumeMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import org.zstack.header.volume.VolumeVO;
/**
@@ -16,6 +17,7 @@
method = HttpMethod.PUT,
responseClass = APISetVmBootVolumeEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "VmUuidDirectResolver", field = "vmInstanceUuid")
public class APISetVmBootVolumeMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String vmInstanceUuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APISetVmClockTrackMsg.java b/header/src/main/java/org/zstack/header/vm/APISetVmClockTrackMsg.java
index 1f25eead1db..2aa0026eb79 100644
--- a/header/src/main/java/org/zstack/header/vm/APISetVmClockTrackMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APISetVmClockTrackMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
@RestRequest(
path = "/vm-instances/{uuid}/actions",
@@ -11,6 +12,7 @@
method = HttpMethod.PUT,
responseClass = APISetVmClockTrackEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APISetVmClockTrackMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APISetVmConsolePasswordMsg.java b/header/src/main/java/org/zstack/header/vm/APISetVmConsolePasswordMsg.java
index 0812289e799..30c886d2833 100755
--- a/header/src/main/java/org/zstack/header/vm/APISetVmConsolePasswordMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APISetVmConsolePasswordMsg.java
@@ -5,6 +5,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.io.Serializable;
@@ -18,6 +19,7 @@
method = HttpMethod.PUT,
responseClass = APISetVmConsolePasswordEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APISetVmConsolePasswordMsg extends APIMessage implements VmInstanceMessage, Serializable {
@APIParam(resourceType = VmInstanceVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APISetVmHostnameMsg.java b/header/src/main/java/org/zstack/header/vm/APISetVmHostnameMsg.java
index 2b2e54afabc..2ea204e2f29 100755
--- a/header/src/main/java/org/zstack/header/vm/APISetVmHostnameMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APISetVmHostnameMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by frank on 2/26/2016.
@@ -14,6 +15,7 @@
isAction = true,
responseClass = APISetVmHostnameEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APISetVmHostnameMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APISetVmQxlMemoryMsg.java b/header/src/main/java/org/zstack/header/vm/APISetVmQxlMemoryMsg.java
index c5d7ebd8e72..e83d4662015 100644
--- a/header/src/main/java/org/zstack/header/vm/APISetVmQxlMemoryMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APISetVmQxlMemoryMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
@RestRequest(
path = "/vm-instances/{uuid}/actions",
@@ -11,6 +12,7 @@
method = HttpMethod.PUT,
responseClass = APISetVmQxlMemoryEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APISetVmQxlMemoryMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APISetVmSoundTypeMsg.java b/header/src/main/java/org/zstack/header/vm/APISetVmSoundTypeMsg.java
index 686697b009c..3c348568865 100644
--- a/header/src/main/java/org/zstack/header/vm/APISetVmSoundTypeMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APISetVmSoundTypeMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
@RestRequest(
path = "/vm-instances/{uuid}/actions",
@@ -11,6 +12,7 @@
method = HttpMethod.PUT,
responseClass = APISetVmSoundTypeEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APISetVmSoundTypeMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APISetVmSshKeyMsg.java b/header/src/main/java/org/zstack/header/vm/APISetVmSshKeyMsg.java
index 3b2d315ea06..fc3bdf81f03 100755
--- a/header/src/main/java/org/zstack/header/vm/APISetVmSshKeyMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APISetVmSshKeyMsg.java
@@ -5,6 +5,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by luchukun on 8/4/16.
@@ -15,6 +16,7 @@
method = HttpMethod.PUT,
responseClass = APISetVmSshKeyEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APISetVmSshKeyMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APISetVmStaticIpMsg.java b/header/src/main/java/org/zstack/header/vm/APISetVmStaticIpMsg.java
index 094f9d4a54f..c82b4064519 100755
--- a/header/src/main/java/org/zstack/header/vm/APISetVmStaticIpMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APISetVmStaticIpMsg.java
@@ -5,6 +5,7 @@
import org.zstack.header.message.APIParam;
import org.zstack.header.network.l3.L3NetworkVO;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by frank on 2/26/2016.
@@ -15,6 +16,7 @@
method = HttpMethod.PUT,
responseClass = APISetVmStaticIpEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "vmInstanceUuid")
public class APISetVmStaticIpMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String vmInstanceUuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIUpdateVmInstanceMsg.java b/header/src/main/java/org/zstack/header/vm/APIUpdateVmInstanceMsg.java
index 60e9343ff38..d9b9d333198 100755
--- a/header/src/main/java/org/zstack/header/vm/APIUpdateVmInstanceMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIUpdateVmInstanceMsg.java
@@ -5,6 +5,7 @@
import org.zstack.header.message.APIParam;
import org.zstack.header.network.l3.L3NetworkVO;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by frank on 6/14/2015.
@@ -15,6 +16,7 @@
isAction = true,
responseClass = APIUpdateVmInstanceEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APIUpdateVmInstanceMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.java b/header/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.java
index de2fd27289c..1863f7c224e 100644
--- a/header/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* @ Author : yh.w
@@ -15,6 +16,7 @@
isAction = true,
responseClass = APIUpdateVmNicDriverEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "NicUuidToVmUuidResolver", field = "vmNicUuid")
public class APIUpdateVmNicDriverMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String vmInstanceUuid;
diff --git a/header/src/main/java/org/zstack/header/vm/APIUpdateVmPriorityMsg.java b/header/src/main/java/org/zstack/header/vm/APIUpdateVmPriorityMsg.java
index a8c6f821450..bab95b4fafa 100644
--- a/header/src/main/java/org/zstack/header/vm/APIUpdateVmPriorityMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/APIUpdateVmPriorityMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
@RestRequest(
path = "/vm-instances/{uuid}/actions",
@@ -11,6 +12,7 @@
isAction = true,
responseClass = APIUpdateVmPriorityEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid")
public class APIUpdateVmPriorityMsg extends APIMessage implements VmInstanceMessage {
@APIParam(resourceType = VmInstanceVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/VmInstanceState.java b/header/src/main/java/org/zstack/header/vm/VmInstanceState.java
index b71d8f3be45..8c63a79c443 100755
--- a/header/src/main/java/org/zstack/header/vm/VmInstanceState.java
+++ b/header/src/main/java/org/zstack/header/vm/VmInstanceState.java
@@ -30,7 +30,8 @@ public enum VmInstanceState {
Error(null),
NoState(VmInstanceStateEvent.noState),
Unknown(VmInstanceStateEvent.unknown),
- Crashed(VmInstanceStateEvent.crashed);
+ Crashed(VmInstanceStateEvent.crashed),
+ Registering(null);
public static List intermediateStates = new ArrayList<>();
@@ -52,6 +53,7 @@ public enum VmInstanceState {
offlineStates.add(Destroyed);
offlineStates.add(VolumeMigrating);
offlineStates.add(Crashed);
+ offlineStates.add(Registering);
Created.transactions(
new Transaction(VmInstanceStateEvent.starting, VmInstanceState.Starting),
@@ -189,6 +191,11 @@ public enum VmInstanceState {
new Transaction(VmInstanceStateEvent.noState, VmInstanceState.NoState),
new Transaction(VmInstanceStateEvent.destroying, VmInstanceState.Destroying)
);
+ Registering.transactions(
+ new Transaction(VmInstanceStateEvent.stopped, VmInstanceState.Stopped),
+ new Transaction(VmInstanceStateEvent.destroying, VmInstanceState.Destroying),
+ new Transaction(VmInstanceStateEvent.destroyed, VmInstanceState.Destroyed)
+ );
NoState.transactions(
new Transaction(VmInstanceStateEvent.running, VmInstanceState.Running),
new Transaction(VmInstanceStateEvent.unknown, VmInstanceState.Unknown),
diff --git a/header/src/main/java/org/zstack/header/vm/cdrom/APISetVmInstanceDefaultCdRomMsg.java b/header/src/main/java/org/zstack/header/vm/cdrom/APISetVmInstanceDefaultCdRomMsg.java
index f5f9b0afa76..0e1a8c93430 100644
--- a/header/src/main/java/org/zstack/header/vm/cdrom/APISetVmInstanceDefaultCdRomMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/cdrom/APISetVmInstanceDefaultCdRomMsg.java
@@ -8,6 +8,7 @@
import org.zstack.header.rest.RestRequest;
import org.zstack.header.vm.VmInstanceMessage;
import org.zstack.header.vm.VmInstanceVO;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Create by lining at 2018/12/29
@@ -18,6 +19,7 @@
isAction = true,
responseClass = APISetVmInstanceDefaultCdRomEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "vmInstanceUuid")
public class APISetVmInstanceDefaultCdRomMsg extends APIMessage implements VmInstanceMessage, APIAuditor {
@APIParam(resourceType = VmCdRomVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEvent.java b/header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEvent.java
new file mode 100644
index 00000000000..39313f598cb
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEvent.java
@@ -0,0 +1,53 @@
+package org.zstack.header.vm.metadata;
+
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.rest.RestResponse;
+
+import java.util.List;
+
+@RestResponse(fieldsTo = {"all"})
+public class APICleanupVmInstanceMetadataEvent extends APIEvent {
+ private Integer totalCleaned;
+ private Integer totalFailed;
+ private List failedVmUuids;
+
+ public APICleanupVmInstanceMetadataEvent() {
+ super(null);
+ }
+
+ public APICleanupVmInstanceMetadataEvent(String apiId) {
+ super(apiId);
+ }
+
+ public Integer getTotalCleaned() {
+ return totalCleaned;
+ }
+
+ public void setTotalCleaned(Integer totalCleaned) {
+ this.totalCleaned = totalCleaned;
+ }
+
+ public Integer getTotalFailed() {
+ return totalFailed;
+ }
+
+ public void setTotalFailed(Integer totalFailed) {
+ this.totalFailed = totalFailed;
+ }
+
+ public List getFailedVmUuids() {
+ return failedVmUuids;
+ }
+
+ public void setFailedVmUuids(List failedVmUuids) {
+ this.failedVmUuids = failedVmUuids;
+ }
+
+ public static APICleanupVmInstanceMetadataEvent __example__() {
+ APICleanupVmInstanceMetadataEvent evt = new APICleanupVmInstanceMetadataEvent();
+ evt.totalCleaned = 5;
+ evt.totalFailed = 0;
+ evt.failedVmUuids = java.util.Collections.emptyList();
+ return evt;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEventDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEventDoc_zh_cn.groovy
new file mode 100644
index 00000000000..3a3c398dde0
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEventDoc_zh_cn.groovy
@@ -0,0 +1,42 @@
+package org.zstack.header.vm.metadata
+
+import java.lang.Integer
+import org.zstack.header.errorcode.ErrorCode
+
+doc {
+
+ title "清理云主机元数据返回"
+
+ field {
+ name "totalCleaned"
+ desc "成功清理的元数据数量"
+ type "Integer"
+ since "5.0.0"
+ }
+ field {
+ name "totalFailed"
+ desc "清理失败的元数据数量"
+ type "Integer"
+ since "5.0.0"
+ }
+ field {
+ name "failedVmUuids"
+ desc "清理失败的云主机UUID列表"
+ type "List"
+ since "5.0.0"
+ }
+ field {
+ name "success"
+ desc "操作是否成功"
+ type "boolean"
+ since "5.0.0"
+ }
+ ref {
+ name "error"
+ path "org.zstack.header.vm.metadata.APICleanupVmInstanceMetadataEvent.error"
+ desc "错误码,若不为null,则表示操作失败, 操作成功时该字段为null"
+ type "ErrorCode"
+ since "5.0.0"
+ clz ErrorCode.class
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsg.java b/header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsg.java
new file mode 100644
index 00000000000..5823f66b78f
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsg.java
@@ -0,0 +1,34 @@
+package org.zstack.header.vm.metadata;
+
+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.vm.VmInstanceVO;
+
+import java.util.List;
+
+@RestRequest(
+ path = "/vm-instances/metadata/cleanup",
+ method = HttpMethod.PUT,
+ responseClass = APICleanupVmInstanceMetadataEvent.class,
+ isAction = true
+)
+public class APICleanupVmInstanceMetadataMsg extends APIMessage {
+ @APIParam(resourceType = VmInstanceVO.class, nonempty = true)
+ private List vmUuids;
+
+ public List getVmUuids() {
+ return vmUuids;
+ }
+
+ public void setVmUuids(List vmUuids) {
+ this.vmUuids = vmUuids;
+ }
+
+ public static APICleanupVmInstanceMetadataMsg __example__() {
+ APICleanupVmInstanceMetadataMsg msg = new APICleanupVmInstanceMetadataMsg();
+ msg.vmUuids = java.util.Arrays.asList(uuid(), uuid());
+ return msg;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsgDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsgDoc_zh_cn.groovy
new file mode 100644
index 00000000000..0c29f0d6106
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsgDoc_zh_cn.groovy
@@ -0,0 +1,58 @@
+package org.zstack.header.vm.metadata
+
+import org.zstack.header.vm.metadata.APICleanupVmInstanceMetadataEvent
+
+doc {
+ title "清理云主机元数据"
+
+ category "云主机"
+
+ desc """清理指定云主机在主存储上的元数据文件"""
+
+ rest {
+ request {
+ url "PUT /v1/vm-instances/metadata/cleanup"
+
+ header (Authorization: 'OAuth the-session-uuid')
+
+ clz APICleanupVmInstanceMetadataMsg.class
+
+ desc """"""
+
+ params {
+
+ column {
+ name "vmUuids"
+ enclosedIn "cleanupVmInstanceMetadata"
+ desc "需要清理元数据的云主机UUID列表"
+ location "body"
+ type "List"
+ 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 APICleanupVmInstanceMetadataEvent.class
+ }
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEvent.java b/header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEvent.java
new file mode 100644
index 00000000000..6dded8354a1
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEvent.java
@@ -0,0 +1,30 @@
+package org.zstack.header.vm.metadata;
+
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.rest.RestResponse;
+
+@RestResponse(fieldsTo = {"all"})
+public class APIGetVmInstanceMetadataFromPrimaryStorageEvent extends APIEvent {
+ private String metadata;
+
+ public APIGetVmInstanceMetadataFromPrimaryStorageEvent() {
+ super(null);
+ }
+
+ public APIGetVmInstanceMetadataFromPrimaryStorageEvent(String apiId) {
+ super(apiId);
+ }
+
+ public String getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(String metadata) {
+ this.metadata = metadata;
+ }
+
+ public static APIGetVmInstanceMetadataFromPrimaryStorageEvent __example__() {
+ APIGetVmInstanceMetadataFromPrimaryStorageEvent evt = new APIGetVmInstanceMetadataFromPrimaryStorageEvent();
+ return evt;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEventDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEventDoc_zh_cn.groovy
new file mode 100644
index 00000000000..2944ee0ed4f
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEventDoc_zh_cn.groovy
@@ -0,0 +1,29 @@
+package org.zstack.header.vm.metadata
+
+import org.zstack.header.errorcode.ErrorCode
+
+doc {
+
+ title "获取云主机元数据返回"
+
+ field {
+ name "metadata"
+ desc "云主机元数据内容"
+ type "String"
+ since "5.0.0"
+ }
+ field {
+ name "success"
+ desc "操作是否成功"
+ type "boolean"
+ since "5.0.0"
+ }
+ ref {
+ name "error"
+ path "org.zstack.header.vm.metadata.APIGetVmInstanceMetadataFromPrimaryStorageEvent.error"
+ desc "错误码,若不为null,则表示操作失败, 操作成功时该字段为null"
+ type "ErrorCode"
+ since "5.0.0"
+ clz ErrorCode.class
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsg.java b/header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsg.java
new file mode 100644
index 00000000000..5b4c46853a9
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsg.java
@@ -0,0 +1,37 @@
+package org.zstack.header.vm.metadata;
+
+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.vm.VmInstanceMessage;
+import org.zstack.header.vm.VmInstanceVO;
+
+@RestRequest(
+ path = "/primary-storage/vm-instances/metadata",
+ method = HttpMethod.GET,
+ responseClass = APIGetVmInstanceMetadataFromPrimaryStorageEvent.class
+)
+public class APIGetVmInstanceMetadataFromPrimaryStorageMsg extends APIMessage implements VmInstanceMessage {
+ @APIParam(resourceType = VmInstanceVO.class)
+ private String uuid;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ @Override
+ public String getVmInstanceUuid() {
+ return uuid;
+ }
+
+ public static APIGetVmInstanceMetadataFromPrimaryStorageMsg __example__() {
+ APIGetVmInstanceMetadataFromPrimaryStorageMsg msg = new APIGetVmInstanceMetadataFromPrimaryStorageMsg();
+ msg.setUuid(uuid(VmInstanceVO.class));
+ return msg;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy
new file mode 100644
index 00000000000..d20565dd003
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy
@@ -0,0 +1,58 @@
+package org.zstack.header.vm.metadata
+
+import org.zstack.header.vm.metadata.APIGetVmInstanceMetadataFromPrimaryStorageEvent
+
+doc {
+ title "获取云主机元数据"
+
+ category "主存储"
+
+ desc """从主存储获取指定云主机的元数据内容"""
+
+ rest {
+ request {
+ url "GET /v1/primary-storage/vm-instances/metadata"
+
+ header (Authorization: 'OAuth the-session-uuid')
+
+ clz APIGetVmInstanceMetadataFromPrimaryStorageMsg.class
+
+ desc """"""
+
+ params {
+
+ column {
+ name "uuid"
+ enclosedIn ""
+ desc "云主机UUID"
+ location "query"
+ type "String"
+ optional false
+ 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 APIGetVmInstanceMetadataFromPrimaryStorageEvent.class
+ }
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEvent.java b/header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEvent.java
new file mode 100644
index 00000000000..b1dc83a0c3b
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEvent.java
@@ -0,0 +1,35 @@
+package org.zstack.header.vm.metadata;
+
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.rest.RestResponse;
+import org.zstack.header.vm.VmInstanceInventory;
+
+@RestResponse(fieldsTo = {"all"})
+public class APIRegisterVmInstanceFromMetadataEvent extends APIEvent {
+ private VmInstanceInventory inventory;
+
+ public APIRegisterVmInstanceFromMetadataEvent() {
+ super(null);
+ }
+
+ public APIRegisterVmInstanceFromMetadataEvent(String apiId) {
+ super(apiId);
+ }
+
+ public VmInstanceInventory getInventory() {
+ return inventory;
+ }
+
+ public void setInventory(VmInstanceInventory inventory) {
+ this.inventory = inventory;
+ }
+
+ public static APIRegisterVmInstanceFromMetadataEvent __example__() {
+ APIRegisterVmInstanceFromMetadataEvent evt = new APIRegisterVmInstanceFromMetadataEvent();
+ VmInstanceInventory vm = new VmInstanceInventory();
+ vm.setUuid(uuid());
+ vm.setName("recovered-vm");
+ evt.setInventory(vm);
+ return evt;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEventDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEventDoc_zh_cn.groovy
new file mode 100644
index 00000000000..e4f286b8ddc
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEventDoc_zh_cn.groovy
@@ -0,0 +1,32 @@
+package org.zstack.header.vm.metadata
+
+import org.zstack.header.vm.VmInstanceInventory
+import org.zstack.header.errorcode.ErrorCode
+
+doc {
+
+ title "从元数据注册云主机返回"
+
+ ref {
+ name "inventory"
+ path "org.zstack.header.vm.metadata.APIRegisterVmInstanceFromMetadataEvent.inventory"
+ desc "云主机详情"
+ type "VmInstanceInventory"
+ since "5.0.0"
+ clz VmInstanceInventory.class
+ }
+ field {
+ name "success"
+ desc "操作是否成功"
+ type "boolean"
+ since "5.0.0"
+ }
+ ref {
+ name "error"
+ path "org.zstack.header.vm.metadata.APIRegisterVmInstanceFromMetadataEvent.error"
+ desc "错误码,若不为null,则表示操作失败, 操作成功时该字段为null"
+ type "ErrorCode"
+ since "5.0.0"
+ clz ErrorCode.class
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsg.java b/header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsg.java
new file mode 100644
index 00000000000..ec862f4d3c7
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsg.java
@@ -0,0 +1,102 @@
+package org.zstack.header.vm.metadata;
+
+import org.springframework.http.HttpMethod;
+import org.zstack.header.message.APIMessage;
+import org.zstack.header.message.APIParam;
+import org.zstack.header.message.DefaultTimeout;
+import org.zstack.header.rest.RestRequest;
+import org.zstack.header.storage.primary.PrimaryStorageVO;
+import org.zstack.header.vm.VmInstanceVO;
+import org.zstack.header.zone.ZoneVO;
+import org.zstack.header.cluster.ClusterVO;
+import org.zstack.header.host.HostVO;
+import org.zstack.header.tag.TagResourceType;
+
+import java.util.concurrent.TimeUnit;
+
+@TagResourceType(VmInstanceVO.class)
+@RestRequest(
+ path = "/vm-instances/metadata/register",
+ method = HttpMethod.POST,
+ responseClass = APIRegisterVmInstanceFromMetadataEvent.class,
+ parameterName = "params"
+)
+@DefaultTimeout(timeunit = TimeUnit.HOURS, value = 1)
+public class APIRegisterVmInstanceFromMetadataMsg extends APIMessage {
+ @APIParam(nonempty = true, maxLength = 2048)
+ private String metadataPath;
+
+ @APIParam(resourceType = PrimaryStorageVO.class)
+ private String primaryStorageUuid;
+
+ @APIParam(resourceType = ZoneVO.class)
+ private String zoneUuid;
+
+ @APIParam(resourceType = ClusterVO.class)
+ private String clusterUuid;
+
+ @APIParam(resourceType = HostVO.class)
+ private String hostUuid;
+
+ @APIParam(required = false, maxLength = 255)
+ private String name;
+
+ public String getMetadataPath() {
+ return metadataPath;
+ }
+
+ public void setMetadataPath(String metadataPath) {
+ this.metadataPath = metadataPath;
+ }
+
+ public String getPrimaryStorageUuid() {
+ return primaryStorageUuid;
+ }
+
+ public void setPrimaryStorageUuid(String primaryStorageUuid) {
+ this.primaryStorageUuid = primaryStorageUuid;
+ }
+
+ public String getZoneUuid() {
+ return zoneUuid;
+ }
+
+ public void setZoneUuid(String zoneUuid) {
+ this.zoneUuid = zoneUuid;
+ }
+
+ public String getClusterUuid() {
+ return clusterUuid;
+ }
+
+ public void setClusterUuid(String clusterUuid) {
+ this.clusterUuid = clusterUuid;
+ }
+
+ public String getHostUuid() {
+ return hostUuid;
+ }
+
+ public void setHostUuid(String hostUuid) {
+ this.hostUuid = hostUuid;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public static APIRegisterVmInstanceFromMetadataMsg __example__() {
+ APIRegisterVmInstanceFromMetadataMsg msg = new APIRegisterVmInstanceFromMetadataMsg();
+ msg.metadataPath = "/mnt/ps/vm-metadata/vm-uuid.vmmeta";
+ msg.primaryStorageUuid = uuid(PrimaryStorageVO.class);
+ msg.zoneUuid = uuid(ZoneVO.class);
+ msg.clusterUuid = uuid(ClusterVO.class);
+ msg.hostUuid = uuid(HostVO.class);
+ msg.name = "my-restored-vm";
+ return msg;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsgDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsgDoc_zh_cn.groovy
new file mode 100644
index 00000000000..8e604678819
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsgDoc_zh_cn.groovy
@@ -0,0 +1,112 @@
+package org.zstack.header.vm.metadata
+
+import org.zstack.header.vm.metadata.APIRegisterVmInstanceFromMetadataEvent
+
+doc {
+ title "从元数据注册云主机(RegisterVmInstanceFromMetadata)"
+
+ category "云主机"
+
+ desc """根据主存储上的元数据文件注册(恢复)一台云主机"""
+
+ rest {
+ request {
+ url "POST /v1/vm-instances/metadata/register"
+
+ header (Authorization: 'OAuth the-session-uuid')
+
+ clz APIRegisterVmInstanceFromMetadataMsg.class
+
+ desc """"""
+
+ params {
+
+ column {
+ name "metadataPath"
+ enclosedIn "params"
+ desc "元数据文件在主存储上的路径"
+ location "body"
+ type "String"
+ optional false
+ since "5.0.0"
+ }
+ column {
+ name "primaryStorageUuid"
+ enclosedIn "params"
+ desc "目标主存储UUID"
+ location "body"
+ type "String"
+ optional false
+ since "5.0.0"
+ }
+ column {
+ name "zoneUuid"
+ enclosedIn "params"
+ desc "区域UUID"
+ location "body"
+ type "String"
+ optional false
+ since "5.0.0"
+ }
+ column {
+ name "clusterUuid"
+ enclosedIn "params"
+ desc "集群UUID"
+ location "body"
+ type "String"
+ optional false
+ since "5.0.0"
+ }
+ column {
+ name "hostUuid"
+ enclosedIn "params"
+ desc "物理机UUID"
+ location "body"
+ type "String"
+ optional false
+ since "5.0.0"
+ }
+ column {
+ name "name"
+ enclosedIn "params"
+ desc "云主机名称"
+ location "body"
+ type "String"
+ optional true
+ since "5.0.0"
+ }
+ column {
+ name "tagUuids"
+ enclosedIn "params"
+ desc "标签UUID列表"
+ location "body"
+ type "List"
+ optional true
+ 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 APIRegisterVmInstanceFromMetadataEvent.class
+ }
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEvent.java b/header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEvent.java
new file mode 100644
index 00000000000..897f3a0ef4e
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEvent.java
@@ -0,0 +1,19 @@
+package org.zstack.header.vm.metadata;
+
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.rest.RestResponse;
+
+@RestResponse(fieldsTo = {"all"})
+public class APIUpdateVmInstanceMetadataEvent extends APIEvent {
+ public APIUpdateVmInstanceMetadataEvent() {
+ super(null);
+ }
+
+ public APIUpdateVmInstanceMetadataEvent(String apiId) {
+ super(apiId);
+ }
+
+ public static APIUpdateVmInstanceMetadataEvent __example__() {
+ return new APIUpdateVmInstanceMetadataEvent();
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEventDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEventDoc_zh_cn.groovy
new file mode 100644
index 00000000000..e6d90be232e
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEventDoc_zh_cn.groovy
@@ -0,0 +1,23 @@
+package org.zstack.header.vm.metadata
+
+import org.zstack.header.errorcode.ErrorCode
+
+doc {
+
+ title "更新云主机元数据返回"
+
+ field {
+ name "success"
+ desc "操作是否成功"
+ type "boolean"
+ since "5.0.0"
+ }
+ ref {
+ name "error"
+ path "org.zstack.header.vm.metadata.APIUpdateVmInstanceMetadataEvent.error"
+ desc "错误码,若不为null,则表示操作失败, 操作成功时该字段为null"
+ type "ErrorCode"
+ since "5.0.0"
+ clz ErrorCode.class
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsg.java b/header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsg.java
new file mode 100644
index 00000000000..46e529b4fbd
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsg.java
@@ -0,0 +1,35 @@
+package org.zstack.header.vm.metadata;
+
+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.vm.VmInstanceVO;
+
+import java.util.Collections;
+import java.util.List;
+
+@RestRequest(
+ path = "/vm-instances/metadata/actions",
+ method = HttpMethod.PUT,
+ responseClass = APIUpdateVmInstanceMetadataEvent.class,
+ isAction = true
+)
+public class APIUpdateVmInstanceMetadataMsg extends APIMessage {
+ @APIParam(resourceType = VmInstanceVO.class, nonempty = true)
+ private List vmUuids;
+
+ public List getVmUuids() {
+ return vmUuids;
+ }
+
+ public void setVmUuids(List vmUuids) {
+ this.vmUuids = vmUuids;
+ }
+
+ public static APIUpdateVmInstanceMetadataMsg __example__() {
+ APIUpdateVmInstanceMetadataMsg msg = new APIUpdateVmInstanceMetadataMsg();
+ msg.vmUuids = Collections.singletonList(uuid());
+ return msg;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsgDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsgDoc_zh_cn.groovy
new file mode 100644
index 00000000000..04330f73fe3
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsgDoc_zh_cn.groovy
@@ -0,0 +1,58 @@
+package org.zstack.header.vm.metadata
+
+import org.zstack.header.vm.metadata.APIUpdateVmInstanceMetadataEvent
+
+doc {
+ title "更新云主机元数据"
+
+ category "云主机"
+
+ desc """立即触发指定云主机的元数据更新"""
+
+ rest {
+ request {
+ url "PUT /v1/vm-instances/metadata/actions"
+
+ header (Authorization: 'OAuth the-session-uuid')
+
+ clz APIUpdateVmInstanceMetadataMsg.class
+
+ desc """"""
+
+ params {
+
+ column {
+ name "vmUuids"
+ enclosedIn "updateVmInstanceMetadata"
+ desc "需要更新元数据的云主机UUID列表"
+ location "body"
+ type "List"
+ 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 APIUpdateVmInstanceMetadataEvent.class
+ }
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/MetadataImpact.java b/header/src/main/java/org/zstack/header/vm/metadata/MetadataImpact.java
new file mode 100644
index 00000000000..198156c7259
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/MetadataImpact.java
@@ -0,0 +1,39 @@
+package org.zstack.header.vm.metadata;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface MetadataImpact {
+ Impact value();
+
+ /**
+ * Spring bean name of the {@link VmUuidFromApiResolver} that converts the
+ * field value(s) into VM UUID(s).
+ *
+ * Must be specified for {@link Impact#CONFIG} and {@link Impact#STORAGE};
+ * ignored for {@link Impact#NONE}.
+ */
+ String resolver() default "";
+
+ /**
+ * The field name in the API message whose value will be extracted (via getter
+ * reflection) and passed to the resolver.
+ *
+ * For example, {@code field = "volumeUuid"} means the interceptor will call
+ * {@code msg.getVolumeUuid()} and pass the result to
+ * {@link VmUuidFromApiResolver#resolveVmUuids(String)}.
+ *
+ * The field value may be a {@code String} or {@code List}.
+ */
+ String field() default "";
+
+ boolean updateOnFailure() default false;
+
+ enum Impact {
+ NONE,
+ CONFIG,
+ STORAGE
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/ResourceMetadata.java b/header/src/main/java/org/zstack/header/vm/metadata/ResourceMetadata.java
new file mode 100644
index 00000000000..e450d65f3f6
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/ResourceMetadata.java
@@ -0,0 +1,40 @@
+package org.zstack.header.vm.metadata;
+
+public class ResourceMetadata {
+ private String resourceUuid;
+ private String vo;
+ private String systemTags;
+ private String resourceConfigs;
+
+ public String getResourceUuid() {
+ return resourceUuid;
+ }
+
+ public void setResourceUuid(String resourceUuid) {
+ this.resourceUuid = resourceUuid;
+ }
+
+ public String getVo() {
+ return vo;
+ }
+
+ public void setVo(String vo) {
+ this.vo = vo;
+ }
+
+ public String getSystemTags() {
+ return systemTags;
+ }
+
+ public void setSystemTags(String systemTags) {
+ this.systemTags = systemTags;
+ }
+
+ public String getResourceConfigs() {
+ return resourceConfigs;
+ }
+
+ public void setResourceConfigs(String resourceConfigs) {
+ this.resourceConfigs = resourceConfigs;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataMsg.java b/header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataMsg.java
new file mode 100644
index 00000000000..bf3956f41fc
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataMsg.java
@@ -0,0 +1,26 @@
+package org.zstack.header.vm.metadata;
+
+import org.zstack.header.message.NeedReplyMessage;
+import org.zstack.header.vm.VmInstanceMessage;
+
+public class UpdateVmInstanceMetadataMsg extends NeedReplyMessage implements VmInstanceMessage {
+ private String vmInstanceUuid;
+ private boolean storageStructureChange;
+
+ @Override
+ public String getVmInstanceUuid() {
+ return vmInstanceUuid;
+ }
+
+ public void setVmInstanceUuid(String vmInstanceUuid) {
+ this.vmInstanceUuid = vmInstanceUuid;
+ }
+
+ public boolean isStorageStructureChange() {
+ return storageStructureChange;
+ }
+
+ public void setStorageStructureChange(boolean storageStructureChange) {
+ this.storageStructureChange = storageStructureChange;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageMsg.java b/header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageMsg.java
new file mode 100644
index 00000000000..ba12e4b918e
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageMsg.java
@@ -0,0 +1,98 @@
+package org.zstack.header.vm.metadata;
+
+import org.zstack.header.message.NeedReplyMessage;
+import org.zstack.header.storage.primary.PrimaryStorageMessage;
+
+public class UpdateVmInstanceMetadataOnPrimaryStorageMsg extends NeedReplyMessage implements PrimaryStorageMessage {
+ private String primaryStorageUuid;
+ private String vmInstanceUuid;
+ private String rootVolumeUuid;
+ private String vmInstanceName;
+ private String vmCategory;
+ private String architecture;
+ private String metadata;
+ private String schemaVersion;
+ private boolean storageStructureChange;
+ private String metadataPath;
+
+ @Override
+ public String getPrimaryStorageUuid() {
+ return primaryStorageUuid;
+ }
+
+ public void setPrimaryStorageUuid(String primaryStorageUuid) {
+ this.primaryStorageUuid = primaryStorageUuid;
+ }
+
+ public String getVmInstanceUuid() {
+ return vmInstanceUuid;
+ }
+
+ public void setVmInstanceUuid(String vmInstanceUuid) {
+ this.vmInstanceUuid = vmInstanceUuid;
+ }
+
+ public String getRootVolumeUuid() {
+ return rootVolumeUuid;
+ }
+
+ public void setRootVolumeUuid(String rootVolumeUuid) {
+ this.rootVolumeUuid = rootVolumeUuid;
+ }
+
+ public String getVmInstanceName() {
+ return vmInstanceName;
+ }
+
+ public void setVmInstanceName(String vmInstanceName) {
+ this.vmInstanceName = vmInstanceName;
+ }
+
+ public String getVmCategory() {
+ return vmCategory;
+ }
+
+ public void setVmCategory(String vmCategory) {
+ this.vmCategory = vmCategory;
+ }
+
+ public String getArchitecture() {
+ return architecture;
+ }
+
+ public void setArchitecture(String architecture) {
+ this.architecture = architecture;
+ }
+
+ public String getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(String metadata) {
+ this.metadata = metadata;
+ }
+
+ public String getSchemaVersion() {
+ return schemaVersion;
+ }
+
+ public void setSchemaVersion(String schemaVersion) {
+ this.schemaVersion = schemaVersion;
+ }
+
+ public boolean isStorageStructureChange() {
+ return storageStructureChange;
+ }
+
+ public void setStorageStructureChange(boolean storageStructureChange) {
+ this.storageStructureChange = storageStructureChange;
+ }
+
+ public String getMetadataPath() {
+ return metadataPath;
+ }
+
+ public void setMetadataPath(String metadataPath) {
+ this.metadataPath = metadataPath;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageReply.java b/header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageReply.java
new file mode 100644
index 00000000000..d8323171909
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageReply.java
@@ -0,0 +1,6 @@
+package org.zstack.header.vm.metadata;
+
+import org.zstack.header.message.MessageReply;
+
+public class UpdateVmInstanceMetadataOnPrimaryStorageReply extends MessageReply {
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataReply.java b/header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataReply.java
new file mode 100644
index 00000000000..98296a42b3c
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataReply.java
@@ -0,0 +1,15 @@
+package org.zstack.header.vm.metadata;
+
+import org.zstack.header.message.MessageReply;
+
+public class UpdateVmInstanceMetadataReply extends MessageReply {
+ private String metadata;
+
+ public String getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(String metadata) {
+ this.metadata = metadata;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataConstants.java b/header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataConstants.java
new file mode 100644
index 00000000000..a47f05e0157
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataConstants.java
@@ -0,0 +1,27 @@
+package org.zstack.header.vm.metadata;
+
+public class VmInstanceMetadataConstants {
+ private VmInstanceMetadataConstants() {
+ }
+
+ public static final String SBLK_METADATA_LV_SUFFIX = "_vmmeta";
+ public static final String FILE_METADATA_SUFFIX = ".vmmeta";
+ public static final String METADATA_DIR_NAME = "vm-metadata";
+
+ private static final String[] STORAGE_PATH_MARKERS = {
+ "/rootVolumes/", "/dataVolumes/", "/volumeSnapshots/", "/memory/"
+ };
+
+ public static String extractOldPrefix(String path) {
+ if (path == null || !path.startsWith("/")) {
+ return null;
+ }
+ for (String marker : STORAGE_PATH_MARKERS) {
+ int idx = path.indexOf(marker);
+ if (idx >= 0) {
+ return path.substring(0, idx + 1);
+ }
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataDTO.java b/header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataDTO.java
new file mode 100644
index 00000000000..311ddbde784
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataDTO.java
@@ -0,0 +1,78 @@
+package org.zstack.header.vm.metadata;
+
+import java.util.List;
+
+public class VmInstanceMetadataDTO {
+ private String schemaVersion;
+ private VmMetadataCategory vmCategory;
+ private ResourceMetadata vm;
+ private List volumes;
+ private List nics;
+ private List snapshots;
+ private List snapshotGroups;
+ private List snapshotGroupRefs;
+
+ public String getSchemaVersion() {
+ return schemaVersion;
+ }
+
+ public void setSchemaVersion(String schemaVersion) {
+ this.schemaVersion = schemaVersion;
+ }
+
+ public VmMetadataCategory getVmCategory() {
+ return vmCategory;
+ }
+
+ public void setVmCategory(VmMetadataCategory vmCategory) {
+ this.vmCategory = vmCategory;
+ }
+
+ public ResourceMetadata getVm() {
+ return vm;
+ }
+
+ public void setVm(ResourceMetadata vm) {
+ this.vm = vm;
+ }
+
+ public List getVolumes() {
+ return volumes;
+ }
+
+ public void setVolumes(List volumes) {
+ this.volumes = volumes;
+ }
+
+ public List getNics() {
+ return nics;
+ }
+
+ public void setNics(List nics) {
+ this.nics = nics;
+ }
+
+ public List getSnapshots() {
+ return snapshots;
+ }
+
+ public void setSnapshots(List snapshots) {
+ this.snapshots = snapshots;
+ }
+
+ public List getSnapshotGroups() {
+ return snapshotGroups;
+ }
+
+ public void setSnapshotGroups(List snapshotGroups) {
+ this.snapshotGroups = snapshotGroups;
+ }
+
+ public List getSnapshotGroupRefs() {
+ return snapshotGroupRefs;
+ }
+
+ public void setSnapshotGroupRefs(List snapshotGroupRefs) {
+ this.snapshotGroupRefs = snapshotGroupRefs;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataCategory.java b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataCategory.java
new file mode 100644
index 00000000000..a2a09028d27
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataCategory.java
@@ -0,0 +1,7 @@
+package org.zstack.header.vm.metadata;
+
+public enum VmMetadataCategory {
+ VM,
+ VM_TEMPLATE,
+ VM_TEMPLATE_CACHE
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyService.java b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyService.java
new file mode 100644
index 00000000000..ff17ffcf7f4
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyService.java
@@ -0,0 +1,29 @@
+package org.zstack.header.vm.metadata;
+
+/**
+ * Service interface for marking VM metadata as dirty.
+ *
+ * Implementations live in the premium module (VmMetadataDirtyMarker).
+ * The zstack core module uses this interface via {@code @Autowired(required = false)}
+ * so that the feature degrades gracefully when the premium module is not loaded.
+ */
+public interface VmMetadataDirtyService {
+ /**
+ * Mark the VM's metadata as dirty so that it will be flushed
+ * to primary storage on the next poll cycle.
+ *
+ * @param vmInstanceUuid the VM whose metadata changed
+ * @return true if the mark was actually written (feature enabled), false otherwise
+ */
+ boolean markDirty(String vmInstanceUuid);
+
+ /**
+ * Mark the VM's metadata as dirty, optionally flagging a storage-structure change
+ * (e.g. volume attach/detach, snapshot, migration).
+ *
+ * @param vmInstanceUuid the VM whose metadata changed
+ * @param storageStructureChange true if the change affects storage topology
+ * @return true if the mark was actually written (feature enabled), false otherwise
+ */
+ boolean markDirty(String vmInstanceUuid, boolean storageStructureChange);
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO.java b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO.java
new file mode 100644
index 00000000000..f313699b82d
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO.java
@@ -0,0 +1,121 @@
+package org.zstack.header.vm.metadata;
+
+import org.zstack.header.managementnode.ManagementNodeVO;
+import org.zstack.header.vm.VmInstanceEO;
+import org.zstack.header.vm.VmInstanceVO;
+import org.zstack.header.vo.ForeignKey;
+import org.zstack.header.vo.ForeignKey.ReferenceOption;
+
+import javax.persistence.*;
+import java.sql.Timestamp;
+
+@Entity
+@Table
+public class VmMetadataDirtyVO {
+ @Id
+ @Column
+ @ForeignKey(parentEntityClass = VmInstanceEO.class, onDeleteAction = ReferenceOption.CASCADE)
+ private String vmInstanceUuid;
+
+ @Column
+ @ForeignKey(parentEntityClass = ManagementNodeVO.class, onDeleteAction = ReferenceOption.SET_NULL)
+ private String managementNodeUuid;
+
+ @Column
+ private long dirtyVersion;
+
+ @Column
+ private Timestamp lastClaimTime;
+
+ @Column
+ private boolean storageStructureChange;
+
+ @Column
+ private int retryCount;
+
+ @Column
+ private Timestamp nextRetryTime;
+
+ @Column
+ private Timestamp createDate;
+
+ @Column
+ private Timestamp lastOpDate;
+
+ @PreUpdate
+ private void preUpdate() {
+ lastOpDate = null;
+ }
+
+ public String getVmInstanceUuid() {
+ return vmInstanceUuid;
+ }
+
+ public void setVmInstanceUuid(String vmInstanceUuid) {
+ this.vmInstanceUuid = vmInstanceUuid;
+ }
+
+ public String getManagementNodeUuid() {
+ return managementNodeUuid;
+ }
+
+ public void setManagementNodeUuid(String managementNodeUuid) {
+ this.managementNodeUuid = managementNodeUuid;
+ }
+
+ public long getDirtyVersion() {
+ return dirtyVersion;
+ }
+
+ public void setDirtyVersion(long dirtyVersion) {
+ this.dirtyVersion = dirtyVersion;
+ }
+
+ public Timestamp getLastClaimTime() {
+ return lastClaimTime;
+ }
+
+ public void setLastClaimTime(Timestamp lastClaimTime) {
+ this.lastClaimTime = lastClaimTime;
+ }
+
+ public boolean isStorageStructureChange() {
+ return storageStructureChange;
+ }
+
+ public void setStorageStructureChange(boolean storageStructureChange) {
+ this.storageStructureChange = storageStructureChange;
+ }
+
+ public int getRetryCount() {
+ return retryCount;
+ }
+
+ public void setRetryCount(int retryCount) {
+ this.retryCount = retryCount;
+ }
+
+ public Timestamp getNextRetryTime() {
+ return nextRetryTime;
+ }
+
+ public void setNextRetryTime(Timestamp nextRetryTime) {
+ this.nextRetryTime = nextRetryTime;
+ }
+
+ public Timestamp getCreateDate() {
+ return createDate;
+ }
+
+ public void setCreateDate(Timestamp createDate) {
+ this.createDate = createDate;
+ }
+
+ public Timestamp getLastOpDate() {
+ return lastOpDate;
+ }
+
+ public void setLastOpDate(Timestamp lastOpDate) {
+ this.lastOpDate = lastOpDate;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO_.java b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO_.java
new file mode 100644
index 00000000000..059ff6ad20f
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO_.java
@@ -0,0 +1,18 @@
+package org.zstack.header.vm.metadata;
+
+import javax.persistence.metamodel.SingularAttribute;
+import javax.persistence.metamodel.StaticMetamodel;
+import java.sql.Timestamp;
+
+@StaticMetamodel(VmMetadataDirtyVO.class)
+public class VmMetadataDirtyVO_ {
+ public static volatile SingularAttribute vmInstanceUuid;
+ public static volatile SingularAttribute managementNodeUuid;
+ public static volatile SingularAttribute dirtyVersion;
+ public static volatile SingularAttribute storageStructureChange;
+ public static volatile SingularAttribute retryCount;
+ public static volatile SingularAttribute nextRetryTime;
+ public static volatile SingularAttribute lastClaimTime;
+ public static volatile SingularAttribute createDate;
+ public static volatile SingularAttribute lastOpDate;
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataErrors.java b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataErrors.java
new file mode 100644
index 00000000000..f06ad8362dd
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataErrors.java
@@ -0,0 +1,28 @@
+package org.zstack.header.vm.metadata;
+
+public enum VmMetadataErrors {
+ METADATA_INVALID_FORMAT(1300),
+ METADATA_SCHEMA_VERSION_MISMATCH(1301),
+ METADATA_UUID_CONFLICT(1302),
+ METADATA_STORAGE_NOT_SUPPORTED(1303),
+ METADATA_CROSS_STORAGE_FORBIDDEN(1304),
+ METADATA_INSTALL_PATH_NOT_FOUND(1305),
+ METADATA_CACHE_VM_NOT_REGISTERABLE(1306),
+ METADATA_VM_REGISTERING(1307),
+ METADATA_READ_CORRUPTED(1308),
+ METADATA_PAYLOAD_TOO_LARGE(1309),
+ METADATA_PS_UNREACHABLE(1310),
+ METADATA_FEATURE_DISABLED(1311),
+ ;
+
+ private String code;
+
+ private VmMetadataErrors(int id) {
+ code = String.format("VM_METADATA.%s", id);
+ }
+
+ @Override
+ public String toString() {
+ return code;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO.java b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO.java
new file mode 100644
index 00000000000..dba4fae3e71
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO.java
@@ -0,0 +1,97 @@
+package org.zstack.header.vm.metadata;
+
+import org.zstack.header.vm.VmInstanceEO;
+import org.zstack.header.vo.ForeignKey;
+import org.zstack.header.vo.ForeignKey.ReferenceOption;
+
+import javax.persistence.*;
+import java.sql.Timestamp;
+
+@Entity
+@Table
+public class VmMetadataFingerprintVO {
+ @Id
+ @Column
+ @ForeignKey(parentEntityClass = VmInstanceEO.class, onDeleteAction = ReferenceOption.CASCADE)
+ private String vmInstanceUuid;
+
+ @Column
+ private Timestamp lastFlushTime;
+
+ @Column
+ private boolean lastFlushFailed;
+
+ @Column
+ private int staleRecoveryCount;
+
+ @Column
+ @Lob
+ private String metadataSnapshot;
+
+ @Column
+ private Timestamp createDate;
+
+ @Column
+ private Timestamp lastOpDate;
+
+ @PreUpdate
+ private void preUpdate() {
+ lastOpDate = null;
+ }
+
+ public String getVmInstanceUuid() {
+ return vmInstanceUuid;
+ }
+
+ public void setVmInstanceUuid(String vmInstanceUuid) {
+ this.vmInstanceUuid = vmInstanceUuid;
+ }
+
+ public Timestamp getLastFlushTime() {
+ return lastFlushTime;
+ }
+
+ public void setLastFlushTime(Timestamp lastFlushTime) {
+ this.lastFlushTime = lastFlushTime;
+ }
+
+ public boolean isLastFlushFailed() {
+ return lastFlushFailed;
+ }
+
+ public void setLastFlushFailed(boolean lastFlushFailed) {
+ this.lastFlushFailed = lastFlushFailed;
+ }
+
+ public int getStaleRecoveryCount() {
+ return staleRecoveryCount;
+ }
+
+ public void setStaleRecoveryCount(int staleRecoveryCount) {
+ this.staleRecoveryCount = staleRecoveryCount;
+ }
+
+ public String getMetadataSnapshot() {
+ return metadataSnapshot;
+ }
+
+ public void setMetadataSnapshot(String metadataSnapshot) {
+ this.metadataSnapshot = metadataSnapshot;
+ }
+
+ public Timestamp getCreateDate() {
+ return createDate;
+ }
+
+ public void setCreateDate(Timestamp createDate) {
+ this.createDate = createDate;
+ }
+
+ public Timestamp getLastOpDate() {
+ return lastOpDate;
+ }
+
+ public void setLastOpDate(Timestamp lastOpDate) {
+ this.lastOpDate = lastOpDate;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO_.java b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO_.java
new file mode 100644
index 00000000000..d2a2876f4f1
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO_.java
@@ -0,0 +1,16 @@
+package org.zstack.header.vm.metadata;
+
+import javax.persistence.metamodel.SingularAttribute;
+import javax.persistence.metamodel.StaticMetamodel;
+import java.sql.Timestamp;
+
+@StaticMetamodel(VmMetadataFingerprintVO.class)
+public class VmMetadataFingerprintVO_ {
+ public static volatile SingularAttribute vmInstanceUuid;
+ public static volatile SingularAttribute lastFlushTime;
+ public static volatile SingularAttribute lastFlushFailed;
+ public static volatile SingularAttribute staleRecoveryCount;
+ public static volatile SingularAttribute metadataSnapshot;
+ public static volatile SingularAttribute createDate;
+ public static volatile SingularAttribute lastOpDate;
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathBuildExtensionPoint.java b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathBuildExtensionPoint.java
new file mode 100644
index 00000000000..f7921b11c8d
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathBuildExtensionPoint.java
@@ -0,0 +1,8 @@
+package org.zstack.header.vm.metadata;
+
+public interface VmMetadataPathBuildExtensionPoint {
+ String getPrimaryStorageType();
+ String buildVmMetadataPath(String primaryStorageUuid, String vmInstanceUuid);
+ String buildMetadataDir(String primaryStorageUuid);
+ String validateMetadataPath(String primaryStorageUuid, String path);
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathReplacementExtensionPoint.java b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathReplacementExtensionPoint.java
new file mode 100644
index 00000000000..989175ffe97
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathReplacementExtensionPoint.java
@@ -0,0 +1,42 @@
+package org.zstack.header.vm.metadata;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public interface VmMetadataPathReplacementExtensionPoint {
+ String getPrimaryStorageType();
+ PathReplacementResult calculatePathReplacements(String targetPsUuid, List allOldPaths);
+ class PathReplacementResult {
+ private Map metadataToCurrentPathMap = new HashMap<>();
+ private String oldPrefix;
+ private String newPrefix;
+
+ public PathReplacementResult() {
+ }
+
+ public Map getMetadataToCurrentPathMap() {
+ return metadataToCurrentPathMap;
+ }
+
+ public void setMetadataToCurrentPathMap(Map metadataToCurrentPathMap) {
+ this.metadataToCurrentPathMap = metadataToCurrentPathMap;
+ }
+
+ public String getOldPrefix() {
+ return oldPrefix;
+ }
+
+ public void setOldPrefix(String oldPrefix) {
+ this.oldPrefix = oldPrefix;
+ }
+
+ public String getNewPrefix() {
+ return newPrefix;
+ }
+
+ public void setNewPrefix(String newPrefix) {
+ this.newPrefix = newPrefix;
+ }
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.java b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.java
new file mode 100644
index 00000000000..bda1d0a09ed
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.java
@@ -0,0 +1,11 @@
+package org.zstack.header.vm.metadata;
+
+import java.sql.Timestamp;
+
+public interface VmMetadataResourcePersistExtensionPoint {
+ String getPrimaryStorageType();
+ void afterVolumePersist(String primaryStorageUuid, String resourceUuid,
+ String resourceType, String hostUuid, long size, Timestamp now);
+ void afterSnapshotPersist(String primaryStorageUuid, String resourceUuid,
+ String resourceType, String hostUuid, long size, Timestamp now);
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/VmUuidFromApiResolver.java b/header/src/main/java/org/zstack/header/vm/metadata/VmUuidFromApiResolver.java
new file mode 100644
index 00000000000..afc0f4f475d
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/VmUuidFromApiResolver.java
@@ -0,0 +1,25 @@
+package org.zstack.header.vm.metadata;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public interface VmUuidFromApiResolver {
+ String resolveVmUuid(String fieldValue);
+
+ default List batchResolveVmUuids(List fieldValues) {
+ List result = new ArrayList<>();
+ if (fieldValues == null || fieldValues.isEmpty()) {
+ return result;
+ }
+ for (String v : fieldValues) {
+ if (v == null) {
+ continue;
+ }
+ String vmUuid = resolveVmUuid(v);
+ if (vmUuid != null) {
+ result.add(vmUuid);
+ }
+ }
+ return result;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/metadata/VolumeResourceMetadata.java b/header/src/main/java/org/zstack/header/vm/metadata/VolumeResourceMetadata.java
new file mode 100644
index 00000000000..76ff75474e1
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/metadata/VolumeResourceMetadata.java
@@ -0,0 +1,22 @@
+package org.zstack.header.vm.metadata;
+
+public class VolumeResourceMetadata extends ResourceMetadata {
+ private String snapshotReference;
+ private String snapshotReferenceTree;
+
+ public String getSnapshotReference() {
+ return snapshotReference;
+ }
+
+ public void setSnapshotReference(String snapshotReference) {
+ this.snapshotReference = snapshotReference;
+ }
+
+ public String getSnapshotReferenceTree() {
+ return snapshotReferenceTree;
+ }
+
+ public void setSnapshotReferenceTree(String snapshotReferenceTree) {
+ this.snapshotReferenceTree = snapshotReferenceTree;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/volume/APIAttachDataVolumeToVmMsg.java b/header/src/main/java/org/zstack/header/volume/APIAttachDataVolumeToVmMsg.java
index 6ae817723f4..b01ff703a4c 100755
--- a/header/src/main/java/org/zstack/header/volume/APIAttachDataVolumeToVmMsg.java
+++ b/header/src/main/java/org/zstack/header/volume/APIAttachDataVolumeToVmMsg.java
@@ -5,6 +5,7 @@
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
import org.zstack.header.vm.VmInstanceVO;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* @api api event for message :ref:`APIAttachVolumeToVmEvent`
@@ -39,6 +40,7 @@
parameterName = "params",
responseClass = APIAttachDataVolumeToVmEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "VmUuidDirectResolver", field = "vmInstanceUuid")
public class APIAttachDataVolumeToVmMsg extends APIMessage implements VolumeMessage {
/**
* @desc vm uuid. see :ref:`VmInstanceInventory`
diff --git a/header/src/main/java/org/zstack/header/volume/APIChangeVolumeStateMsg.java b/header/src/main/java/org/zstack/header/volume/APIChangeVolumeStateMsg.java
index 30478454c67..464436a6345 100755
--- a/header/src/main/java/org/zstack/header/volume/APIChangeVolumeStateMsg.java
+++ b/header/src/main/java/org/zstack/header/volume/APIChangeVolumeStateMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* @api change data volume state
@@ -38,6 +39,7 @@
method = HttpMethod.PUT,
responseClass = APIChangeVolumeStateEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VolumeUuidToVmUuidResolver", field = "uuid")
public class APIChangeVolumeStateMsg extends APIMessage implements VolumeMessage {
/**
* @desc data volume uuid
diff --git a/header/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotGroupMsg.java b/header/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotGroupMsg.java
index 9b497a73fe4..13434495343 100644
--- a/header/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotGroupMsg.java
+++ b/header/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotGroupMsg.java
@@ -13,6 +13,7 @@
import org.zstack.header.storage.snapshot.group.VolumeSnapshotGroupVO;
import org.zstack.header.vm.VmInstanceInventory;
import org.zstack.header.vm.VmInstanceVO;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.util.ArrayList;
import java.util.List;
@@ -27,6 +28,7 @@
responseClass = APICreateVolumeSnapshotGroupEvent.class,
parameterName = "params"
)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "VolumeUuidToVmUuidResolver", field = "rootVolumeUuid", updateOnFailure = true)
@DefaultTimeout(timeunit = TimeUnit.HOURS, value = 3)
public class APICreateVolumeSnapshotGroupMsg extends APICreateMessage implements VolumeMessage, CreateVolumeSnapshotGroupMessage, APIMultiAuditor {
/**
diff --git a/header/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotMsg.java b/header/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotMsg.java
index 35f57d205f6..ca92ecf5034 100755
--- a/header/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotMsg.java
+++ b/header/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotMsg.java
@@ -5,6 +5,7 @@
import org.zstack.header.other.APIAuditor;
import org.zstack.header.rest.RestRequest;
import org.zstack.header.storage.snapshot.VolumeSnapshotVO;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.util.concurrent.TimeUnit;
@@ -45,6 +46,7 @@
parameterName = "params"
)
@DefaultTimeout(timeunit = TimeUnit.HOURS, value = 3)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "VolumeUuidToVmUuidResolver", field = "volumeUuid", updateOnFailure = true)
public class APICreateVolumeSnapshotMsg extends APICreateMessage implements VolumeMessage, APIAuditor {
/**
* @desc volume uuid. See :ref:`VolumeInventory`
diff --git a/header/src/main/java/org/zstack/header/volume/APIDeleteDataVolumeMsg.java b/header/src/main/java/org/zstack/header/volume/APIDeleteDataVolumeMsg.java
index fdbb1be9847..bde41313f8e 100755
--- a/header/src/main/java/org/zstack/header/volume/APIDeleteDataVolumeMsg.java
+++ b/header/src/main/java/org/zstack/header/volume/APIDeleteDataVolumeMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIDeleteMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.util.List;
@@ -42,6 +43,7 @@
method = HttpMethod.DELETE,
responseClass = APIDeleteDataVolumeEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "VolumeUuidToVmUuidResolver", field = "uuid")
public class APIDeleteDataVolumeMsg extends APIDeleteMessage implements VolumeMessage {
/**
* @desc data volume uuid
diff --git a/header/src/main/java/org/zstack/header/volume/APIDetachDataVolumeFromVmMsg.java b/header/src/main/java/org/zstack/header/volume/APIDetachDataVolumeFromVmMsg.java
index 5164ffca076..65374886a04 100755
--- a/header/src/main/java/org/zstack/header/volume/APIDetachDataVolumeFromVmMsg.java
+++ b/header/src/main/java/org/zstack/header/volume/APIDetachDataVolumeFromVmMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.vm.VmInstanceVO;
+import org.zstack.header.vm.metadata.MetadataImpact;
import org.zstack.header.rest.RestRequest;
/**
@@ -36,6 +37,7 @@
method = HttpMethod.DELETE,
responseClass = APIDetachDataVolumeFromVmEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "VolumeUuidToVmUuidResolver", field = "uuid")
public class APIDetachDataVolumeFromVmMsg extends APIMessage implements VolumeMessage {
/**
* @desc data volume uuid. See :ref:`VolumeInventory`
diff --git a/header/src/main/java/org/zstack/header/volume/APIExpungeDataVolumeMsg.java b/header/src/main/java/org/zstack/header/volume/APIExpungeDataVolumeMsg.java
index 272036c9378..53071f40ae8 100755
--- a/header/src/main/java/org/zstack/header/volume/APIExpungeDataVolumeMsg.java
+++ b/header/src/main/java/org/zstack/header/volume/APIExpungeDataVolumeMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by frank on 11/16/2015.
@@ -14,6 +15,7 @@
method = HttpMethod.PUT,
responseClass = APIExpungeDataVolumeEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "VolumeUuidToVmUuidResolver", field = "uuid")
public class APIExpungeDataVolumeMsg extends APIMessage implements VolumeMessage {
@APIParam(resourceType = VolumeVO.class, successIfResourceNotExisting = true)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/volume/APIFlattenVolumeMsg.java b/header/src/main/java/org/zstack/header/volume/APIFlattenVolumeMsg.java
index daeb56b44eb..624d62dd540 100644
--- a/header/src/main/java/org/zstack/header/volume/APIFlattenVolumeMsg.java
+++ b/header/src/main/java/org/zstack/header/volume/APIFlattenVolumeMsg.java
@@ -7,6 +7,7 @@
import org.zstack.header.message.DefaultTimeout;
import org.zstack.header.other.APIAuditor;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import java.util.concurrent.TimeUnit;
@@ -17,6 +18,7 @@
method = HttpMethod.PUT,
responseClass = APIFlattenVolumeEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "VolumeUuidToVmUuidResolver", field = "uuid")
public class APIFlattenVolumeMsg extends APIMessage implements VolumeMessage, APIAuditor {
@APIParam(resourceType = VolumeVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/volume/APIRecoverDataVolumeMsg.java b/header/src/main/java/org/zstack/header/volume/APIRecoverDataVolumeMsg.java
index eec77334a37..11fc833074d 100755
--- a/header/src/main/java/org/zstack/header/volume/APIRecoverDataVolumeMsg.java
+++ b/header/src/main/java/org/zstack/header/volume/APIRecoverDataVolumeMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by frank on 11/12/2015.
@@ -14,6 +15,7 @@
method = HttpMethod.PUT,
responseClass = APIRecoverDataVolumeEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "VolumeUuidToVmUuidResolver", field = "uuid")
public class APIRecoverDataVolumeMsg extends APIMessage implements VolumeMessage {
@APIParam(resourceType = VolumeVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/volume/APISyncVolumeSizeMsg.java b/header/src/main/java/org/zstack/header/volume/APISyncVolumeSizeMsg.java
index d4780c73be0..0eb69ce5dc4 100755
--- a/header/src/main/java/org/zstack/header/volume/APISyncVolumeSizeMsg.java
+++ b/header/src/main/java/org/zstack/header/volume/APISyncVolumeSizeMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by xing5 on 2016/4/24.
@@ -14,6 +15,7 @@
responseClass = APISyncVolumeSizeEvent.class,
isAction = true
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VolumeUuidToVmUuidResolver", field = "uuid")
public class APISyncVolumeSizeMsg extends APIMessage implements VolumeMessage {
@APIParam(resourceType = VolumeVO.class)
private String uuid;
diff --git a/header/src/main/java/org/zstack/header/volume/APIUndoSnapshotCreationMsg.java b/header/src/main/java/org/zstack/header/volume/APIUndoSnapshotCreationMsg.java
index 0d27cfaa18a..6c6b5513525 100644
--- a/header/src/main/java/org/zstack/header/volume/APIUndoSnapshotCreationMsg.java
+++ b/header/src/main/java/org/zstack/header/volume/APIUndoSnapshotCreationMsg.java
@@ -5,6 +5,7 @@
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
import org.zstack.header.storage.snapshot.VolumeSnapshotVO;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* @ Author : yh.w
@@ -16,6 +17,7 @@
method = HttpMethod.PUT,
responseClass = APIUndoSnapshotCreationEvent.class
)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "VolumeUuidToVmUuidResolver", field = "uuid", updateOnFailure = true)
public class APIUndoSnapshotCreationMsg extends APIMessage implements VolumeMessage {
@APIParam(resourceType = VolumeVO.class)
diff --git a/header/src/main/java/org/zstack/header/volume/APIUpdateVolumeMsg.java b/header/src/main/java/org/zstack/header/volume/APIUpdateVolumeMsg.java
index 785cf824abd..a3d67b10f73 100755
--- a/header/src/main/java/org/zstack/header/volume/APIUpdateVolumeMsg.java
+++ b/header/src/main/java/org/zstack/header/volume/APIUpdateVolumeMsg.java
@@ -4,6 +4,7 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
/**
* Created by frank on 6/14/2015.
@@ -14,6 +15,7 @@
responseClass = APIUpdateVolumeEvent.class,
isAction = true
)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VolumeUuidToVmUuidResolver", field = "uuid")
public class APIUpdateVolumeMsg extends APIMessage implements VolumeMessage {
@APIParam(resourceType = VolumeVO.class)
private String uuid;
diff --git a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/APILocalStorageMigrateVolumeMsg.java b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/APILocalStorageMigrateVolumeMsg.java
index e1864931171..a586da2bf48 100755
--- a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/APILocalStorageMigrateVolumeMsg.java
+++ b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/APILocalStorageMigrateVolumeMsg.java
@@ -10,6 +10,7 @@
import org.zstack.header.rest.APINoSee;
import org.zstack.header.rest.RestRequest;
import org.zstack.header.storage.primary.PrimaryStorageMessage;
+import org.zstack.header.vm.metadata.MetadataImpact;
import org.zstack.header.storage.primary.PrimaryStorageVO;
import org.zstack.header.volume.VolumeVO;
@@ -25,6 +26,7 @@
isAction = true
)
@DefaultTimeout(timeunit = TimeUnit.HOURS, value = 24)
+@MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "VolumeUuidToVmUuidResolver", field = "volumeUuid", updateOnFailure = true)
public class APILocalStorageMigrateVolumeMsg extends APIMessage implements PrimaryStorageMessage, APIAuditor {
@APIParam(resourceType = VolumeVO.class)
private String volumeUuid;
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 d4665a86a06..4a75220b6d8 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
@@ -39,6 +39,8 @@
import org.zstack.header.storage.primary.VolumeSnapshotCapability.VolumeSnapshotArrangementType;
import org.zstack.header.storage.snapshot.*;
import org.zstack.header.vm.*;
+import org.zstack.header.vm.metadata.UpdateVmInstanceMetadataOnPrimaryStorageMsg;
+import org.zstack.header.vm.metadata.UpdateVmInstanceMetadataOnPrimaryStorageReply;
import org.zstack.header.vo.ResourceVO;
import org.zstack.header.volume.*;
import org.zstack.storage.primary.*;
@@ -65,7 +67,8 @@
import static org.zstack.core.Platform.*;
import static org.zstack.storage.primary.local.LocalStorageUtils.getHostUuidFromInstallUrl;
import static org.zstack.utils.CollectionDSL.*;
-import static org.zstack.utils.CollectionUtils.*;
+import static org.zstack.utils.CollectionUtils.toMap;
+import static org.zstack.utils.CollectionUtils.transformAndRemoveNull;
/**
* Created by frank on 6/30/2015.
@@ -902,6 +905,8 @@ public void handleLocalMessage(Message msg) {
handle((CommitVolumeSnapshotOnPrimaryStorageMsg) msg);
} else if (msg instanceof PullVolumeSnapshotOnPrimaryStorageMsg) {
handle((PullVolumeSnapshotOnPrimaryStorageMsg) msg);
+ } else if (msg instanceof RebaseVolumeBackingFileOnPrimaryStorageMsg) {
+ handle((RebaseVolumeBackingFileOnPrimaryStorageMsg) msg);
} else {
super.handleLocalMessage(msg);
}
@@ -1640,6 +1645,24 @@ public void fail(ErrorCode errorCode) {
});
}
+ protected void handle(RebaseVolumeBackingFileOnPrimaryStorageMsg msg) {
+ LocalStorageHypervisorFactory f = getHypervisorBackendFactoryByHostUuid(msg.getHostUuid());
+ LocalStorageHypervisorBackend bkd = f.getHypervisorBackend(self);
+ bkd.handle(msg, msg.getHostUuid(), new ReturnValueCompletion(msg) {
+ @Override
+ public void success(RebaseVolumeBackingFileOnPrimaryStorageReply returnValue) {
+ bus.reply(msg, returnValue);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ RebaseVolumeBackingFileOnPrimaryStorageReply reply = new RebaseVolumeBackingFileOnPrimaryStorageReply();
+ reply.setError(errorCode);
+ bus.reply(msg, reply);
+ }
+ });
+ }
+
private void handle(RemoveHostFromLocalStorageMsg msg) {
RemoveHostFromLocalStorageReply reply = new RemoveHostFromLocalStorageReply();
thdf.chainSubmit(new ChainTask(msg) {
@@ -3329,4 +3352,189 @@ public void fail(ErrorCode errorCode) {
public static class LocalStoragePhysicalCapacityUsage extends PrimaryStorageBase.PhysicalCapacityUsage {
public long localStorageUsedSize;
}
+
+ @Override
+ protected void handle(final UpdateVmInstanceMetadataOnPrimaryStorageMsg msg) {
+ thdf.chainSubmit(new ChainTask(msg) {
+ @Override
+ public String getSyncSignature() {
+ return "update-metadata-on-ps-" + self.getUuid();
+ }
+
+ @Override
+ public int getSyncLevel() {
+ return 10;
+ }
+
+ @Override
+ public void run(SyncTaskChain chain) {
+ final String hostUuid;
+ final LocalStorageHypervisorBackend bkd;
+ try {
+ hostUuid = getHostUuidByResourceUuid(msg.getRootVolumeUuid());
+ LocalStorageHypervisorFactory f = getHypervisorBackendFactoryByHostUuid(hostUuid);
+ bkd = f.getHypervisorBackend(self);
+ } catch (Exception e) {
+ UpdateVmInstanceMetadataOnPrimaryStorageReply reply = new UpdateVmInstanceMetadataOnPrimaryStorageReply();
+ reply.setError(operr("failed to resolve host for vm metadata update on local primary storage[uuid:%s], rootVolumeUuid[%s]: %s",
+ self.getUuid(), msg.getRootVolumeUuid(), e.getMessage()));
+ bus.reply(msg, reply);
+ chain.next();
+ return;
+ }
+ bkd.handle(msg, hostUuid, new ReturnValueCompletion(msg, chain) {
+ @Override
+ public void success(UpdateVmInstanceMetadataOnPrimaryStorageReply returnValue) {
+ bus.reply(msg, returnValue);
+ chain.next();
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ UpdateVmInstanceMetadataOnPrimaryStorageReply reply = new UpdateVmInstanceMetadataOnPrimaryStorageReply();
+ reply.setError(errorCode);
+ bus.reply(msg, reply);
+ chain.next();
+ }
+ });
+ }
+
+ @Override
+ public String getName() {
+ return "update-metadata-on-ps-" + self.getUuid();
+ }
+ });
+ }
+
+ @Override
+ protected void handle(final GetVmInstanceMetadataFromPrimaryStorageMsg msg) {
+ GetVmInstanceMetadataFromPrimaryStorageReply reply = new GetVmInstanceMetadataFromPrimaryStorageReply();
+
+ String hostUuid = null;
+ if (msg.getHostUuid() != null) {
+ hostUuid = msg.getHostUuid();
+ }
+
+ if (hostUuid == null) {
+ if (msg.getRootVolumeUuid() == null) {
+ reply.setError(operr("cannot determine host for vm metadata get on local primary storage[uuid:%s]," +
+ " rootVolumeUuid is null", self.getUuid()));
+ bus.reply(msg, reply);
+ return;
+ }
+ try {
+ hostUuid = getHostUuidByResourceUuid(msg.getRootVolumeUuid());
+ } catch (Exception e) {
+ reply.setError(operr("cannot determine host for vm metadata get on local primary storage[uuid:%s], rootVolumeUuid[%s]: %s",
+ self.getUuid(), msg.getRootVolumeUuid(), e.getMessage()));
+ bus.reply(msg, reply);
+ return;
+ }
+ }
+
+ LocalStorageHypervisorFactory f = getHypervisorBackendFactoryByHostUuid(hostUuid);
+ LocalStorageHypervisorBackend bkd = f.getHypervisorBackend(self);
+ bkd.handle(msg, hostUuid, new ReturnValueCompletion(msg) {
+ @Override
+ public void success(GetVmInstanceMetadataFromPrimaryStorageReply returnValue) {
+ bus.reply(msg, returnValue);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ reply.setError(errorCode);
+ bus.reply(msg, reply);
+ }
+ });
+ }
+
+ @Override
+ protected void handle(final ScanVmInstanceMetadataFromPrimaryStorageMsg msg) {
+ ScanVmInstanceMetadataFromPrimaryStorageReply reply = new ScanVmInstanceMetadataFromPrimaryStorageReply();
+
+ 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()) {
+ reply.setError(operr("no connected host found for local primary storage[uuid:%s]", self.getUuid()));
+ bus.reply(msg, reply);
+ return;
+ }
+
+ List allSummaries = Collections.synchronizedList(new ArrayList<>());
+
+ new While<>(connectedHostUuids).all((hostUuid, com) -> {
+ LocalStorageHypervisorFactory f = getHypervisorBackendFactoryByHostUuid(hostUuid);
+ LocalStorageHypervisorBackend bkd = f.getHypervisorBackend(self);
+ bkd.handle(msg, hostUuid, new ReturnValueCompletion(com) {
+ @Override
+ public void success(ScanVmInstanceMetadataFromPrimaryStorageReply returnValue) {
+ if (returnValue.getVmInstanceMetadata() != null) {
+ allSummaries.addAll(returnValue.getVmInstanceMetadata());
+ }
+ com.done();
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ logger.warn(String.format("failed to scan vm metadata from host[uuid:%s] on local primary storage[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 scan vm metadata from all hosts on local primary storage[uuid:%s], causes: %s",
+ self.getUuid(), errorCodeList));
+ } else {
+ reply.setVmInstanceMetadata(new ArrayList<>(allSummaries));
+ }
+ bus.reply(msg, reply);
+ }
+ });
+ }
+
+ @Override
+ protected void handle(final CleanupVmInstanceMetadataOnPrimaryStorageMsg msg) {
+ CleanupVmInstanceMetadataOnPrimaryStorageReply reply = new CleanupVmInstanceMetadataOnPrimaryStorageReply();
+
+ String hostUuid = msg.getHostUuid();
+ if (hostUuid == null && msg.getRootVolumeUuid() != null) {
+ try {
+ hostUuid = getHostUuidByResourceUuid(msg.getRootVolumeUuid());
+ } catch (Exception e) {
+ logger.warn(String.format("failed to get host by rootVolumeUuid[%s]: %s", msg.getRootVolumeUuid(), e.getMessage()));
+ }
+ }
+
+ if (hostUuid == null) {
+ reply.setError(operr("cannot determine host for vm metadata cleanup on local primary storage[uuid:%s]," +
+ " rootVolumeUuid[%s], hostUuid is null", self.getUuid(), msg.getRootVolumeUuid()));
+ bus.reply(msg, reply);
+ return;
+ }
+
+ LocalStorageHypervisorFactory f = getHypervisorBackendFactoryByHostUuid(hostUuid);
+ LocalStorageHypervisorBackend bkd = f.getHypervisorBackend(self);
+ bkd.handle(msg, hostUuid, new ReturnValueCompletion(msg) {
+ @Override
+ public void success(CleanupVmInstanceMetadataOnPrimaryStorageReply returnValue) {
+ bus.reply(msg, returnValue);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ reply.setError(errorCode);
+ bus.reply(msg, reply);
+ }
+ });
+ }
}
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 7760e28de93..d8226d932b2 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
@@ -7,6 +7,8 @@
import org.zstack.header.image.ImageInventory;
import org.zstack.header.storage.primary.*;
import org.zstack.header.storage.snapshot.VolumeSnapshotInventory;
+import org.zstack.header.vm.metadata.UpdateVmInstanceMetadataOnPrimaryStorageMsg;
+import org.zstack.header.vm.metadata.UpdateVmInstanceMetadataOnPrimaryStorageReply;
import org.zstack.header.volume.*;
import org.zstack.storage.primary.EstimateVolumeTemplateSizeOnPrimaryStorageMsg;
import org.zstack.storage.primary.EstimateVolumeTemplateSizeOnPrimaryStorageReply;
@@ -121,4 +123,14 @@ public LocalStorageHypervisorBackend(PrimaryStorageVO self) {
abstract void handle(CommitVolumeSnapshotOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
abstract void handle(PullVolumeSnapshotOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
+
+ abstract void handle(UpdateVmInstanceMetadataOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
+
+ abstract void handle(GetVmInstanceMetadataFromPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
+
+ abstract void handle(ScanVmInstanceMetadataFromPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
+
+ abstract void handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg 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 e8d268e518a..0346a8bfe4f 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
@@ -42,11 +42,15 @@
import org.zstack.header.rest.RESTFacade;
import org.zstack.header.storage.backup.*;
import org.zstack.header.storage.primary.*;
-import org.zstack.header.storage.snapshot.*;
+import org.zstack.header.storage.snapshot.VolumeSnapshotConstant;
+import org.zstack.header.storage.snapshot.VolumeSnapshotInventory;
+import org.zstack.header.storage.snapshot.VolumeSnapshotVO;
import org.zstack.header.vm.VmInstanceSpec.ImageSpec;
import org.zstack.header.vm.VmInstanceState;
import org.zstack.header.vm.VmInstanceVO;
import org.zstack.header.vm.VmInstanceVO_;
+import org.zstack.header.vm.metadata.UpdateVmInstanceMetadataOnPrimaryStorageMsg;
+import org.zstack.header.vm.metadata.UpdateVmInstanceMetadataOnPrimaryStorageReply;
import org.zstack.header.volume.*;
import org.zstack.identity.AccountManager;
import org.zstack.kvm.*;
@@ -67,9 +71,7 @@
import java.util.*;
import java.util.stream.Collectors;
-import static org.zstack.core.Platform.inerr;
-import static org.zstack.core.Platform.multiErr;
-import static org.zstack.core.Platform.operr;
+import static org.zstack.core.Platform.*;
import static org.zstack.utils.CollectionDSL.list;
import static org.zstack.utils.CollectionUtils.transformAndRemoveNull;
@@ -903,6 +905,52 @@ public void setHashValue(String hashValue) {
}
}
+ public static class WriteVmMetadataCmd extends AgentCommand {
+ public String metadata;
+ public String metadataPath;
+ public String vmUuid;
+ public String vmName;
+ public String vmCategory;
+ public String architecture;
+ public String schemaVersion;
+ }
+
+ public static class WriteVmMetadataRsp extends AgentResponse {
+ }
+
+ public static class GetVmInstanceMetadataCmd extends AgentCommand {
+ public String metadataPath;
+ }
+
+ public static class GetVmInstanceMetadataRsp extends AgentResponse {
+ public String metadata;
+ }
+
+ public static class ScanVmMetadataCmd extends AgentCommand {
+ public String metadataDir;
+ }
+
+ public static class ScanVmMetadataRsp extends AgentResponse {
+ public List metadataEntries = new ArrayList<>();
+ }
+
+ public static class CleanupVmMetadataCmd extends AgentCommand {
+ public String metadataPath;
+ }
+
+ public static class CleanupVmMetadataRsp extends AgentResponse {
+ }
+
+ public static class PrefixRebaseBackingFilesCmd extends LocalStorageKvmBackend.AgentCommand {
+ public List filePaths;
+ public String oldPrefix;
+ public String newPrefix;
+ }
+
+ public static class PrefixRebaseBackingFilesRsp extends LocalStorageKvmBackend.AgentResponse {
+ public int rebasedCount;
+ }
+
public static final String INIT_PATH = "/localstorage/init";
public static final String GET_PHYSICAL_CAPACITY_PATH = "/localstorage/getphysicalcapacity";
public static final String CREATE_EMPTY_VOLUME_PATH = "/localstorage/volume/createempty";
@@ -935,6 +983,11 @@ public void setHashValue(String hashValue) {
public static final String CANCEL_DOWNLOAD_BITS_FROM_KVM_HOST_PATH = "/localstorage/kvmhost/download/cancel";
public static final String GET_DOWNLOAD_BITS_FROM_KVM_HOST_PROGRESS_PATH = "/localstorage/kvmhost/download/progress";
public static final String GET_QCOW2_HASH_VALUE_PATH = "/localstorage/getqcow2hash";
+ public static final String WRITE_VM_METADATA_PATH = "/localstorage/vm/metadata/write";
+ 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 PREFIX_REBASE_BACKING_FILES_PATH = "/localstorage/snapshot/prefixrebasebackingfiles";
public LocalStorageKvmBackend() {
}
@@ -3797,4 +3850,114 @@ public void fail(ErrorCode errorCode) {
}
});
}
+
+ @Override
+ void handle(UpdateVmInstanceMetadataOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion) {
+ WriteVmMetadataCmd cmd = new WriteVmMetadataCmd();
+ cmd.metadata = msg.getMetadata();
+ cmd.metadataPath = msg.getMetadataPath();
+ cmd.vmUuid = msg.getVmInstanceUuid();
+ cmd.vmName = msg.getVmInstanceName();
+ cmd.vmCategory = msg.getVmCategory();
+ cmd.architecture = msg.getArchitecture();
+ cmd.schemaVersion = msg.getSchemaVersion();
+
+ httpCall(WRITE_VM_METADATA_PATH, hostUuid, cmd, WriteVmMetadataRsp.class, new ReturnValueCompletion(completion) {
+ @Override
+ public void success(WriteVmMetadataRsp rsp) {
+ completion.success(new UpdateVmInstanceMetadataOnPrimaryStorageReply());
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ completion.fail(errorCode);
+ }
+ });
+ }
+
+ @Override
+ void handle(GetVmInstanceMetadataFromPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion) {
+ GetVmInstanceMetadataCmd cmd = new GetVmInstanceMetadataCmd();
+ cmd.metadataPath = msg.getMetadataPath();
+
+ httpCall(GET_VM_INSTANCE_METADATA_PATH, hostUuid, cmd, GetVmInstanceMetadataRsp.class, new ReturnValueCompletion(completion) {
+ @Override
+ public void success(GetVmInstanceMetadataRsp rsp) {
+ GetVmInstanceMetadataFromPrimaryStorageReply reply = new GetVmInstanceMetadataFromPrimaryStorageReply();
+ reply.setMetadata(rsp.metadata);
+ completion.success(reply);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ completion.fail(errorCode);
+ }
+ });
+ }
+
+ @Override
+ void handle(ScanVmInstanceMetadataFromPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion) {
+ ScanVmMetadataCmd cmd = new ScanVmMetadataCmd();
+ cmd.metadataDir = msg.getMetadataDir();
+
+ httpCall(SCAN_VM_METADATA_PATH, hostUuid, cmd, ScanVmMetadataRsp.class, new ReturnValueCompletion(completion) {
+ @Override
+ public void success(ScanVmMetadataRsp rsp) {
+ ScanVmInstanceMetadataFromPrimaryStorageReply reply = new ScanVmInstanceMetadataFromPrimaryStorageReply();
+ if (rsp.metadataEntries != null) {
+ rsp.metadataEntries.forEach(entry -> entry.setHostUuid(hostUuid));
+ reply.setVmInstanceMetadata(rsp.metadataEntries);
+ } else {
+ reply.setVmInstanceMetadata(Collections.emptyList());
+ }
+ completion.success(reply);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ completion.fail(errorCode);
+ }
+ });
+ }
+
+ @Override
+ void handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion) {
+ CleanupVmMetadataCmd cmd = new CleanupVmMetadataCmd();
+ cmd.metadataPath = msg.getMetadataPath();
+
+ httpCall(CLEANUP_VM_METADATA_PATH, hostUuid, cmd, CleanupVmMetadataRsp.class, new ReturnValueCompletion(completion) {
+ @Override
+ public void success(CleanupVmMetadataRsp rsp) {
+ CleanupVmInstanceMetadataOnPrimaryStorageReply reply = new CleanupVmInstanceMetadataOnPrimaryStorageReply();
+ 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();
+ cmd.filePaths = msg.getInstallPaths();
+ cmd.oldPrefix = msg.getOldPrefix();
+ cmd.newPrefix = msg.getNewPrefix();
+
+ httpCall(PREFIX_REBASE_BACKING_FILES_PATH, hostUuid, cmd, PrefixRebaseBackingFilesRsp.class, new ReturnValueCompletion(completion) {
+ @Override
+ public void success(PrefixRebaseBackingFilesRsp rsp) {
+ RebaseVolumeBackingFileOnPrimaryStorageReply reply = new RebaseVolumeBackingFileOnPrimaryStorageReply();
+ reply.setRebasedCount(rsp.rebasedCount);
+ completion.success(reply);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ completion.fail(errorCode);
+ }
+ });
+ }
}
diff --git a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulator.java b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulator.java
index dbe774888f0..3edb2e916db 100755
--- a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulator.java
+++ b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulator.java
@@ -334,6 +334,44 @@ String offlineMerge(HttpEntity entity) {
return null;
}
+ @RequestMapping(value=LocalStorageKvmBackend.WRITE_VM_METADATA_PATH, method= RequestMethod.POST)
+ public @ResponseBody
+ String writeVmMetadata(HttpEntity entity) {
+ WriteVmMetadataCmd cmd = JSONObjectUtil.toObject(entity.getBody(), WriteVmMetadataCmd.class);
+ config.writeVmMetadataCmds.add(cmd);
+ reply(entity, new WriteVmMetadataRsp());
+ return null;
+ }
+
+ @RequestMapping(value=LocalStorageKvmBackend.GET_VM_INSTANCE_METADATA_PATH, method= RequestMethod.POST)
+ public @ResponseBody
+ String getVmInstanceMetadata(HttpEntity entity) {
+ GetVmInstanceMetadataCmd cmd = JSONObjectUtil.toObject(entity.getBody(), GetVmInstanceMetadataCmd.class);
+ config.getVmInstanceMetadataCmds.add(cmd);
+ GetVmInstanceMetadataRsp rsp = new GetVmInstanceMetadataRsp();
+ reply(entity, rsp);
+ return null;
+ }
+
+ @RequestMapping(value=LocalStorageKvmBackend.SCAN_VM_METADATA_PATH, method= RequestMethod.POST)
+ public @ResponseBody
+ String scanVmMetadata(HttpEntity entity) {
+ ScanVmMetadataCmd cmd = JSONObjectUtil.toObject(entity.getBody(), ScanVmMetadataCmd.class);
+ config.scanVmMetadataCmds.add(cmd);
+ ScanVmMetadataRsp rsp = new ScanVmMetadataRsp();
+ reply(entity, rsp);
+ return null;
+ }
+
+ @RequestMapping(value=LocalStorageKvmBackend.CLEANUP_VM_METADATA_PATH, method= RequestMethod.POST)
+ public @ResponseBody
+ String cleanupVmMetadata(HttpEntity entity) {
+ CleanupVmMetadataCmd cmd = JSONObjectUtil.toObject(entity.getBody(), CleanupVmMetadataCmd.class);
+ config.cleanupVmMetadataCmds.add(cmd);
+ reply(entity, new CleanupVmMetadataRsp());
+ return null;
+ }
+
@ExceptionHandler(Exception.class)
public ModelAndView handleAllException(Exception ex) {
logger.warn(ex.getMessage(), ex);
diff --git a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulatorConfig.java b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulatorConfig.java
index 53a02339833..34463b46c6e 100755
--- a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulatorConfig.java
+++ b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulatorConfig.java
@@ -59,4 +59,9 @@ public static class Capacity {
public List getQCOW2ReferenceCmds = new ArrayList<>();
public List getQCOW2ReferenceCmdReference = new ArrayList<>();
+
+ public List writeVmMetadataCmds = new ArrayList<>();
+ public List getVmInstanceMetadataCmds = new ArrayList<>();
+ public List scanVmMetadataCmds = new ArrayList<>();
+ public List cleanupVmMetadataCmds = new ArrayList<>();
}
diff --git a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.java b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.java
new file mode 100644
index 00000000000..d721d144b88
--- /dev/null
+++ b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.java
@@ -0,0 +1,146 @@
+package org.zstack.storage.primary.local;
+
+import org.springframework.beans.factory.annotation.Autowire;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Configurable;
+import org.zstack.core.db.DatabaseFacade;
+import org.zstack.core.db.Q;
+import org.zstack.header.exception.CloudRuntimeException;
+import org.zstack.header.storage.primary.PrimaryStorageVO;
+import org.zstack.header.storage.primary.PrimaryStorageVO_;
+import org.zstack.header.vm.metadata.VmInstanceMetadataConstants;
+import org.zstack.header.vm.metadata.VmMetadataPathBuildExtensionPoint;
+import org.zstack.header.vm.metadata.VmMetadataPathReplacementExtensionPoint;
+import org.zstack.header.vm.metadata.VmMetadataResourcePersistExtensionPoint;
+import org.zstack.utils.Utils;
+import org.zstack.utils.logging.CLogger;
+
+import java.sql.Timestamp;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
+public class LocalStorageVmMetadataExtension implements VmMetadataPathBuildExtensionPoint,
+ VmMetadataPathReplacementExtensionPoint, VmMetadataResourcePersistExtensionPoint {
+ private static final CLogger logger = Utils.getLogger(LocalStorageVmMetadataExtension.class);
+
+ @Autowired
+ private DatabaseFacade dbf;
+
+ @Override
+ public String getPrimaryStorageType() {
+ return LocalStorageConstants.LOCAL_STORAGE_TYPE;
+ }
+
+ @Override
+ public String buildMetadataDir(String primaryStorageUuid) {
+ String url = Q.New(PrimaryStorageVO.class).select(PrimaryStorageVO_.url).eq(PrimaryStorageVO_.uuid, primaryStorageUuid).findValue();
+ if (url == null) {
+ throw new CloudRuntimeException(String.format("cannot find url for primary storage[uuid:%s]", primaryStorageUuid));
+ }
+ return String.format("%s/%s", normalizeBaseDir(url), VmInstanceMetadataConstants.METADATA_DIR_NAME);
+ }
+
+ @Override
+ public String buildVmMetadataPath(String primaryStorageUuid, String vmInstanceUuid) {
+ String url = Q.New(PrimaryStorageVO.class).select(PrimaryStorageVO_.url).eq(PrimaryStorageVO_.uuid, primaryStorageUuid).findValue();
+ if (url == null) {
+ throw new CloudRuntimeException(String.format("cannot find url for primary storage[uuid:%s]", primaryStorageUuid));
+ }
+ return String.format("%s/%s/%s%s", normalizeBaseDir(url), VmInstanceMetadataConstants.METADATA_DIR_NAME, vmInstanceUuid, VmInstanceMetadataConstants.FILE_METADATA_SUFFIX);
+ }
+
+ @Override
+ public PathReplacementResult calculatePathReplacements(String targetPsUuid, List allOldPaths) {
+ if (allOldPaths == null || allOldPaths.isEmpty()) {
+ PathReplacementResult result = new PathReplacementResult();
+ result.setMetadataToCurrentPathMap(Collections.emptyMap());
+ return result;
+ }
+
+ String baseDir = Q.New(PrimaryStorageVO.class).select(PrimaryStorageVO_.url).eq(PrimaryStorageVO_.uuid, targetPsUuid).findValue();
+ if (baseDir == null) {
+ logger.warn(String.format("LocalStorage PS[uuid:%s] has no url, path replacement disabled", targetPsUuid));
+ PathReplacementResult result = new PathReplacementResult();
+ result.setMetadataToCurrentPathMap(Collections.emptyMap());
+ return result;
+ }
+ String newPrefix = normalizeBaseDir(baseDir) + "/";
+
+ // Extract old prefix from the first recognizable path
+ String oldPrefix = null;
+ for (String path : allOldPaths) {
+ oldPrefix = VmInstanceMetadataConstants.extractOldPrefix(path);
+ if (oldPrefix != null) break;
+ }
+
+ Map pathMap = new LinkedHashMap<>();
+ if (oldPrefix != null) {
+ for (String oldPath : allOldPaths) {
+ if (oldPath != null && oldPath.startsWith(oldPrefix)) {
+ pathMap.put(oldPath, newPrefix + oldPath.substring(oldPrefix.length()));
+ }
+ }
+ } else {
+ logger.warn(String.format("cannot extract old path prefix from any path for LocalStorage PS[uuid:%s], " +
+ "path replacement disabled", targetPsUuid));
+ }
+
+ PathReplacementResult result = new PathReplacementResult();
+ result.setMetadataToCurrentPathMap(pathMap);
+ result.setOldPrefix(oldPrefix);
+ result.setNewPrefix(newPrefix);
+ return result;
+ }
+
+ @Override
+ public String validateMetadataPath(String primaryStorageUuid, String path) {
+ // Expected format: /.vmmeta
+ // e.g. /local_ps/vm-metadata/a1b2c3d4e5f6...vmmeta
+ String metadataDir = buildMetadataDir(primaryStorageUuid);
+ String prefix = metadataDir + "/";
+ String suffix = VmInstanceMetadataConstants.FILE_METADATA_SUFFIX;
+
+ if (!path.startsWith(prefix) || !path.endsWith(suffix)) {
+ return String.format("metadataPath[%s] does not match expected format: %s/%s",
+ path, metadataDir, suffix);
+ }
+
+ String uuidPart = path.substring(prefix.length(), path.length() - suffix.length());
+ if (!uuidPart.matches("[0-9a-f]{32}")) {
+ return String.format("metadataPath[%s] contains invalid uuid[%s], expected 32-char hex", path, uuidPart);
+ }
+ return null;
+ }
+
+ private String normalizeBaseDir(String url) {
+ return url.endsWith("/") ? url.substring(0, url.length() - 1) : url;
+ }
+
+ @Override
+ public void afterVolumePersist(String primaryStorageUuid, String resourceUuid,
+ String resourceType, String hostUuid, long size, Timestamp now) {
+ createResourceRef(primaryStorageUuid, resourceUuid, resourceType, hostUuid, size, now);
+ }
+
+ @Override
+ public void afterSnapshotPersist(String primaryStorageUuid, String resourceUuid,
+ String resourceType, String hostUuid, long size, Timestamp now) {
+ createResourceRef(primaryStorageUuid, resourceUuid, resourceType, hostUuid, size, now);
+ }
+
+ private void createResourceRef(String primaryStorageUuid, String resourceUuid,
+ String resourceType, String hostUuid, long size, Timestamp now) {
+ LocalStorageResourceRefVO ref = new LocalStorageResourceRefVO();
+ ref.setPrimaryStorageUuid(primaryStorageUuid);
+ ref.setResourceUuid(resourceUuid);
+ ref.setResourceType(resourceType);
+ ref.setHostUuid(hostUuid);
+ ref.setSize(size);
+ ref.setCreateDate(now);
+ ref.setLastOpDate(now);
+ dbf.persist(ref);
+ }
+}
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 abe9ac152b6..b63e1d20597 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
@@ -36,7 +36,6 @@
import org.zstack.header.storage.backup.BackupStorageVO;
import org.zstack.header.storage.primary.*;
import org.zstack.header.storage.primary.VolumeSnapshotCapability.VolumeSnapshotArrangementType;
-import org.zstack.header.storage.snapshot.DeleteVolumeSnapshotDirection;
import org.zstack.header.storage.snapshot.ShrinkVolumeSnapshotOnPrimaryStorageMsg;
import org.zstack.header.storage.snapshot.VolumeSnapshotConstant;
import org.zstack.header.storage.snapshot.VolumeSnapshotInventory;
@@ -44,23 +43,27 @@
import org.zstack.header.vm.VmInstanceState;
import org.zstack.header.vm.VmInstanceVO;
import org.zstack.header.vm.VmInstanceVO_;
+import org.zstack.header.vm.metadata.*;
import org.zstack.header.volume.*;
-import org.zstack.kvm.*;
-import org.zstack.storage.primary.*;
+import org.zstack.kvm.KVMConstant;
+import org.zstack.storage.primary.EstimateVolumeTemplateSizeOnPrimaryStorageMsg;
+import org.zstack.storage.primary.EstimateVolumeTemplateSizeOnPrimaryStorageReply;
+import org.zstack.storage.primary.PrimaryStorageBase;
+import org.zstack.storage.primary.PrimaryStorageCapacityUpdater;
import org.zstack.storage.snapshot.reference.VolumeSnapshotReferenceUtils;
import org.zstack.storage.volume.VolumeErrors;
import org.zstack.storage.volume.VolumeSystemTags;
import org.zstack.tag.SystemTagCreator;
-import org.zstack.utils.CollectionUtils;
import org.zstack.utils.DebugUtils;
import org.zstack.utils.Utils;
-import org.zstack.utils.function.Function;
import org.zstack.utils.logging.CLogger;
import javax.persistence.Tuple;
import javax.persistence.TypedQuery;
import java.io.File;
-import java.util.*;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -131,6 +134,8 @@ protected void handleLocalMessage(Message msg) {
handle((CommitVolumeSnapshotOnPrimaryStorageMsg) msg);
} else if (msg instanceof PullVolumeSnapshotOnPrimaryStorageMsg) {
handle((PullVolumeSnapshotOnPrimaryStorageMsg) msg);
+ } else if (msg instanceof RebaseVolumeBackingFileOnPrimaryStorageMsg) {
+ handle((RebaseVolumeBackingFileOnPrimaryStorageMsg) msg);
} else {
super.handleLocalMessage(msg);
}
@@ -1924,4 +1929,153 @@ private String getHostUuidFromVolume(String volumeUuid) {
return hostUuid;
}
+
+ @Override
+ protected void handle(UpdateVmInstanceMetadataOnPrimaryStorageMsg msg) {
+ thdf.chainSubmit(new ChainTask(msg) {
+ @Override
+ public String getSyncSignature() {
+ return "update-metadata-on-ps-" + self.getUuid();
+ }
+
+ @Override
+ public int getSyncLevel() {
+ return 10;
+ }
+
+ @Override
+ public void run(SyncTaskChain chain) {
+ UpdateVmInstanceMetadataOnPrimaryStorageReply reply = new UpdateVmInstanceMetadataOnPrimaryStorageReply();
+
+ String hostUuid = getHostUuidFromVolume(msg.getRootVolumeUuid());
+ if (hostUuid == null || hostUuid.isEmpty()) {
+ reply.setError(operr("no host found for volume[uuid:%s]", msg.getRootVolumeUuid()));
+ bus.reply(msg, reply);
+ chain.next();
+ return;
+ }
+
+ final NfsPrimaryStorageBackend backend = getBackendByHostUuid(hostUuid);
+ backend.handle(msg, hostUuid, new ReturnValueCompletion(msg, chain) {
+ @Override
+ public void success(UpdateVmInstanceMetadataOnPrimaryStorageReply r) {
+ bus.reply(msg, r);
+ chain.next();
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ reply.setError(operr("failed to update vm metadata on NFS primary storage[uuid:%s]", self.getUuid()));
+ bus.reply(msg, reply);
+ chain.next();
+ }
+ });
+ }
+
+ @Override
+ public String getName() {
+ return "update-metadata-on-ps-" + self.getUuid();
+ }
+ });
+ }
+
+ @Override
+ protected void handle(GetVmInstanceMetadataFromPrimaryStorageMsg msg) {
+ GetVmInstanceMetadataFromPrimaryStorageReply reply = new GetVmInstanceMetadataFromPrimaryStorageReply();
+ 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;
+ }
+ String hostUuid = connectedHosts.get(0).getUuid();
+ final NfsPrimaryStorageBackend backend = getBackendByHostUuid(hostUuid);
+ backend.handle(msg, hostUuid, new ReturnValueCompletion(msg) {
+ @Override
+ public void success(GetVmInstanceMetadataFromPrimaryStorageReply r) {
+ bus.reply(msg, r);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ reply.setError(errorCode);
+ bus.reply(msg, reply);
+ }
+ });
+ }
+
+ @Override
+ protected void handle(ScanVmInstanceMetadataFromPrimaryStorageMsg msg) {
+ ScanVmInstanceMetadataFromPrimaryStorageReply reply = new ScanVmInstanceMetadataFromPrimaryStorageReply();
+ 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;
+ }
+ String hostUuid = connectedHosts.get(0).getUuid();
+ final NfsPrimaryStorageBackend backend = getBackendByHostUuid(hostUuid);
+ backend.handle(msg, hostUuid, new ReturnValueCompletion(msg) {
+ @Override
+ public void success(ScanVmInstanceMetadataFromPrimaryStorageReply r) {
+ bus.reply(msg, r);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ reply.setError(errorCode);
+ bus.reply(msg, reply);
+ }
+ });
+ }
+
+ @Override
+ protected void handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg msg) {
+ CleanupVmInstanceMetadataOnPrimaryStorageReply reply = new CleanupVmInstanceMetadataOnPrimaryStorageReply();
+ 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;
+ }
+ String hostUuid = connectedHosts.get(0).getUuid();
+ final NfsPrimaryStorageBackend backend = getBackendByHostUuid(hostUuid);
+ backend.handle(msg, hostUuid, new ReturnValueCompletion(msg) {
+ @Override
+ public void success(CleanupVmInstanceMetadataOnPrimaryStorageReply r) {
+ bus.reply(msg, r);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ reply.setError(errorCode);
+ bus.reply(msg, reply);
+ }
+ });
+ }
+
+ @Override
+ protected void handle(RebaseVolumeBackingFileOnPrimaryStorageMsg msg) {
+ RebaseVolumeBackingFileOnPrimaryStorageReply reply = new RebaseVolumeBackingFileOnPrimaryStorageReply();
+ 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;
+ }
+ String hostUuid = connectedHosts.get(0).getUuid();
+ final NfsPrimaryStorageBackend backend = getBackendByHostUuid(hostUuid);
+ backend.handle(msg, hostUuid, new ReturnValueCompletion(msg) {
+ @Override
+ public void success(RebaseVolumeBackingFileOnPrimaryStorageReply r) {
+ bus.reply(msg, r);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ reply.setError(errorCode);
+ bus.reply(msg, reply);
+ }
+ });
+ }
}
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 459023d7c17..35a240a6221 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
@@ -7,6 +7,8 @@
import org.zstack.header.image.ImageInventory;
import org.zstack.header.storage.primary.*;
import org.zstack.header.storage.snapshot.VolumeSnapshotInventory;
+import org.zstack.header.vm.metadata.UpdateVmInstanceMetadataOnPrimaryStorageMsg;
+import org.zstack.header.vm.metadata.UpdateVmInstanceMetadataOnPrimaryStorageReply;
import org.zstack.header.volume.VolumeStats;
import org.zstack.header.volume.BatchSyncVolumeSizeOnPrimaryStorageMsg;
import org.zstack.header.volume.BatchSyncVolumeSizeOnPrimaryStorageReply;
@@ -91,6 +93,16 @@ public interface NfsPrimaryStorageBackend {
void updateMountPoint(PrimaryStorageInventory pinv, String clusterUuid, String oldMountPoint, String newMountPoint, Completion completion);
+ void handle(UpdateVmInstanceMetadataOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
+
+ void handle(GetVmInstanceMetadataFromPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
+
+ void handle(ScanVmInstanceMetadataFromPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
+
+ void handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
+
+ void handle(RebaseVolumeBackingFileOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion);
+
class BitsInfo {
private String installPath;
private long size;
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 93d3d7aab99..8d979dd94bb 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
@@ -21,7 +21,9 @@
import org.zstack.core.timeout.ApiTimeoutManager;
import org.zstack.core.trash.StorageTrash;
import org.zstack.header.core.*;
-import org.zstack.header.core.workflow.*;
+import org.zstack.header.core.workflow.Flow;
+import org.zstack.header.core.workflow.FlowTrigger;
+import org.zstack.header.core.workflow.NoRollbackFlow;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.errorcode.ErrorCodeList;
import org.zstack.header.errorcode.OperationFailureException;
@@ -39,6 +41,8 @@
import org.zstack.header.vm.VmInstanceState;
import org.zstack.header.vm.VmInstanceVO;
import org.zstack.header.vm.VmInstanceVO_;
+import org.zstack.header.vm.metadata.UpdateVmInstanceMetadataOnPrimaryStorageMsg;
+import org.zstack.header.vm.metadata.UpdateVmInstanceMetadataOnPrimaryStorageReply;
import org.zstack.header.volume.*;
import org.zstack.identity.AccountManager;
import org.zstack.kvm.*;
@@ -129,7 +133,12 @@ public class NfsPrimaryStorageKVMBackend implements NfsPrimaryStorageBackend,
public static final String GET_DOWNLOAD_BITS_FROM_KVM_HOST_PROGRESS_PATH = "/nfsprimarystorage/kvmhost/download/progress";
public static final String CREATE_VOLUME_FROM_TEMPLATE_PATH = "/nfsprimarystorage/sftp/createvolumefromtemplate";
public static final String GET_QCOW2_HASH_VALUE_PATH = "/nfsprimarystorage/getqcow2hash";
+ public static final String WRITE_VM_METADATA_PATH = "/nfsprimarystorage/vm/metadata/write";
+ 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 NFS_PREFIX_REBASE_BACKING_FILES_PATH = "/nfsprimarystorage/snapshot/prefixrebasebackingfiles";
//////////////// For unit test //////////////////////////
private boolean syncGetCapacity = false;
@@ -2051,4 +2060,174 @@ public void run(MessageReply r) {
}
});
}
+
+ @Override
+ public void handle(UpdateVmInstanceMetadataOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion) {
+ WriteVmMetadataCmd cmd = new WriteVmMetadataCmd();
+ cmd.setUuid(msg.getPrimaryStorageUuid());
+ cmd.metadata = msg.getMetadata();
+ cmd.metadataPath = msg.getMetadataPath();
+ cmd.vmUuid = msg.getVmInstanceUuid();
+ cmd.vmName = msg.getVmInstanceName();
+ cmd.vmCategory = msg.getVmCategory();
+ cmd.architecture = msg.getArchitecture();
+ cmd.schemaVersion = msg.getSchemaVersion();
+
+ KVMHostAsyncHttpCallMsg hmsg = new KVMHostAsyncHttpCallMsg();
+ hmsg.setCommand(cmd);
+ hmsg.setPath(WRITE_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;
+ }
+
+ WriteVmMetadataRsp rsp = ((KVMHostAsyncHttpCallReply) reply).toResponse(WriteVmMetadataRsp.class);
+ if (!rsp.isSuccess()) {
+ completion.fail(operr("failed to write vm metadata on nfs via host[uuid:%s]: %s", hostUuid, rsp.getError()));
+ return;
+ }
+
+ completion.success(new UpdateVmInstanceMetadataOnPrimaryStorageReply());
+ }
+ });
+ }
+
+ @Override
+ public void handle(GetVmInstanceMetadataFromPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion) {
+ NfsPrimaryStorageKVMBackendCommands.GetVmInstanceMetadataCmd cmd = new NfsPrimaryStorageKVMBackendCommands.GetVmInstanceMetadataCmd();
+ cmd.setUuid(msg.getPrimaryStorageUuid());
+ cmd.metadataPath = msg.getMetadataPath();
+
+ KVMHostAsyncHttpCallMsg hmsg = new KVMHostAsyncHttpCallMsg();
+ hmsg.setCommand(cmd);
+ hmsg.setPath(GET_VM_INSTANCE_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;
+ }
+
+ GetVmInstanceMetadataRsp rsp = ((KVMHostAsyncHttpCallReply) reply).toResponse(GetVmInstanceMetadataRsp.class);
+ if (!rsp.isSuccess()) {
+ completion.fail(operr("failed to get vm instance metadata on nfs via host[uuid:%s]: %s", hostUuid, rsp.getError()));
+ return;
+ }
+
+ GetVmInstanceMetadataFromPrimaryStorageReply r = new GetVmInstanceMetadataFromPrimaryStorageReply();
+ r.setMetadata(rsp.metadata);
+ completion.success(r);
+ }
+ });
+ }
+
+ @Override
+ public void handle(ScanVmInstanceMetadataFromPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion) {
+ NfsPrimaryStorageKVMBackendCommands.ScanVmMetadataCmd cmd = new NfsPrimaryStorageKVMBackendCommands.ScanVmMetadataCmd();
+ cmd.setUuid(msg.getPrimaryStorageUuid());
+ cmd.metadataDir = msg.getMetadataDir();
+
+ KVMHostAsyncHttpCallMsg hmsg = new KVMHostAsyncHttpCallMsg();
+ hmsg.setCommand(cmd);
+ hmsg.setPath(SCAN_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;
+ }
+
+ NfsPrimaryStorageKVMBackendCommands.ScanVmMetadataRsp rsp = ((KVMHostAsyncHttpCallReply) reply).toResponse(NfsPrimaryStorageKVMBackendCommands.ScanVmMetadataRsp.class);
+ if (!rsp.isSuccess()) {
+ completion.fail(operr("failed to scan vm instance metadata on nfs via host[uuid:%s]: %s", hostUuid, rsp.getError()));
+ return;
+ }
+
+ ScanVmInstanceMetadataFromPrimaryStorageReply r = new ScanVmInstanceMetadataFromPrimaryStorageReply();
+ if (rsp.metadataEntries != null) {
+ rsp.metadataEntries.forEach(entry -> entry.setHostUuid(hostUuid));
+ r.setVmInstanceMetadata(rsp.metadataEntries);
+ }
+ completion.success(r);
+ }
+ });
+ }
+
+ @Override
+ public void handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion) {
+ CleanupVmMetadataCmd cmd = new CleanupVmMetadataCmd();
+ cmd.setUuid(msg.getPrimaryStorageUuid());
+ cmd.metadataPath = msg.getMetadataPath();
+
+ KVMHostAsyncHttpCallMsg hmsg = new KVMHostAsyncHttpCallMsg();
+ hmsg.setCommand(cmd);
+ hmsg.setPath(CLEANUP_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;
+ }
+
+ CleanupVmMetadataRsp rsp = ((KVMHostAsyncHttpCallReply) reply).toResponse(CleanupVmMetadataRsp.class);
+ if (!rsp.isSuccess()) {
+ completion.fail(operr("failed to cleanup vm metadata on nfs via host[uuid:%s]: %s", hostUuid, rsp.getError()));
+ return;
+ }
+
+ CleanupVmInstanceMetadataOnPrimaryStorageReply r = new CleanupVmInstanceMetadataOnPrimaryStorageReply();
+ completion.success(r);
+ }
+ });
+ }
+
+ @Override
+ public void handle(RebaseVolumeBackingFileOnPrimaryStorageMsg msg, String hostUuid, ReturnValueCompletion completion) {
+ NfsPrimaryStorageKVMBackendCommands.PrefixRebaseBackingFilesCmd cmd = new NfsPrimaryStorageKVMBackendCommands.PrefixRebaseBackingFilesCmd();
+ // NFS installPaths are already filesystem paths, no conversion needed
+ cmd.filePaths = msg.getInstallPaths();
+ cmd.oldPrefix = msg.getOldPrefix();
+ cmd.newPrefix = msg.getNewPrefix();
+ cmd.setUuid(msg.getPrimaryStorageUuid());
+
+ KVMHostAsyncHttpCallMsg hmsg = new KVMHostAsyncHttpCallMsg();
+ hmsg.setCommand(cmd);
+ hmsg.setPath(NFS_PREFIX_REBASE_BACKING_FILES_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;
+ }
+
+ NfsPrimaryStorageKVMBackendCommands.PrefixRebaseBackingFilesRsp rsp =
+ ((KVMHostAsyncHttpCallReply) reply).toResponse(NfsPrimaryStorageKVMBackendCommands.PrefixRebaseBackingFilesRsp.class);
+ if (!rsp.isSuccess()) {
+ completion.fail(operr("failed to prefix rebase backing files on nfs via host[uuid:%s]: %s", hostUuid, rsp.getError()));
+ return;
+ }
+
+ RebaseVolumeBackingFileOnPrimaryStorageReply r = new RebaseVolumeBackingFileOnPrimaryStorageReply();
+ r.setRebasedCount(rsp.rebasedCount);
+ 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 d7cebfaa4c6..12c41c054c7 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
@@ -2,6 +2,7 @@
import org.zstack.header.HasThreadContext;
import org.zstack.header.core.validation.Validation;
+import org.zstack.header.storage.primary.VmMetadataScanEntry;
import org.zstack.kvm.KVMAgentCommands;
import org.zstack.kvm.KVMAgentCommands.AgentCommand;
import org.zstack.kvm.KVMAgentCommands.AgentResponse;
@@ -948,4 +949,51 @@ public void setHashValue(String hashValue) {
this.hashValue = hashValue;
}
}
+
+ public static class WriteVmMetadataCmd extends NfsPrimaryStorageAgentCommand {
+ public String metadata;
+ public String metadataPath;
+ public String vmUuid;
+ public String vmName;
+ public String vmCategory;
+ public String architecture;
+ public String schemaVersion;
+ }
+
+ public static class WriteVmMetadataRsp extends NfsPrimaryStorageAgentResponse {
+ }
+
+
+ public static class GetVmInstanceMetadataCmd extends NfsPrimaryStorageAgentCommand {
+ public String metadataPath;
+ }
+
+ public static class GetVmInstanceMetadataRsp extends NfsPrimaryStorageAgentResponse {
+ public String metadata;
+ }
+
+ public static class ScanVmMetadataCmd extends NfsPrimaryStorageAgentCommand {
+ public String metadataDir;
+ }
+
+ public static class ScanVmMetadataRsp extends NfsPrimaryStorageAgentResponse {
+ public List metadataEntries = new ArrayList<>();
+ }
+
+ public static class CleanupVmMetadataCmd extends NfsPrimaryStorageAgentCommand {
+ public String metadataPath;
+ }
+
+ public static class CleanupVmMetadataRsp extends NfsPrimaryStorageAgentResponse {
+ }
+
+ public static class PrefixRebaseBackingFilesCmd extends NfsPrimaryStorageAgentCommand {
+ public List filePaths;
+ public String oldPrefix;
+ public String newPrefix;
+ }
+
+ public static class PrefixRebaseBackingFilesRsp extends NfsPrimaryStorageAgentResponse {
+ public int rebasedCount;
+ }
}
diff --git a/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java b/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java
new file mode 100644
index 00000000000..6aebb36c005
--- /dev/null
+++ b/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java
@@ -0,0 +1,117 @@
+package org.zstack.storage.primary.nfs;
+
+import org.springframework.beans.factory.annotation.Autowire;
+import org.springframework.beans.factory.annotation.Configurable;
+import org.zstack.core.db.Q;
+import org.zstack.header.exception.CloudRuntimeException;
+import org.zstack.header.storage.primary.PrimaryStorageVO;
+import org.zstack.header.storage.primary.PrimaryStorageVO_;
+import org.zstack.header.vm.metadata.VmInstanceMetadataConstants;
+import org.zstack.header.vm.metadata.VmMetadataPathBuildExtensionPoint;
+import org.zstack.header.vm.metadata.VmMetadataPathReplacementExtensionPoint;
+import org.zstack.utils.Utils;
+import org.zstack.utils.logging.CLogger;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
+public class NfsVmMetadataExtension implements VmMetadataPathBuildExtensionPoint, VmMetadataPathReplacementExtensionPoint {
+ private static final CLogger logger = Utils.getLogger(NfsVmMetadataExtension.class);
+
+ @Override
+ public String getPrimaryStorageType() {
+ return NfsPrimaryStorageConstant.NFS_PRIMARY_STORAGE_TYPE;
+ }
+
+ private String resolveBaseDir(String primaryStorageUuid) {
+ String baseDir = Q.New(PrimaryStorageVO.class).select(PrimaryStorageVO_.mountPath).eq(PrimaryStorageVO_.uuid, primaryStorageUuid).findValue();
+ if (baseDir == null) {
+ baseDir = Q.New(PrimaryStorageVO.class).select(PrimaryStorageVO_.url).eq(PrimaryStorageVO_.uuid, primaryStorageUuid).findValue();
+ }
+ if (baseDir == null) {
+ throw new CloudRuntimeException(String.format("cannot find mountPath or url for NFS primary storage[uuid:%s]", primaryStorageUuid));
+ }
+ return baseDir.endsWith("/") ? baseDir.substring(0, baseDir.length() - 1) : baseDir;
+ }
+
+ @Override
+ public String buildMetadataDir(String primaryStorageUuid) {
+ String baseDir = resolveBaseDir(primaryStorageUuid);
+ return String.format("%s/%s", baseDir, VmInstanceMetadataConstants.METADATA_DIR_NAME);
+ }
+
+ @Override
+ public String buildVmMetadataPath(String primaryStorageUuid, String vmInstanceUuid) {
+ String baseDir = resolveBaseDir(primaryStorageUuid);
+ return String.format("%s/%s/%s%s", baseDir, VmInstanceMetadataConstants.METADATA_DIR_NAME, vmInstanceUuid, VmInstanceMetadataConstants.FILE_METADATA_SUFFIX);
+ }
+
+ @Override
+ public String validateMetadataPath(String primaryStorageUuid, String path) {
+ // Expected format: /.vmmeta
+ // e.g. /mnt/pss/vm-metadata/a1b2c3d4e5f6...vmmeta
+ String metadataDir = buildMetadataDir(primaryStorageUuid);
+ String prefix = metadataDir + "/";
+ String suffix = VmInstanceMetadataConstants.FILE_METADATA_SUFFIX;
+
+ if (!path.startsWith(prefix) || !path.endsWith(suffix)) {
+ return String.format("metadataPath[%s] does not match expected format: %s/%s",
+ path, metadataDir, suffix);
+ }
+
+ String uuidPart = path.substring(prefix.length(), path.length() - suffix.length());
+ if (!uuidPart.matches("[0-9a-f]{32}")) {
+ return String.format("metadataPath[%s] contains invalid uuid[%s], expected 32-char hex", path, uuidPart);
+ }
+ return null;
+ }
+
+ @Override
+ public PathReplacementResult calculatePathReplacements(String targetPsUuid, List allOldPaths) {
+ if (allOldPaths == null || allOldPaths.isEmpty()) {
+ PathReplacementResult result = new PathReplacementResult();
+ result.setMetadataToCurrentPathMap(Collections.emptyMap());
+ return result;
+ }
+
+ String baseDir = Q.New(PrimaryStorageVO.class).select(PrimaryStorageVO_.mountPath).eq(PrimaryStorageVO_.uuid, targetPsUuid).findValue();
+ if (baseDir == null) {
+ baseDir = Q.New(PrimaryStorageVO.class).select(PrimaryStorageVO_.url).eq(PrimaryStorageVO_.uuid, targetPsUuid).findValue();
+ }
+ if (baseDir == null) {
+ logger.warn(String.format("NFS PS[uuid:%s] has no mountPath or url, path replacement disabled", targetPsUuid));
+ PathReplacementResult result = new PathReplacementResult();
+ result.setMetadataToCurrentPathMap(Collections.emptyMap());
+ return result;
+ }
+ String newPrefix = baseDir.endsWith("/") ? baseDir : baseDir + "/";
+
+ // Extract old prefix from the first recognizable path
+ String oldPrefix = null;
+ for (String path : allOldPaths) {
+ oldPrefix = VmInstanceMetadataConstants.extractOldPrefix(path);
+ if (oldPrefix != null) break;
+ }
+
+ Map pathMap = new LinkedHashMap<>();
+ if (oldPrefix != null) {
+ for (String oldPath : allOldPaths) {
+ if (oldPath != null && oldPath.startsWith(oldPrefix)) {
+ pathMap.put(oldPath, newPrefix + oldPath.substring(oldPrefix.length()));
+ }
+ }
+ } else {
+ logger.warn(String.format("cannot extract old path prefix from any path for NFS PS[uuid:%s], " +
+ "path replacement disabled", targetPsUuid));
+ }
+
+ PathReplacementResult result = new PathReplacementResult();
+ result.setMetadataToCurrentPathMap(pathMap);
+ result.setOldPrefix(oldPrefix);
+ result.setNewPrefix(newPrefix);
+ return result;
+ }
+}
diff --git a/resourceconfig/src/main/java/org/zstack/resourceconfig/APIDeleteResourceConfigMsg.java b/resourceconfig/src/main/java/org/zstack/resourceconfig/APIDeleteResourceConfigMsg.java
index fd43d66dac3..7733f7702b0 100644
--- a/resourceconfig/src/main/java/org/zstack/resourceconfig/APIDeleteResourceConfigMsg.java
+++ b/resourceconfig/src/main/java/org/zstack/resourceconfig/APIDeleteResourceConfigMsg.java
@@ -5,11 +5,13 @@
import org.zstack.header.message.APIDeleteMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import org.zstack.header.vo.ResourceVO;
@RestRequest(path = "/resource-configurations/{category}/{name}/{resourceUuid}",
method = HttpMethod.DELETE,
responseClass = APIDeleteResourceConfigEvent.class)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "ResourceUuidToVmUuidResolver", field = "resourceUuid")
public class APIDeleteResourceConfigMsg extends APIDeleteMessage implements ResourceConfigMessage {
@APIParam
private String category;
diff --git a/resourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.java b/resourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.java
index 1b8437d2404..fc30ba61e3b 100644
--- a/resourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.java
+++ b/resourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.java
@@ -5,12 +5,14 @@
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.APIParam;
import org.zstack.header.rest.RestRequest;
+import org.zstack.header.vm.metadata.MetadataImpact;
import org.zstack.header.vo.ResourceVO;
@RestRequest(path = "/resource-configurations/{category}/{name}/{resourceUuid}/actions",
method = HttpMethod.PUT,
isAction = true,
responseClass = APIUpdateResourceConfigEvent.class)
+@MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "ResourceUuidToVmUuidResolver", field = "resourceUuid")
public class APIUpdateResourceConfigMsg extends APIMessage implements ResourceConfigMessage {
@APIParam
private String category;
diff --git a/sdk/src/main/java/SourceClassMap.java b/sdk/src/main/java/SourceClassMap.java
index 146b132c459..fc47060a642 100644
--- a/sdk/src/main/java/SourceClassMap.java
+++ b/sdk/src/main/java/SourceClassMap.java
@@ -247,6 +247,7 @@ public class SourceClassMap {
put("org.zstack.header.storage.primary.PrimaryStorageHostStatus", "org.zstack.sdk.PrimaryStorageHostStatus");
put("org.zstack.header.storage.primary.PrimaryStorageInventory", "org.zstack.sdk.PrimaryStorageInventory");
put("org.zstack.header.storage.primary.UsageReport", "org.zstack.sdk.UsageReport");
+ put("org.zstack.header.storage.primary.VmMetadataScanEntry", "org.zstack.sdk.VmMetadataScanEntry");
put("org.zstack.header.storage.snapshot.BatchDeleteVolumeSnapshotStruct", "org.zstack.sdk.BatchDeleteVolumeSnapshotStruct");
put("org.zstack.header.storage.snapshot.ShrinkResult", "org.zstack.sdk.ShrinkResult");
put("org.zstack.header.storage.snapshot.VolumeSnapshotBackupStorageRefInventory", "org.zstack.sdk.VolumeSnapshotBackupStorageRefInventory");
@@ -1163,6 +1164,7 @@ public class SourceClassMap {
put("org.zstack.sdk.VmInstanceResourceMetadataGroupInventory", "org.zstack.header.vm.devices.VmInstanceResourceMetadataGroupInventory");
put("org.zstack.sdk.VmMemoryBillingInventory", "org.zstack.billing.generator.vm.memory.VmMemoryBillingInventory");
put("org.zstack.sdk.VmMemorySpendingDetails", "org.zstack.billing.spendingcalculator.vm.VmMemorySpendingDetails");
+ put("org.zstack.sdk.VmMetadataScanEntry", "org.zstack.header.storage.primary.VmMetadataScanEntry");
put("org.zstack.sdk.VmNicBandwidthSpendingDetails", "org.zstack.billing.spendingcalculator.vmnic.VmNicBandwidthSpendingDetails");
put("org.zstack.sdk.VmNicConflictEntry", "org.zstack.header.storage.snapshot.group.VmNicConflictEntry");
put("org.zstack.sdk.VmNicInventory", "org.zstack.header.vm.VmNicInventory");
diff --git a/sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.java b/sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.java
new file mode 100644
index 00000000000..46586cab3c4
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.java
@@ -0,0 +1,101 @@
+package org.zstack.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.zstack.sdk.*;
+
+public class CleanupVmInstanceMetadataAction 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.CleanupVmInstanceMetadataResult 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 = true, nullElements = false, emptyString = true, noTrim = false)
+ public java.util.List vmUuids;
+
+ @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.CleanupVmInstanceMetadataResult value = res.getResult(org.zstack.sdk.CleanupVmInstanceMetadataResult.class);
+ ret.value = value == null ? new org.zstack.sdk.CleanupVmInstanceMetadataResult() : 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 = "/vm-instances/metadata/cleanup";
+ info.needSession = true;
+ info.needPoll = true;
+ info.parameterName = "cleanupVmInstanceMetadata";
+ return info;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.java b/sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.java
new file mode 100644
index 00000000000..879a409cc59
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.java
@@ -0,0 +1,30 @@
+package org.zstack.sdk;
+
+
+
+public class CleanupVmInstanceMetadataResult {
+ public java.lang.Integer totalCleaned;
+ public void setTotalCleaned(java.lang.Integer totalCleaned) {
+ this.totalCleaned = totalCleaned;
+ }
+ public java.lang.Integer getTotalCleaned() {
+ return this.totalCleaned;
+ }
+
+ public java.lang.Integer totalFailed;
+ public void setTotalFailed(java.lang.Integer totalFailed) {
+ this.totalFailed = totalFailed;
+ }
+ public java.lang.Integer getTotalFailed() {
+ return this.totalFailed;
+ }
+
+ public java.util.List failedVmUuids;
+ public void setFailedVmUuids(java.util.List failedVmUuids) {
+ this.failedVmUuids = failedVmUuids;
+ }
+ public java.util.List getFailedVmUuids() {
+ return this.failedVmUuids;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageAction.java b/sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageAction.java
new file mode 100644
index 00000000000..a0d62c682a4
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageAction.java
@@ -0,0 +1,101 @@
+package org.zstack.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.zstack.sdk.*;
+
+public class GetVmInstanceMetadataFromPrimaryStorageAction 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.GetVmInstanceMetadataFromPrimaryStorageResult 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.GetVmInstanceMetadataFromPrimaryStorageResult value = res.getResult(org.zstack.sdk.GetVmInstanceMetadataFromPrimaryStorageResult.class);
+ ret.value = value == null ? new org.zstack.sdk.GetVmInstanceMetadataFromPrimaryStorageResult() : 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/vm-instances/metadata";
+ info.needSession = true;
+ info.needPoll = true;
+ info.parameterName = "";
+ return info;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageResult.java b/sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageResult.java
new file mode 100644
index 00000000000..d22099fae76
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageResult.java
@@ -0,0 +1,14 @@
+package org.zstack.sdk;
+
+
+
+public class GetVmInstanceMetadataFromPrimaryStorageResult {
+ public java.lang.String metadata;
+ public void setMetadata(java.lang.String metadata) {
+ this.metadata = metadata;
+ }
+ public java.lang.String getMetadata() {
+ return this.metadata;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataAction.java b/sdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataAction.java
new file mode 100644
index 00000000000..8af44d58133
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataAction.java
@@ -0,0 +1,116 @@
+package org.zstack.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.zstack.sdk.*;
+
+public class RegisterVmInstanceFromMetadataAction 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.RegisterVmInstanceFromMetadataResult 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, maxLength = 2048, nonempty = true, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String metadataPath;
+
+ @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String primaryStorageUuid;
+
+ @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String zoneUuid;
+
+ @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String clusterUuid;
+
+ @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String hostUuid;
+
+ @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
+ public java.lang.String name;
+
+ @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.RegisterVmInstanceFromMetadataResult value = res.getResult(org.zstack.sdk.RegisterVmInstanceFromMetadataResult.class);
+ ret.value = value == null ? new org.zstack.sdk.RegisterVmInstanceFromMetadataResult() : 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 = "POST";
+ info.path = "/vm-instances/metadata/register";
+ info.needSession = true;
+ info.needPoll = true;
+ info.parameterName = "params";
+ return info;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataResult.java b/sdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataResult.java
new file mode 100644
index 00000000000..11634dcf3f1
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataResult.java
@@ -0,0 +1,14 @@
+package org.zstack.sdk;
+
+import org.zstack.sdk.VmInstanceInventory;
+
+public class RegisterVmInstanceFromMetadataResult {
+ public VmInstanceInventory inventory;
+ public void setInventory(VmInstanceInventory inventory) {
+ this.inventory = inventory;
+ }
+ public VmInstanceInventory getInventory() {
+ return this.inventory;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageAction.java b/sdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageAction.java
new file mode 100644
index 00000000000..bdb11d011bc
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageAction.java
@@ -0,0 +1,101 @@
+package org.zstack.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.zstack.sdk.*;
+
+public class ScanVmInstanceMetadataFromPrimaryStorageAction 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.ScanVmInstanceMetadataFromPrimaryStorageResult 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.ScanVmInstanceMetadataFromPrimaryStorageResult value = res.getResult(org.zstack.sdk.ScanVmInstanceMetadataFromPrimaryStorageResult.class);
+ ret.value = value == null ? new org.zstack.sdk.ScanVmInstanceMetadataFromPrimaryStorageResult() : 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/vm-instances/metadata/scan";
+ info.needSession = true;
+ info.needPoll = true;
+ info.parameterName = "";
+ return info;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageResult.java b/sdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageResult.java
new file mode 100644
index 00000000000..4abb18ceae6
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageResult.java
@@ -0,0 +1,14 @@
+package org.zstack.sdk;
+
+
+
+public class ScanVmInstanceMetadataFromPrimaryStorageResult {
+ public java.util.List vmInstanceMetadata;
+ public void setVmInstanceMetadata(java.util.List vmInstanceMetadata) {
+ this.vmInstanceMetadata = vmInstanceMetadata;
+ }
+ public java.util.List getVmInstanceMetadata() {
+ return this.vmInstanceMetadata;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataAction.java b/sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataAction.java
new file mode 100644
index 00000000000..2f2620e38e2
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataAction.java
@@ -0,0 +1,101 @@
+package org.zstack.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.zstack.sdk.*;
+
+public class UpdateVmInstanceMetadataAction 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.UpdateVmInstanceMetadataResult 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 = true, nullElements = false, emptyString = true, noTrim = false)
+ public java.util.List vmUuids;
+
+ @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.UpdateVmInstanceMetadataResult value = res.getResult(org.zstack.sdk.UpdateVmInstanceMetadataResult.class);
+ ret.value = value == null ? new org.zstack.sdk.UpdateVmInstanceMetadataResult() : 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 = "/vm-instances/metadata/actions";
+ info.needSession = true;
+ info.needPoll = true;
+ info.parameterName = "updateVmInstanceMetadata";
+ return info;
+ }
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataResult.java b/sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataResult.java
new file mode 100644
index 00000000000..d09f1fe7bf7
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataResult.java
@@ -0,0 +1,7 @@
+package org.zstack.sdk;
+
+
+
+public class UpdateVmInstanceMetadataResult {
+
+}
diff --git a/sdk/src/main/java/org/zstack/sdk/VmMetadataScanEntry.java b/sdk/src/main/java/org/zstack/sdk/VmMetadataScanEntry.java
new file mode 100644
index 00000000000..fc5fc13f644
--- /dev/null
+++ b/sdk/src/main/java/org/zstack/sdk/VmMetadataScanEntry.java
@@ -0,0 +1,87 @@
+package org.zstack.sdk;
+
+
+
+public class VmMetadataScanEntry {
+
+ public java.lang.String vmUuid;
+ public void setVmUuid(java.lang.String vmUuid) {
+ this.vmUuid = vmUuid;
+ }
+ public java.lang.String getVmUuid() {
+ return this.vmUuid;
+ }
+
+ public java.lang.String vmName;
+ public void setVmName(java.lang.String vmName) {
+ this.vmName = vmName;
+ }
+ public java.lang.String getVmName() {
+ return this.vmName;
+ }
+
+ public java.lang.String vmCategory;
+ public void setVmCategory(java.lang.String vmCategory) {
+ this.vmCategory = vmCategory;
+ }
+ public java.lang.String getVmCategory() {
+ return this.vmCategory;
+ }
+
+ public java.lang.String architecture;
+ public void setArchitecture(java.lang.String architecture) {
+ this.architecture = architecture;
+ }
+ public java.lang.String getArchitecture() {
+ return this.architecture;
+ }
+
+ public java.lang.String schemaVersion;
+ public void setSchemaVersion(java.lang.String schemaVersion) {
+ this.schemaVersion = schemaVersion;
+ }
+ public java.lang.String getSchemaVersion() {
+ return this.schemaVersion;
+ }
+
+ public java.lang.String metadataPath;
+ public void setMetadataPath(java.lang.String metadataPath) {
+ this.metadataPath = metadataPath;
+ }
+ public java.lang.String getMetadataPath() {
+ return this.metadataPath;
+ }
+
+ public java.lang.String hostUuid;
+ public void setHostUuid(java.lang.String hostUuid) {
+ this.hostUuid = hostUuid;
+ }
+ public java.lang.String getHostUuid() {
+ return this.hostUuid;
+ }
+
+ public long sizeBytes;
+ public void setSizeBytes(long sizeBytes) {
+ this.sizeBytes = sizeBytes;
+ }
+ public long getSizeBytes() {
+ return this.sizeBytes;
+ }
+
+ public long lastUpdateTime;
+ public void setLastUpdateTime(long lastUpdateTime) {
+ this.lastUpdateTime = lastUpdateTime;
+ }
+ public long getLastUpdateTime() {
+ return this.lastUpdateTime;
+ }
+
+ public boolean incomplete;
+ public void setIncomplete(boolean incomplete) {
+ this.incomplete = incomplete;
+ }
+ public boolean getIncomplete() {
+ return this.incomplete;
+ }
+
+}
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..d31026b7014 100755
--- a/storage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.java
+++ b/storage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.java
@@ -6,6 +6,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.transaction.annotation.Transactional;
+import org.zstack.core.Platform;
import org.zstack.core.asyncbatch.While;
import org.zstack.core.cascade.CascadeConstant;
import org.zstack.core.cascade.CascadeFacade;
@@ -50,6 +51,7 @@
import org.zstack.header.storage.primary.PrimaryStorageCanonicalEvent.PrimaryStorageStatusChangedData;
import org.zstack.header.storage.snapshot.*;
import org.zstack.header.vm.*;
+import org.zstack.header.vm.metadata.*;
import org.zstack.header.volume.*;
import org.zstack.storage.volume.VolumeUtils;
import org.zstack.utils.CollectionDSL;
@@ -417,6 +419,16 @@ protected void handleLocalMessage(Message msg) {
handle((DeleteVolumeChainOnPrimaryStorageMsg) msg);
} else if (msg instanceof CleanUpStorageTrashOnPrimaryStorageMsg) {
handle((CleanUpStorageTrashOnPrimaryStorageMsg)msg);
+ } else if (msg instanceof UpdateVmInstanceMetadataOnPrimaryStorageMsg) {
+ handle((UpdateVmInstanceMetadataOnPrimaryStorageMsg) msg);
+ } else if (msg instanceof ScanVmInstanceMetadataFromPrimaryStorageMsg) {
+ handle((ScanVmInstanceMetadataFromPrimaryStorageMsg) msg);
+ } else if (msg instanceof GetVmInstanceMetadataFromPrimaryStorageMsg) {
+ handle((GetVmInstanceMetadataFromPrimaryStorageMsg) msg);
+ } else if (msg instanceof CleanupVmInstanceMetadataOnPrimaryStorageMsg) {
+ handle((CleanupVmInstanceMetadataOnPrimaryStorageMsg) msg);
+ } else if (msg instanceof RebaseVolumeBackingFileOnPrimaryStorageMsg) {
+ handle((RebaseVolumeBackingFileOnPrimaryStorageMsg) msg);
} else {
bus.dealWithUnknownMessage(msg);
}
@@ -935,6 +947,8 @@ protected void handleApiMessage(APIMessage msg) {
handle((APICleanUpStorageTrashOnPrimaryStorageMsg) msg);
} else if (msg instanceof APIAddStorageProtocolMsg) {
handle((APIAddStorageProtocolMsg) msg);
+ } else if (msg instanceof APIScanVmInstanceMetadataFromPrimaryStorageMsg) {
+ handle((APIScanVmInstanceMetadataFromPrimaryStorageMsg) msg);
} else {
bus.dealWithUnknownMessage(msg);
}
@@ -1773,6 +1787,36 @@ protected void handle(UnlinkBitsOnPrimaryStorageMsg msg) {
bus.reply(msg, reply);
};
+ protected void handle(UpdateVmInstanceMetadataOnPrimaryStorageMsg msg) {
+ UpdateVmInstanceMetadataOnPrimaryStorageReply reply = new UpdateVmInstanceMetadataOnPrimaryStorageReply();
+ reply.setError(operr("operation not supported"));
+ bus.reply(msg, reply);
+ }
+
+ protected void handle(GetVmInstanceMetadataFromPrimaryStorageMsg msg) {
+ GetVmInstanceMetadataFromPrimaryStorageReply reply = new GetVmInstanceMetadataFromPrimaryStorageReply();
+ reply.setError(operr("operation not supported"));
+ bus.reply(msg, reply);
+ }
+
+ protected void handle(ScanVmInstanceMetadataFromPrimaryStorageMsg msg) {
+ ScanVmInstanceMetadataFromPrimaryStorageReply reply = new ScanVmInstanceMetadataFromPrimaryStorageReply();
+ reply.setError(operr("operation not supported"));
+ bus.reply(msg, reply);
+ }
+
+ protected void handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg msg) {
+ CleanupVmInstanceMetadataOnPrimaryStorageReply reply = new CleanupVmInstanceMetadataOnPrimaryStorageReply();
+ 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"));
+ bus.reply(msg, reply);
+ }
+
// don't attach any cluster
public boolean isUnmounted() {
long count = Q.New(PrimaryStorageClusterRefVO.class)
@@ -1812,4 +1856,42 @@ protected ImageCacheVO createTemporaryImageCacheFromVolumeSnapshot(ImageInventor
private static String getDeduplicateError(String operationName) {
return String.format("an other %s task is running, cancel this operation", operationName);
}
+
+ private void handle(APIScanVmInstanceMetadataFromPrimaryStorageMsg msg) {
+ APIScanVmInstanceMetadataFromPrimaryStorageEvent evt = new APIScanVmInstanceMetadataFromPrimaryStorageEvent(msg.getId());
+
+ String psType = Q.New(PrimaryStorageVO.class).select(PrimaryStorageVO_.type).eq(PrimaryStorageVO_.uuid, msg.getPrimaryStorageUuid()).findValue();
+ VmMetadataPathBuildExtensionPoint ext = pluginRgty.getExtensionFromMap(psType, VmMetadataPathBuildExtensionPoint.class);
+ if (ext == null) {
+ evt.setError(Platform.operr("primary storage type %s does not support metadata", psType));
+ bus.publish(evt);
+ return;
+ }
+ String metadataDir = ext.buildMetadataDir(msg.getPrimaryStorageUuid());
+
+ ScanVmInstanceMetadataFromPrimaryStorageMsg gmsg = new ScanVmInstanceMetadataFromPrimaryStorageMsg();
+ gmsg.setPrimaryStorageUuid(msg.getPrimaryStorageUuid());
+ gmsg.setMetadataDir(metadataDir);
+ bus.makeTargetServiceIdByResourceUuid(gmsg, PrimaryStorageConstant.SERVICE_ID, msg.getPrimaryStorageUuid());
+ bus.send(gmsg, new CloudBusCallBack(msg) {
+ @Override
+ public void run(MessageReply r) {
+ if (!r.isSuccess()) {
+ evt.setError(r.getError());
+ bus.publish(evt);
+ return;
+ }
+ ScanVmInstanceMetadataFromPrimaryStorageReply re = r.castReply();
+ List metadata = re.getVmInstanceMetadata();
+ if (metadata == null) {
+ metadata = Collections.emptyList();
+ }
+ List filtered = metadata.stream()
+ .filter(e -> !VmMetadataCategory.VM_TEMPLATE_CACHE.name().equals(e.getVmCategory()))
+ .collect(Collectors.toList());
+ evt.setVmInstanceMetadata(filtered);
+ bus.publish(evt);
+ }
+ });
+ }
}
diff --git a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
index 07c05b73b9e..91aca4c069e 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 cleanupVmInstanceMetadata(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.CleanupVmInstanceMetadataAction.class) Closure c) {
+ def a = new org.zstack.sdk.CleanupVmInstanceMetadataAction()
+ 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 cloneVmInstance(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.CloneVmInstanceAction.class) Closure c) {
def a = new org.zstack.sdk.CloneVmInstanceAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
@@ -6929,33 +6956,6 @@ abstract class ApiHelper {
}
- def updateHostname(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UpdateHostnameAction.class) Closure c) {
- def a = new org.zstack.sdk.UpdateHostnameAction()
- 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 createIPsecConnection(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.CreateIPsecConnectionAction.class) Closure c) {
def a = new org.zstack.sdk.CreateIPsecConnectionAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
@@ -18566,6 +18566,33 @@ abstract class ApiHelper {
}
+ def getVmInstanceMetadataFromPrimaryStorage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.GetVmInstanceMetadataFromPrimaryStorageAction.class) Closure c) {
+ def a = new org.zstack.sdk.GetVmInstanceMetadataFromPrimaryStorageAction()
+ 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 getVmInstanceProtectedRecoveryPoints(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.GetVmInstanceProtectedRecoveryPointsAction.class) Closure c) {
def a = new org.zstack.sdk.GetVmInstanceProtectedRecoveryPointsAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
@@ -27406,6 +27433,33 @@ abstract class ApiHelper {
}
+ def registerVmInstanceFromMetadata(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.RegisterVmInstanceFromMetadataAction.class) Closure c) {
+ def a = new org.zstack.sdk.RegisterVmInstanceFromMetadataAction()
+ 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 reimageVmInstance(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ReimageVmInstanceAction.class) Closure c) {
def a = new org.zstack.sdk.ReimageVmInstanceAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
@@ -28621,6 +28675,33 @@ abstract class ApiHelper {
}
+ def scanVmInstanceMetadataFromPrimaryStorage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ScanVmInstanceMetadataFromPrimaryStorageAction.class) Closure c) {
+ def a = new org.zstack.sdk.ScanVmInstanceMetadataFromPrimaryStorageAction()
+ 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 securityMachineDetectSync(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.SecurityMachineDetectSyncAction.class) Closure c) {
def a = new org.zstack.sdk.SecurityMachineDetectSyncAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
@@ -32212,6 +32293,33 @@ abstract class ApiHelper {
}
+ def updateHostname(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UpdateHostnameAction.class) Closure c) {
+ def a = new org.zstack.sdk.UpdateHostnameAction()
+ 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 updateIPsecConnection(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UpdateIPsecConnectionAction.class) Closure c) {
def a = new org.zstack.sdk.UpdateIPsecConnectionAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
@@ -34183,6 +34291,33 @@ abstract class ApiHelper {
}
+ def updateVmInstanceMetadata(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UpdateVmInstanceMetadataAction.class) Closure c) {
+ def a = new org.zstack.sdk.UpdateVmInstanceMetadataAction()
+ 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 updateVmNicDriver(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UpdateVmNicDriverAction.class) Closure c) {
def a = new org.zstack.sdk.UpdateVmNicDriverAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
@@ -38395,8 +38530,8 @@ abstract class ApiHelper {
}
- def addZBox(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.zbox.AddZBoxAction.class) Closure c) {
- def a = new org.zstack.sdk.zbox.AddZBoxAction()
+ def cleanSoftwarePackage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.softwarePackage.header.CleanSoftwarePackageAction.class) Closure c) {
+ def a = new org.zstack.sdk.softwarePackage.header.CleanSoftwarePackageAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
c.resolveStrategy = Closure.OWNER_FIRST
c.delegate = a
@@ -38422,8 +38557,8 @@ abstract class ApiHelper {
}
- def createZBoxBackup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.zbox.CreateZBoxBackupAction.class) Closure c) {
- def a = new org.zstack.sdk.zbox.CreateZBoxBackupAction()
+ def getDirectoryUsage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.softwarePackage.header.GetDirectoryUsageAction.class) Closure c) {
+ def a = new org.zstack.sdk.softwarePackage.header.GetDirectoryUsageAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
c.resolveStrategy = Closure.OWNER_FIRST
c.delegate = a
@@ -38449,8 +38584,8 @@ abstract class ApiHelper {
}
- def ejectZBox(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.zbox.EjectZBoxAction.class) Closure c) {
- def a = new org.zstack.sdk.zbox.EjectZBoxAction()
+ def getUploadSoftwarePackageJobDetails(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.softwarePackage.header.GetUploadSoftwarePackageJobDetailsAction.class) Closure c) {
+ def a = new org.zstack.sdk.softwarePackage.header.GetUploadSoftwarePackageJobDetailsAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
c.resolveStrategy = Closure.OWNER_FIRST
c.delegate = a
@@ -38476,8 +38611,8 @@ abstract class ApiHelper {
}
- def getZBoxBackupDetails(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.zbox.GetZBoxBackupDetailsAction.class) Closure c) {
- def a = new org.zstack.sdk.zbox.GetZBoxBackupDetailsAction()
+ def installSoftwarePackage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.softwarePackage.header.InstallSoftwarePackageAction.class) Closure c) {
+ def a = new org.zstack.sdk.softwarePackage.header.InstallSoftwarePackageAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
c.resolveStrategy = Closure.OWNER_FIRST
c.delegate = a
@@ -38503,8 +38638,8 @@ abstract class ApiHelper {
}
- def queryZBox(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.zbox.QueryZBoxAction.class) Closure c) {
- def a = new org.zstack.sdk.zbox.QueryZBoxAction()
+ def querySoftwarePackage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.softwarePackage.header.QuerySoftwarePackageAction.class) Closure c) {
+ def a = new org.zstack.sdk.softwarePackage.header.QuerySoftwarePackageAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
c.resolveStrategy = Closure.OWNER_FIRST
c.delegate = a
@@ -38532,15 +38667,13 @@ abstract class ApiHelper {
}
- def queryZBoxBackup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.zbox.QueryZBoxBackupAction.class) Closure c) {
- def a = new org.zstack.sdk.zbox.QueryZBoxBackupAction()
+ def uninstallSoftwarePackage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.softwarePackage.header.UninstallSoftwarePackageAction.class) Closure c) {
+ def a = new org.zstack.sdk.softwarePackage.header.UninstallSoftwarePackageAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
c.resolveStrategy = Closure.OWNER_FIRST
c.delegate = a
c()
- a.conditions = a.conditions.collect { it.toString() }
-
if (System.getProperty("apipath") != null) {
if (a.apiId == null) {
@@ -38561,8 +38694,8 @@ abstract class ApiHelper {
}
- def syncZBoxCapacity(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.zbox.SyncZBoxCapacityAction.class) Closure c) {
- def a = new org.zstack.sdk.zbox.SyncZBoxCapacityAction()
+ def uploadSoftwarePackage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.softwarePackage.header.UploadSoftwarePackageAction.class) Closure c) {
+ def a = new org.zstack.sdk.softwarePackage.header.UploadSoftwarePackageAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
c.resolveStrategy = Closure.OWNER_FIRST
c.delegate = a
@@ -38588,25 +38721,26 @@ abstract class ApiHelper {
}
- def cleanSoftwarePackage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.softwarePackage.header.CleanSoftwarePackageAction.class) Closure c) {
- def a = new org.zstack.sdk.softwarePackage.header.CleanSoftwarePackageAction()
+ def addZBox(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.zbox.AddZBoxAction.class) Closure c) {
+ def a = new org.zstack.sdk.zbox.AddZBoxAction()
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())
@@ -38614,25 +38748,26 @@ abstract class ApiHelper {
}
- def getDirectoryUsage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.softwarePackage.header.GetDirectoryUsageAction.class) Closure c) {
- def a = new org.zstack.sdk.softwarePackage.header.GetDirectoryUsageAction()
+ def createZBoxBackup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.zbox.CreateZBoxBackupAction.class) Closure c) {
+ def a = new org.zstack.sdk.zbox.CreateZBoxBackupAction()
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())
@@ -38640,25 +38775,26 @@ abstract class ApiHelper {
}
- def getUploadSoftwarePackageJobDetails(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.softwarePackage.header.GetUploadSoftwarePackageJobDetailsAction.class) Closure c) {
- def a = new org.zstack.sdk.softwarePackage.header.GetUploadSoftwarePackageJobDetailsAction()
+ def ejectZBox(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.zbox.EjectZBoxAction.class) Closure c) {
+ def a = new org.zstack.sdk.zbox.EjectZBoxAction()
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())
@@ -38666,22 +38802,26 @@ abstract class ApiHelper {
}
- def installSoftwarePackage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.softwarePackage.header.InstallSoftwarePackageAction.class) Closure c) {
- def a = new org.zstack.sdk.softwarePackage.header.InstallSoftwarePackageAction()
+ def getZBoxBackupDetails(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.zbox.GetZBoxBackupDetailsAction.class) Closure c) {
+ def a = new org.zstack.sdk.zbox.GetZBoxBackupDetailsAction()
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())
@@ -38689,13 +38829,13 @@ abstract class ApiHelper {
}
- def querySoftwarePackage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.softwarePackage.header.QuerySoftwarePackageAction.class) Closure c) {
- def a = new org.zstack.sdk.softwarePackage.header.QuerySoftwarePackageAction()
+ def queryZBox(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.zbox.QueryZBoxAction.class) Closure c) {
+ def a = new org.zstack.sdk.zbox.QueryZBoxAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
c.resolveStrategy = Closure.OWNER_FIRST
c.delegate = a
c()
-
+
a.conditions = a.conditions.collect { it.toString() }
@@ -38703,14 +38843,14 @@ abstract class ApiHelper {
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())
@@ -38718,26 +38858,28 @@ abstract class ApiHelper {
}
- def uninstallSoftwarePackage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.softwarePackage.header.UninstallSoftwarePackageAction.class) Closure c) {
- def a = new org.zstack.sdk.softwarePackage.header.UninstallSoftwarePackageAction()
+ def queryZBoxBackup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.zbox.QueryZBoxBackupAction.class) Closure c) {
+ def a = new org.zstack.sdk.zbox.QueryZBoxBackupAction()
a.sessionId = Test.currentEnvSpec?.session?.uuid
c.resolveStrategy = Closure.OWNER_FIRST
c.delegate = a
c()
+
+ a.conditions = a.conditions.collect { it.toString() }
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())
@@ -38745,25 +38887,26 @@ abstract class ApiHelper {
}
- def uploadSoftwarePackage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.softwarePackage.header.UploadSoftwarePackageAction.class) Closure c) {
- def a = new org.zstack.sdk.softwarePackage.header.UploadSoftwarePackageAction()
+ def syncZBoxCapacity(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.zbox.SyncZBoxCapacityAction.class) Closure c) {
+ def a = new org.zstack.sdk.zbox.SyncZBoxCapacityAction()
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())
diff --git a/testlib/src/main/java/org/zstack/testlib/LocalStorageSpec.groovy b/testlib/src/main/java/org/zstack/testlib/LocalStorageSpec.groovy
index 747ca4388b1..c7143282f6b 100755
--- a/testlib/src/main/java/org/zstack/testlib/LocalStorageSpec.groovy
+++ b/testlib/src/main/java/org/zstack/testlib/LocalStorageSpec.groovy
@@ -600,6 +600,22 @@ class LocalStorageSpec extends PrimaryStorageSpec {
rsp.hashValue = cmd.installPath
return rsp
}
+
+ simulator(LocalStorageKvmBackend.WRITE_VM_METADATA_PATH) {
+ return new LocalStorageKvmBackend.WriteVmMetadataRsp()
+ }
+
+ simulator(LocalStorageKvmBackend.GET_VM_INSTANCE_METADATA_PATH) {
+ return new LocalStorageKvmBackend.GetVmInstanceMetadataRsp()
+ }
+
+ simulator(LocalStorageKvmBackend.SCAN_VM_METADATA_PATH) {
+ return new LocalStorageKvmBackend.ScanVmMetadataRsp()
+ }
+
+ simulator(LocalStorageKvmBackend.CLEANUP_VM_METADATA_PATH) {
+ return new LocalStorageKvmBackend.CleanupVmMetadataRsp()
+ }
}
}
diff --git a/testlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy b/testlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy
index 0dbe59bfc01..09344d42a5c 100755
--- a/testlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy
+++ b/testlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy
@@ -522,6 +522,22 @@ class NfsPrimaryStorageSpec extends PrimaryStorageSpec {
return rsp
}
+ simulator(NfsPrimaryStorageKVMBackend.WRITE_VM_METADATA_PATH) {
+ return new NfsPrimaryStorageKVMBackendCommands.WriteVmMetadataRsp()
+ }
+
+ simulator(NfsPrimaryStorageKVMBackend.GET_VM_INSTANCE_METADATA_PATH) {
+ return new NfsPrimaryStorageKVMBackendCommands.GetVmInstanceMetadataRsp()
+ }
+
+ simulator(NfsPrimaryStorageKVMBackend.SCAN_VM_METADATA_PATH) {
+ return new NfsPrimaryStorageKVMBackendCommands.ScanVmMetadataRsp()
+ }
+
+ simulator(NfsPrimaryStorageKVMBackend.CLEANUP_VM_METADATA_PATH) {
+ return new NfsPrimaryStorageKVMBackendCommands.CleanupVmMetadataRsp()
+ }
+
VFS.vfsHook(NfsPrimaryStorageKVMBackend.NFS_REBASE_VOLUME_BACKING_FILE_PATH, xspec) { rsp, HttpEntity e, EnvSpec spec ->
def cmd = JSONObjectUtil.toObject(e.body, NfsPrimaryStorageKVMBackendCommands.NfsRebaseVolumeBackingFileCmd.class)