+ 3005
+ The remote license has expired
+
+
+
+ 3006
+ The remote license expires earlier than the local license
+
+
+
+ 3007
+ The remote license available capacity is lower than the local license
+
+
3100
License server generic error
diff --git a/conf/globalConfig/ceph.xml b/conf/globalConfig/ceph.xml
index be1993a594..ccde2ee280 100755
--- a/conf/globalConfig/ceph.xml
+++ b/conf/globalConfig/ceph.xml
@@ -107,7 +107,7 @@
sds.admin.password
the password of ceph admin user
- password
+ Admin@123
ceph
java.lang.String
diff --git a/conf/persistence.xml b/conf/persistence.xml
index 33f4326f40..30c36210dd 100755
--- a/conf/persistence.xml
+++ b/conf/persistence.xml
@@ -139,6 +139,7 @@
org.zstack.storage.primary.local.LocalStorageResourceRefVO
org.zstack.storage.primary.local.LocalStorageHostRefVO
org.zstack.header.storage.addon.primary.ExternalPrimaryStorageVO
+ org.zstack.header.storage.addon.primary.ExternalPrimaryStorageSpaceVO
org.zstack.header.storage.addon.primary.PrimaryStorageOutputProtocolRefVO
org.zstack.header.storage.addon.primary.ExternalPrimaryStorageHostRefVO
org.zstack.storage.ceph.backup.CephBackupStorageVO
diff --git a/conf/serviceConfig/vmInstance.xml b/conf/serviceConfig/vmInstance.xml
index 81a683490e..e24559a05c 100755
--- a/conf/serviceConfig/vmInstance.xml
+++ b/conf/serviceConfig/vmInstance.xml
@@ -117,6 +117,9 @@
org.zstack.header.vm.APISetVmConsolePasswordMsg
+
+ org.zstack.header.vm.APIUpdateConsolePasswordMsg
+
org.zstack.header.vm.APIGetVmConsoleAddressMsg
diff --git a/conf/springConfigXml/ExternalPrimaryStorage.xml b/conf/springConfigXml/ExternalPrimaryStorage.xml
index f0b5f60289..60c3ed6115 100644
--- a/conf/springConfigXml/ExternalPrimaryStorage.xml
+++ b/conf/springConfigXml/ExternalPrimaryStorage.xml
@@ -25,10 +25,13 @@
+
+
+
@@ -44,6 +47,13 @@
+
+
+
+
+
+
+
@@ -52,10 +62,4 @@
-
-
-
-
-
-
diff --git a/conf/springConfigXml/cbd.xml b/conf/springConfigXml/cbd.xml
index 1582b32551..fc95b60b6b 100644
--- a/conf/springConfigXml/cbd.xml
+++ b/conf/springConfigXml/cbd.xml
@@ -16,6 +16,10 @@
+
+
+
+
diff --git a/conf/springConfigXml/vyos.xml b/conf/springConfigXml/vyos.xml
index 30a2ecbf07..0793d44131 100755
--- a/conf/springConfigXml/vyos.xml
+++ b/conf/springConfigXml/vyos.xml
@@ -125,6 +125,7 @@
+
diff --git a/conf/springConfigXml/zbs.xml b/conf/springConfigXml/zbs.xml
index 4ef20cc35c..2e0234ddc1 100644
--- a/conf/springConfigXml/zbs.xml
+++ b/conf/springConfigXml/zbs.xml
@@ -21,7 +21,6 @@
-
diff --git a/conf/zstack.xml b/conf/zstack.xml
index ed752bf46b..5a5dbc3e24 100755
--- a/conf/zstack.xml
+++ b/conf/zstack.xml
@@ -120,4 +120,5 @@
+
diff --git a/header/src/main/java/org/zstack/header/message/NeedReplyMessage.java b/header/src/main/java/org/zstack/header/message/NeedReplyMessage.java
index 20aa942729..c873b03b04 100755
--- a/header/src/main/java/org/zstack/header/message/NeedReplyMessage.java
+++ b/header/src/main/java/org/zstack/header/message/NeedReplyMessage.java
@@ -24,6 +24,11 @@ public List getSystemTags() {
return systemTags;
}
+ public String getSystemTag(Predicate isMatch) {
+ return systemTags == null ? null :
+ systemTags.stream().filter(isMatch).findFirst().orElse(null);
+ }
+
public void setSystemTags(List systemTags) {
this.systemTags = systemTags;
}
diff --git a/header/src/main/java/org/zstack/header/network/l3/L3NetworkUpdateExtensionPoint.java b/header/src/main/java/org/zstack/header/network/l3/L3NetworkUpdateExtensionPoint.java
deleted file mode 100644
index 6699c0b002..0000000000
--- a/header/src/main/java/org/zstack/header/network/l3/L3NetworkUpdateExtensionPoint.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package org.zstack.header.network.l3;
-
-public interface L3NetworkUpdateExtensionPoint {
- void updateL3NetworkMtu(L3NetworkInventory inventory);
-}
diff --git a/header/src/main/java/org/zstack/header/network/l3/SdnControllerDisableDHCPMsg.java b/header/src/main/java/org/zstack/header/network/l3/SdnControllerDisableDHCPMsg.java
new file mode 100644
index 0000000000..7d0e0c9dcb
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/network/l3/SdnControllerDisableDHCPMsg.java
@@ -0,0 +1,46 @@
+package org.zstack.header.network.l3;
+
+import org.zstack.header.message.NeedReplyMessage;
+import org.zstack.header.network.sdncontroller.SdnControllerMessage;
+import org.zstack.utils.network.IPv6Constants;
+
+public class SdnControllerDisableDHCPMsg extends NeedReplyMessage implements SdnControllerMessage {
+ private String l3NetworkUuid;
+ private Integer ipVersion = IPv6Constants.DUAL_STACK;
+ private String sdnControllerUuid;
+ private boolean checkIpRange = false;
+
+ public Integer getIpVersion() {
+ return ipVersion;
+ }
+
+ public void setIpVersion(Integer ipVersion) {
+ this.ipVersion = ipVersion;
+ }
+
+ public String getL3NetworkUuid() {
+ return l3NetworkUuid;
+ }
+
+ public void setL3NetworkUuid(String l3NetworkUuid) {
+ this.l3NetworkUuid = l3NetworkUuid;
+ }
+
+ @Override
+ public String getSdnControllerUuid() {
+ return sdnControllerUuid;
+ }
+
+ public void setSdnControllerUuid(String sdnControllerUuid) {
+ this.sdnControllerUuid = sdnControllerUuid;
+ }
+
+ public boolean isCheckIpRange() {
+ return checkIpRange;
+ }
+
+ public void setCheckIpRange(boolean checkIpRange) {
+ this.checkIpRange = checkIpRange;
+ }
+}
+
diff --git a/header/src/main/java/org/zstack/header/network/l3/SdnControllerDisableDHCPReply.java b/header/src/main/java/org/zstack/header/network/l3/SdnControllerDisableDHCPReply.java
new file mode 100644
index 0000000000..990833e6a7
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/network/l3/SdnControllerDisableDHCPReply.java
@@ -0,0 +1,6 @@
+package org.zstack.header.network.l3;
+
+import org.zstack.header.message.MessageReply;
+
+public class SdnControllerDisableDHCPReply extends MessageReply {
+}
diff --git a/header/src/main/java/org/zstack/header/network/l3/SdnControllerEnableDHCPMsg.java b/header/src/main/java/org/zstack/header/network/l3/SdnControllerEnableDHCPMsg.java
new file mode 100644
index 0000000000..ade67404bd
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/network/l3/SdnControllerEnableDHCPMsg.java
@@ -0,0 +1,26 @@
+package org.zstack.header.network.l3;
+
+import org.zstack.header.message.NeedReplyMessage;
+import org.zstack.header.network.sdncontroller.SdnControllerMessage;
+
+public class SdnControllerEnableDHCPMsg extends NeedReplyMessage implements SdnControllerMessage {
+ private String l3NetworkUuid;
+ private String sdnControllerUuid;
+
+ public String getL3NetworkUuid() {
+ return l3NetworkUuid;
+ }
+
+ public void setL3NetworkUuid(String l3NetworkUuid) {
+ this.l3NetworkUuid = l3NetworkUuid;
+ }
+
+ @Override
+ public String getSdnControllerUuid() {
+ return sdnControllerUuid;
+ }
+
+ public void setSdnControllerUuid(String sdnControllerUuid) {
+ this.sdnControllerUuid = sdnControllerUuid;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/network/l3/SdnControllerEnableDHCPReply.java b/header/src/main/java/org/zstack/header/network/l3/SdnControllerEnableDHCPReply.java
new file mode 100644
index 0000000000..15cf0701b0
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/network/l3/SdnControllerEnableDHCPReply.java
@@ -0,0 +1,6 @@
+package org.zstack.header.network.l3;
+
+import org.zstack.header.message.MessageReply;
+
+public class SdnControllerEnableDHCPReply extends MessageReply {
+}
diff --git a/header/src/main/java/org/zstack/header/network/l3/SdnControllerUpdateDHCPMsg.java b/header/src/main/java/org/zstack/header/network/l3/SdnControllerUpdateDHCPMsg.java
new file mode 100644
index 0000000000..3cc193a7d2
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/network/l3/SdnControllerUpdateDHCPMsg.java
@@ -0,0 +1,37 @@
+package org.zstack.header.network.l3;
+
+import org.zstack.header.message.NeedReplyMessage;
+import org.zstack.header.network.sdncontroller.SdnControllerMessage;
+import org.zstack.utils.network.IPv6Constants;
+
+public class SdnControllerUpdateDHCPMsg extends NeedReplyMessage implements SdnControllerMessage {
+ private String l3NetworkUuid;
+ private String sdnControllerUuid;
+ private Integer ipVersion = IPv6Constants.DUAL_STACK;
+
+ @Override
+ public String getSdnControllerUuid() {
+ return sdnControllerUuid;
+ }
+
+ public void setSdnControllerUuid(String sdnControllerUuid) {
+ this.sdnControllerUuid = sdnControllerUuid;
+ }
+
+ public String getL3NetworkUuid() {
+ return l3NetworkUuid;
+ }
+
+ public void setL3NetworkUuid(String l3NetworkUuid) {
+ this.l3NetworkUuid = l3NetworkUuid;
+ }
+
+ public Integer getIpVersion() {
+ return ipVersion;
+ }
+
+ public void setIpVersion(Integer ipVersion) {
+ this.ipVersion = ipVersion;
+ }
+}
+
diff --git a/header/src/main/java/org/zstack/header/network/l3/SdnControllerUpdateDHCPReply.java b/header/src/main/java/org/zstack/header/network/l3/SdnControllerUpdateDHCPReply.java
new file mode 100644
index 0000000000..ddda3d6555
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/network/l3/SdnControllerUpdateDHCPReply.java
@@ -0,0 +1,6 @@
+package org.zstack.header.network.l3;
+
+import org.zstack.header.message.MessageReply;
+
+public class SdnControllerUpdateDHCPReply extends MessageReply {
+}
diff --git a/header/src/main/java/org/zstack/header/network/service/SdnControllerDhcp.java b/header/src/main/java/org/zstack/header/network/service/SdnControllerDhcp.java
index 065d90e17d..c4a482b426 100644
--- a/header/src/main/java/org/zstack/header/network/service/SdnControllerDhcp.java
+++ b/header/src/main/java/org/zstack/header/network/service/SdnControllerDhcp.java
@@ -24,14 +24,14 @@ public interface SdnControllerDhcp {
/**
* 启用指定 L3 网络的 DHCP 服务
- * @param l3_min L3 网络索引
- * @param l3_max L3 网络索引
+ * @param l3Min L3 网络索引
+ * @param l3Max L3 网络索引
* @param invs L3 网络清单列表
* @param sync 是否同步操作
* @param completion 操作完成后的回调
* */
- void enableDhcp(long l3Min, long l3Max, List invs, boolean sync, Completion completion);
+ void enableDhcp(long l3Min, long l3Max, List invs, Integer ipversion, boolean sync, Completion completion);
/**
* 启用指定 L3 网络的 DHCP 服务
@@ -39,7 +39,7 @@ public interface SdnControllerDhcp {
* @param completion 操作完成后的回调
* */
- void enableDhcp(List invs, Completion completion);
+ void enableDhcp(List invs, Integer ipversion, Completion completion);
/**
* 禁用指定 L3 网络的 DHCP 服务
@@ -48,5 +48,5 @@ public interface SdnControllerDhcp {
* @param completion 操作完成后的回调
* */
- void disableDhcp(List invs, int ipversion, Completion completion);
+ void disableDhcp(List invs, Integer ipversion, Completion completion);
}
diff --git a/header/src/main/java/org/zstack/header/storage/addon/StorageCapacity.java b/header/src/main/java/org/zstack/header/storage/addon/StorageCapacity.java
index 59388eaa75..9f2ff79c7d 100644
--- a/header/src/main/java/org/zstack/header/storage/addon/StorageCapacity.java
+++ b/header/src/main/java/org/zstack/header/storage/addon/StorageCapacity.java
@@ -1,8 +1,29 @@
package org.zstack.header.storage.addon;
+import java.util.HashMap;
+import java.util.Map;
+
public class StorageCapacity {
+ public static class Capacity {
+ public long total;
+ public long available;
+ }
+
private long totalCapacity;
private long availableCapacity;
+ /***
+ * key: location url, it must be unique and consistent anywhere and anytime.
+ * ZStack use location url to identify different storage locations and generate storage space resource uuid based on it.
+ * storage space resource uuid = UUID.nameUUIDFromBytes((psUuid + locationUrl).getBytes()).toString()
+ *
+ * if storage do not support multiple locations, return null or empty map.
+ * if storage support multiple locations, the location url must be the prefix of volume install url.
+ * ZStack will retrieve the location url from volume install url to find the corresponding capacity info.
+ */
+ private Map capacitiesByLocationUrl;
+
+ // remove in future versions
+ @Deprecated
private StorageHealthy healthy;
public long getTotalCapacity() {
@@ -21,6 +42,25 @@ public void setAvailableCapacity(long availableCapacity) {
this.availableCapacity = availableCapacity;
}
+ public Map getCapacitiesByLocationUrl() {
+ return capacitiesByLocationUrl;
+ }
+
+ public void setCapacitiesByLocationUrl(Map capacitiesByLocationUrl) {
+ this.capacitiesByLocationUrl = capacitiesByLocationUrl;
+ }
+
+ public void putCapacity(String locationUrl, long availableCapacity, long totalCapacity) {
+ if (this.capacitiesByLocationUrl == null) {
+ this.capacitiesByLocationUrl = new HashMap<>();
+ }
+
+ Capacity capacity = new Capacity();
+ capacity.available = availableCapacity;
+ capacity.total = totalCapacity;
+ this.capacitiesByLocationUrl.put(locationUrl, capacity);
+ }
+
public StorageHealthy getHealthy() {
return healthy;
}
diff --git a/header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageSpaceInventory.java b/header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageSpaceInventory.java
new file mode 100644
index 0000000000..c6236d14fa
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageSpaceInventory.java
@@ -0,0 +1,133 @@
+package org.zstack.header.storage.addon.primary;
+
+import org.zstack.header.search.Inventory;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.sql.Timestamp;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Inventory(mappingVOClass = ExternalPrimaryStorageSpaceVO.class)
+public class ExternalPrimaryStorageSpaceInventory implements Serializable {
+ private String uuid;
+ private String primaryStorageUuid;
+ private String locationUrl;
+ private String type;
+ private String name;
+ private Long availableCapacity;
+ private Long totalCapacity;
+ private Long availablePhysicalCapacity;
+ private Long totalPhysicalCapacity;
+ private Timestamp createDate;
+ private Timestamp lastOpDate;
+
+ public static ExternalPrimaryStorageSpaceInventory valueOf(ExternalPrimaryStorageSpaceVO vo) {
+ ExternalPrimaryStorageSpaceInventory inv = new ExternalPrimaryStorageSpaceInventory();
+ inv.setUuid(vo.getUuid());
+ inv.setPrimaryStorageUuid(vo.getPrimaryStorageUuid());
+ inv.setLocationUrl(vo.getLocationUrl());
+ inv.setType(vo.getType());
+ inv.setName(vo.getName());
+ inv.setAvailableCapacity(vo.getAvailableCapacity());
+ inv.setTotalCapacity(vo.getTotalCapacity());
+ inv.setAvailablePhysicalCapacity(vo.getAvailablePhysicalCapacity());
+ inv.setTotalPhysicalCapacity(vo.getTotalPhysicalCapacity());
+ inv.setCreateDate(vo.getCreateDate());
+ inv.setLastOpDate(vo.getLastOpDate());
+ return inv;
+ }
+
+ public static List valueOf(Collection vos) {
+ return vos.stream().map(ExternalPrimaryStorageSpaceInventory::valueOf).collect(Collectors.toList());
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public String getPrimaryStorageUuid() {
+ return primaryStorageUuid;
+ }
+
+ public void setPrimaryStorageUuid(String primaryStorageUuid) {
+ this.primaryStorageUuid = primaryStorageUuid;
+ }
+
+ public String getLocationUrl() {
+ return locationUrl;
+ }
+
+ public void setLocationUrl(String locationUrl) {
+ this.locationUrl = locationUrl;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Long getAvailableCapacity() {
+ return availableCapacity;
+ }
+
+ public void setAvailableCapacity(Long availableCapacity) {
+ this.availableCapacity = availableCapacity;
+ }
+
+ public Long getTotalCapacity() {
+ return totalCapacity;
+ }
+
+ public void setTotalCapacity(Long totalCapacity) {
+ this.totalCapacity = totalCapacity;
+ }
+
+ public Long getAvailablePhysicalCapacity() {
+ return availablePhysicalCapacity;
+ }
+
+ public void setAvailablePhysicalCapacity(Long availablePhysicalCapacity) {
+ this.availablePhysicalCapacity = availablePhysicalCapacity;
+ }
+
+ public Long getTotalPhysicalCapacity() {
+ return totalPhysicalCapacity;
+ }
+
+ public void setTotalPhysicalCapacity(Long totalPhysicalCapacity) {
+ this.totalPhysicalCapacity = totalPhysicalCapacity;
+ }
+
+ 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;
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageSpaceVO.java b/header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageSpaceVO.java
new file mode 100644
index 0000000000..59473955b8
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageSpaceVO.java
@@ -0,0 +1,140 @@
+package org.zstack.header.storage.addon.primary;
+
+import org.zstack.header.storage.primary.PrimaryStorageEO;
+import org.zstack.header.vo.ForeignKey;
+import org.zstack.header.vo.ToInventory;
+
+import javax.persistence.*;
+import java.sql.Timestamp;
+
+@Entity
+@Table
+public class ExternalPrimaryStorageSpaceVO implements ToInventory {
+ @Column
+ @Id
+ private String uuid;
+
+ @Column
+ @ForeignKey(parentEntityClass = PrimaryStorageEO.class, onDeleteAction = ForeignKey.ReferenceOption.CASCADE)
+ private String primaryStorageUuid;
+
+ @Column
+ private String locationUrl;
+
+ @Column
+ private String type;
+
+ @Column
+ private String name;
+
+ @Column
+ private long availableCapacity;
+
+ @Column
+ private long totalCapacity;
+
+ @Column
+ private long availablePhysicalCapacity;
+
+ @Column
+ private long totalPhysicalCapacity;
+
+ @Column
+ private Timestamp createDate;
+ @Column
+ private Timestamp lastOpDate;
+
+
+ @PreUpdate
+ private void preUpdate() {
+ lastOpDate = null;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public String getPrimaryStorageUuid() {
+ return primaryStorageUuid;
+ }
+
+ public void setPrimaryStorageUuid(String primaryStorageUuid) {
+ this.primaryStorageUuid = primaryStorageUuid;
+ }
+
+ public String getLocationUrl() {
+ return locationUrl;
+ }
+
+ public void setLocationUrl(String locationUrl) {
+ this.locationUrl = locationUrl;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public long getAvailableCapacity() {
+ return availableCapacity;
+ }
+
+ public void setAvailableCapacity(long availableCapacity) {
+ this.availableCapacity = availableCapacity;
+ }
+
+ public long getTotalCapacity() {
+ return totalCapacity;
+ }
+
+ public void setTotalCapacity(long totalCapacity) {
+ this.totalCapacity = totalCapacity;
+ }
+
+ public long getAvailablePhysicalCapacity() {
+ return availablePhysicalCapacity;
+ }
+
+ public void setAvailablePhysicalCapacity(long availablePhysicalCapacity) {
+ this.availablePhysicalCapacity = availablePhysicalCapacity;
+ }
+
+ public long getTotalPhysicalCapacity() {
+ return totalPhysicalCapacity;
+ }
+
+ public void setTotalPhysicalCapacity(long totalPhysicalCapacity) {
+ this.totalPhysicalCapacity = totalPhysicalCapacity;
+ }
+
+ 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/storage/addon/primary/ExternalPrimaryStorageSpaceVO_.java b/header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageSpaceVO_.java
new file mode 100644
index 0000000000..a09a94b389
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageSpaceVO_.java
@@ -0,0 +1,19 @@
+package org.zstack.header.storage.addon.primary;
+
+
+import javax.persistence.metamodel.SingularAttribute;
+import javax.persistence.metamodel.StaticMetamodel;
+
+@StaticMetamodel(ExternalPrimaryStorageSpaceVO.class)
+public class ExternalPrimaryStorageSpaceVO_ {
+
+ public static volatile SingularAttribute uuid;
+ public static volatile SingularAttribute primaryStorageUuid;
+ public static volatile SingularAttribute type;
+ public static volatile SingularAttribute name;
+ public static volatile SingularAttribute locationUrl;
+ public static volatile SingularAttribute availableCapacity;
+ public static volatile SingularAttribute totalCapacity;
+ public static volatile SingularAttribute availablePhysicalCapacity;
+ public static volatile SingularAttribute totalPhysicalCapacity;
+}
diff --git a/header/src/main/java/org/zstack/header/storage/addon/primary/HeartbeatVolumeTopology.java b/header/src/main/java/org/zstack/header/storage/addon/primary/HeartbeatVolumeTopology.java
new file mode 100644
index 0000000000..fb5023c03d
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/addon/primary/HeartbeatVolumeTopology.java
@@ -0,0 +1,26 @@
+package org.zstack.header.storage.addon.primary;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class HeartbeatVolumeTopology {
+ /**
+ * key: storage space url
+ * value: heartbeat volume covering the storage space, if the volume has no heartbeat, we should
+ * treat the storage space as disconnected too. one storage space can only be covered by one heartbeat volume.
+ * and one heartbeat volume can cover multiple storage spaces.
+ */
+ private Map heartbeatVolumeByCoveringPaths = new HashMap<>();
+
+ public Map getHeartbeatVolumeByCoveringPaths() {
+ return heartbeatVolumeByCoveringPaths;
+ }
+
+ public void setHeartbeatVolumeByCoveringPaths(Map heartbeatVolumeByCoveringPaths) {
+ this.heartbeatVolumeByCoveringPaths = heartbeatVolumeByCoveringPaths;
+ }
+
+ public void putHeartbeatVolume(String coveringPath, HeartbeatVolumeTO heartbeatVolumeTO) {
+ this.heartbeatVolumeByCoveringPaths.put(coveringPath, heartbeatVolumeTO);
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageControllerSvc.java b/header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageControllerSvc.java
index 5d6896960c..48d9b29068 100644
--- a/header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageControllerSvc.java
+++ b/header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageControllerSvc.java
@@ -1,5 +1,6 @@
package org.zstack.header.storage.addon.primary;
+import org.zstack.header.apimediator.ApiMessageInterceptionException;
import org.zstack.header.core.Completion;
import org.zstack.header.core.ReturnValueCompletion;
import org.zstack.header.host.HostInventory;
@@ -17,11 +18,14 @@ public interface PrimaryStorageControllerSvc {
void connect(String config, String url, ReturnValueCompletion comp);
void ping(Completion completion);
+ void getCapacity(List requiredUrls, ReturnValueCompletion comp);
void reportCapacity(ReturnValueCompletion comp);
void reportHealthy(ReturnValueCompletion comp);
void reportNodeHealthy(HostInventory host, ReturnValueCompletion comp);
StorageCapabilities reportCapabilities();
+ // TODO: remove this method in future
+ @Deprecated
String allocateSpace(AllocateSpaceSpec aspec);
void createVolume(CreateVolumeSpec v, ReturnValueCompletioncomp);
@@ -48,7 +52,7 @@ public interface PrimaryStorageControllerSvc {
void expungeSnapshot(String installPath, Completion comp);
void revertVolumeSnapshot(String snapshotInstallPath, ReturnValueCompletion comp);
- void validateConfig(String config);
+ String validateConfig(String config) throws ApiMessageInterceptionException;
void setTrashExpireTime(int timeInSeconds, Completion completion);
void onFirstAdditionConfigure(Completion completion);
diff --git a/header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageNodeSvc.java b/header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageNodeSvc.java
index f292e69418..d7a6207cbc 100644
--- a/header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageNodeSvc.java
+++ b/header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageNodeSvc.java
@@ -25,11 +25,11 @@ public interface PrimaryStorageNodeSvc {
void deployClient(HostInventory h, Completion comp);
- void activateHeartbeatVolume(HostInventory h, ReturnValueCompletion comp);
+ void activateHeartbeatVolume(HostInventory h, ReturnValueCompletion comp);
void deactivateHeartbeatVolume(HostInventory h, Completion comp);
- HeartbeatVolumeTO getHeartbeatVolumeActiveInfo(HostInventory h);
+ HeartbeatVolumeTopology getHeartbeatVolumeActiveInfo(HostInventory h);
String getIdentity();
}
diff --git a/header/src/main/java/org/zstack/header/storage/addon/primary/StorageCapabilities.java b/header/src/main/java/org/zstack/header/storage/addon/primary/StorageCapabilities.java
index b2a6b7fe64..e1ca8e8e5c 100644
--- a/header/src/main/java/org/zstack/header/storage/addon/primary/StorageCapabilities.java
+++ b/header/src/main/java/org/zstack/header/storage/addon/primary/StorageCapabilities.java
@@ -9,10 +9,10 @@
public class StorageCapabilities {
private VolumeSnapshotCapability snapshotCapability;
+ private boolean supportMultiSpace;
private boolean supportCloneFromVolume;
-
+ private boolean supportCloneFromAnotherSpace;
private boolean supportStorageQos;
-
private boolean supportLiveExpandVolume;
private boolean supportShareableVolume;
private boolean supportExportVolumeSnapshot;
@@ -68,6 +68,14 @@ public void setSupportCloneFromVolume(boolean supportCloneFromVolume) {
this.supportCloneFromVolume = supportCloneFromVolume;
}
+ public boolean isSupportCloneFromAnotherSpace() {
+ return supportCloneFromAnotherSpace;
+ }
+
+ public void setSupportCloneFromAnotherSpace(boolean supportCloneFromAnotherSpace) {
+ this.supportCloneFromAnotherSpace = supportCloneFromAnotherSpace;
+ }
+
public List getSupportedImageFormats() {
return supportedImageFormats;
}
@@ -91,4 +99,12 @@ public boolean isSupportLiveExpandVolume() {
public void setSupportLiveExpandVolume(boolean supportLiveExpandVolume) {
this.supportLiveExpandVolume = supportLiveExpandVolume;
}
+
+ public boolean isSupportMultiSpace() {
+ return supportMultiSpace;
+ }
+
+ public void setSupportMultiSpace(boolean supportMultiSpace) {
+ this.supportMultiSpace = supportMultiSpace;
+ }
}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/AllocatePrimaryStorageSpaceMsg.java b/header/src/main/java/org/zstack/header/storage/primary/AllocatePrimaryStorageSpaceMsg.java
index 7b8543d03f..3413603d29 100644
--- a/header/src/main/java/org/zstack/header/storage/primary/AllocatePrimaryStorageSpaceMsg.java
+++ b/header/src/main/java/org/zstack/header/storage/primary/AllocatePrimaryStorageSpaceMsg.java
@@ -1,6 +1,10 @@
package org.zstack.header.storage.primary;
public class AllocatePrimaryStorageSpaceMsg extends AllocatePrimaryStorageMsg {
+ /**
+ * Indicates whether to force allocate primary storage space even if the primary storage
+ * is marked as full. Because some volume snapshot instantiated before allocated
+ */
private boolean force;
private String requiredInstallUri;
diff --git a/header/src/main/java/org/zstack/header/storage/primary/GetOwningVolumePathFromInternalSnapshotMsg.java b/header/src/main/java/org/zstack/header/storage/primary/GetOwningVolumePathFromInternalSnapshotMsg.java
new file mode 100644
index 0000000000..8e82eafac9
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/GetOwningVolumePathFromInternalSnapshotMsg.java
@@ -0,0 +1,27 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.NeedReplyMessage;
+
+import java.util.List;
+
+public class GetOwningVolumePathFromInternalSnapshotMsg extends NeedReplyMessage implements PrimaryStorageMessage {
+ private String primaryStorageUuid;
+ private List snapshotPaths;
+
+ @Override
+ public String getPrimaryStorageUuid() {
+ return primaryStorageUuid;
+ }
+
+ public void setPrimaryStorageUuid(String primaryStorageUuid) {
+ this.primaryStorageUuid = primaryStorageUuid;
+ }
+
+ public List getSnapshotPaths() {
+ return snapshotPaths;
+ }
+
+ public void setSnapshotPaths(List snapshotPaths) {
+ this.snapshotPaths = snapshotPaths;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/GetOwningVolumePathFromInternalSnapshotReply.java b/header/src/main/java/org/zstack/header/storage/primary/GetOwningVolumePathFromInternalSnapshotReply.java
new file mode 100644
index 0000000000..0083623318
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/storage/primary/GetOwningVolumePathFromInternalSnapshotReply.java
@@ -0,0 +1,22 @@
+package org.zstack.header.storage.primary;
+
+import org.zstack.header.message.MessageReply;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class GetOwningVolumePathFromInternalSnapshotReply extends MessageReply {
+ private Map owningVolumePaths = new HashMap<>();
+
+ public Map getOwningVolumePaths() {
+ return owningVolumePaths;
+ }
+
+ public void setOwningVolumePaths(Map owningVolumePaths) {
+ this.owningVolumePaths = owningVolumePaths;
+ }
+
+ public void putOwningVolumePath(String snapshotPath, String volumePath) {
+ this.owningVolumePaths.put(snapshotPath, volumePath);
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/PSCapacityExtensionPoint.java b/header/src/main/java/org/zstack/header/storage/primary/PSCapacityExtensionPoint.java
index 6a3eba3cd3..7a86252c67 100644
--- a/header/src/main/java/org/zstack/header/storage/primary/PSCapacityExtensionPoint.java
+++ b/header/src/main/java/org/zstack/header/storage/primary/PSCapacityExtensionPoint.java
@@ -4,8 +4,27 @@
import org.springframework.transaction.annotation.Transactional;
public interface PSCapacityExtensionPoint {
- String buildAllocatedInstallUrl(AllocatePrimaryStorageSpaceMsg msg, PrimaryStorageInventory psInv);
+ /**
+ * Allocate space dry run, return the installUrl that can be used to allocate space
+ * note: this method will not actually allocate space, just check whether the space can be allocated,
+ * and it has no thread safety guarantee, so it is possible that the space can be allocated in dry run,
+ * but fail in actual allocation.
+ * @param msg
+ * @param psInv
+ * @return installUrl that can be used to allocate space
+ */
+ String allocateSpaceDryRun(AllocatePrimaryStorageSpaceMsg msg, PrimaryStorageInventory psInv);
+
+ /**
+ * Reserve capacity after space allocation.
+ * throw exception if failed
+ * @param msg
+ * @param allocatedInstallUrl
+ * @param size
+ * @param psUuid
+ * @return the actually reserved size
+ */
@Transactional(propagation = Propagation.MANDATORY)
long reserveCapacity(AllocatePrimaryStorageSpaceMsg msg, String allocatedInstallUrl, long size, String psUuid);
diff --git a/header/src/main/java/org/zstack/header/storage/primary/VolumeSnapshotCapability.java b/header/src/main/java/org/zstack/header/storage/primary/VolumeSnapshotCapability.java
index 59d63b473c..79050146db 100755
--- a/header/src/main/java/org/zstack/header/storage/primary/VolumeSnapshotCapability.java
+++ b/header/src/main/java/org/zstack/header/storage/primary/VolumeSnapshotCapability.java
@@ -10,6 +10,11 @@ public static enum VolumeSnapshotArrangementType {
CHAIN,
INDIVIDUAL
}
+
+ public static enum VolumeSnapshotPlacementType {
+ INTERNAL,
+ EXTERNAL,
+ }
private boolean support;
@@ -28,13 +33,14 @@ public static enum VolumeSnapshotArrangementType {
private VolumeSnapshotArrangementType arrangementType;
+ private VolumeSnapshotPlacementType placementType;
+
/***
* If volume snapshot is inner snapshot on volume, it must be set.
* A regex match volume install path from inner volume snapshot install path.
* such as pool/vol from pool/vol@snapshot can be extracted by regex ^[^@]+
*/
- // TODO(mj) refactor it
- private String volumePathFromInnerSnapshotRegex;
+ private String volumePathFromInternalSnapshotRegex;
public boolean isSupport() {
return support;
@@ -52,6 +58,14 @@ public void setArrangementType(VolumeSnapshotArrangementType arrangementType) {
this.arrangementType = arrangementType;
}
+ public VolumeSnapshotPlacementType getPlacementType() {
+ return placementType;
+ }
+
+ public void setPlacementType(VolumeSnapshotPlacementType placementType) {
+ this.placementType = placementType;
+ }
+
public boolean isSupportCreateOnHypervisor() {
return supportCreateOnHypervisor;
}
@@ -68,11 +82,13 @@ public void setSupportLazyDelete(boolean supportLazyDelete) {
this.supportLazyDelete = supportLazyDelete;
}
- public String getVolumePathFromInnerSnapshotRegex() {
- return volumePathFromInnerSnapshotRegex;
+ @Deprecated
+ public String getVolumePathFromInternalSnapshotRegex() {
+ return volumePathFromInternalSnapshotRegex;
}
- public void setVolumePathFromInnerSnapshotRegex(String volumePathFromInnerSnapshotRegex) {
- this.volumePathFromInnerSnapshotRegex = volumePathFromInnerSnapshotRegex;
+ @Deprecated
+ public void setVolumePathFromInternalSnapshotRegex(String volumePathFromInternalSnapshotRegex) {
+ this.volumePathFromInternalSnapshotRegex = volumePathFromInternalSnapshotRegex;
}
}
diff --git a/header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordEvent.java b/header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordEvent.java
new file mode 100644
index 0000000000..8e8df9cd1f
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordEvent.java
@@ -0,0 +1,38 @@
+package org.zstack.header.vm;
+
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.rest.RestResponse;
+
+/**
+ * Created by haoyu.ding on 2025/11/19.
+ */
+@RestResponse(allTo = "inventory")
+public class APIUpdateConsolePasswordEvent extends APIEvent {
+ private VmInstanceInventory inventory;
+
+ public APIUpdateConsolePasswordEvent() {
+ super(null);
+ }
+
+ public APIUpdateConsolePasswordEvent(String apiId) {
+ super(apiId);
+ }
+
+ public VmInstanceInventory getInventory() {
+ return inventory;
+ }
+
+ public void setInventory(VmInstanceInventory inventory) {
+ this.inventory = inventory;
+ }
+
+ public static APIUpdateConsolePasswordEvent __example__() {
+ APIUpdateConsolePasswordEvent event = new APIUpdateConsolePasswordEvent(uuid());
+ VmInstanceInventory vm = new VmInstanceInventory();
+ vm.setUuid(uuid());
+ vm.setName("Test-VM-Updated");
+ vm.setState(VmInstanceState.Running.toString());
+ event.setInventory(vm);
+ return event;
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordEventDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordEventDoc_zh_cn.groovy
new file mode 100644
index 0000000000..06edb77809
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordEventDoc_zh_cn.groovy
@@ -0,0 +1,32 @@
+package org.zstack.header.vm
+
+import org.zstack.header.vm.VmInstanceInventory
+import org.zstack.header.errorcode.ErrorCode
+
+doc {
+
+ title "更新虚拟机控制台密码事件"
+
+ ref {
+ name "inventory"
+ path "org.zstack.header.vm.APIUpdateConsolePasswordEvent.inventory"
+ desc "null"
+ type "VmInstanceInventory"
+ since "5.4.2"
+ clz VmInstanceInventory.class
+ }
+ field {
+ name "success"
+ desc ""
+ type "boolean"
+ since "5.4.2"
+ }
+ ref {
+ name "error"
+ path "org.zstack.header.vm.APIUpdateConsolePasswordEvent.error"
+ desc "错误码,若不为null,则表示操作失败, 操作成功时该字段为null",false
+ type "ErrorCode"
+ since "5.4.2"
+ clz ErrorCode.class
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordMsg.java b/header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordMsg.java
new file mode 100644
index 0000000000..1d5c31917a
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordMsg.java
@@ -0,0 +1,55 @@
+package org.zstack.header.vm;
+
+import org.springframework.http.HttpMethod;
+import org.zstack.header.identity.Action;
+import org.zstack.header.log.NoLogging;
+import org.zstack.header.message.APIMessage;
+import org.zstack.header.message.APIParam;
+import org.zstack.header.rest.RestRequest;
+
+/**
+ * Created by haoyu.ding on 2025/11/19.
+ */
+@Action(category = VmInstanceConstant.ACTION_CATEGORY)
+@RestRequest(
+ path = "/vm-instances/{uuid}/actions",
+ isAction = true,
+ method = HttpMethod.PUT,
+ responseClass = APIUpdateConsolePasswordEvent.class
+)
+public class APIUpdateConsolePasswordMsg extends APIMessage implements VmInstanceMessage {
+ @APIParam(resourceType = VmInstanceVO.class, checkAccount = true, operationTarget = true)
+ private String uuid;
+
+ @APIParam
+ @NoLogging
+ private String password;
+
+ @Override
+ public String getVmInstanceUuid() {
+ return uuid;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public static APIUpdateConsolePasswordMsg __example__() {
+ APIUpdateConsolePasswordMsg msg = new APIUpdateConsolePasswordMsg();
+ msg.setUuid(uuid());
+ msg.setPassword("new-password-123");
+ return msg;
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordMsgDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordMsgDoc_zh_cn.groovy
new file mode 100644
index 0000000000..9b4a3afacd
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordMsgDoc_zh_cn.groovy
@@ -0,0 +1,67 @@
+package org.zstack.header.vm
+
+import org.zstack.header.vm.APIUpdateConsolePasswordEvent
+
+doc {
+ title "UpdateConsolePassword"
+
+ category "vmInstance"
+
+ desc """更新虚拟机控制台密码,虚拟机必须处于运行状态且已设置控制台密码"""
+
+ rest {
+ request {
+ url "PUT /v1/vm-instances/{uuid}/actions"
+
+ header (Authorization: 'OAuth the-session-uuid')
+
+ clz APIUpdateConsolePasswordMsg.class
+
+ desc """"""
+
+ params {
+
+ column {
+ name "uuid"
+ enclosedIn "updateConsolePassword"
+ desc "资源的UUID,唯一标示该资源"
+ location "url"
+ type "String"
+ optional false
+ since "5.4.2"
+ }
+ column {
+ name "password"
+ enclosedIn "updateConsolePassword"
+ desc ""
+ location "body"
+ type "String"
+ optional false
+ since "5.4.2"
+ }
+ column {
+ name "systemTags"
+ enclosedIn ""
+ desc "系统标签"
+ location "body"
+ type "List"
+ optional true
+ since "5.4.2"
+ }
+ column {
+ name "userTags"
+ enclosedIn ""
+ desc "用户标签"
+ location "body"
+ type "List"
+ optional true
+ since "5.4.2"
+ }
+ }
+ }
+
+ response {
+ clz APIUpdateConsolePasswordEvent.class
+ }
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/vm/UpdateVmConsolePasswordOnHypervisorMsg.java b/header/src/main/java/org/zstack/header/vm/UpdateVmConsolePasswordOnHypervisorMsg.java
new file mode 100644
index 0000000000..c008220bd5
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/UpdateVmConsolePasswordOnHypervisorMsg.java
@@ -0,0 +1,37 @@
+package org.zstack.header.vm;
+
+import org.zstack.header.host.HostMessage;
+import org.zstack.header.log.NoLogging;
+import org.zstack.header.message.NeedReplyMessage;
+
+public class UpdateVmConsolePasswordOnHypervisorMsg extends NeedReplyMessage implements HostMessage {
+ private String hostUuid;
+ private String vmInstanceUuid;
+ @NoLogging
+ private String password;
+
+ @Override
+ public String getHostUuid() {
+ return hostUuid;
+ }
+
+ public void setHostUuid(String hostUuid) {
+ this.hostUuid = hostUuid;
+ }
+
+ public String getVmInstanceUuid() {
+ return vmInstanceUuid;
+ }
+
+ public void setVmInstanceUuid(String vmInstanceUuid) {
+ this.vmInstanceUuid = vmInstanceUuid;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/vm/UpdateVmConsolePasswordOnHypervisorReply.java b/header/src/main/java/org/zstack/header/vm/UpdateVmConsolePasswordOnHypervisorReply.java
new file mode 100644
index 0000000000..f85cd1fe51
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/vm/UpdateVmConsolePasswordOnHypervisorReply.java
@@ -0,0 +1,6 @@
+package org.zstack.header.vm;
+
+import org.zstack.header.message.MessageReply;
+
+public class UpdateVmConsolePasswordOnHypervisorReply extends MessageReply {
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java b/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java
index 96da4293fa..7007c592ae 100755
--- a/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java
+++ b/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java
@@ -122,6 +122,7 @@ public boolean isRoot() {
public static class ImageSpec implements Serializable {
private ImageInventory inventory;
+ // FIXME: not for multi space primary storage
private boolean needDownload = true;
private ImageBackupStorageRefInventory selectedBackupStorage;
@@ -352,6 +353,7 @@ public void setHostname(String hostname) {
private boolean ignoreResourceReleaseFailure;
private boolean usbRedirect = false;
private boolean enableSecurityElement = false;
+ private Boolean enableHygonSecurityElement;
private String enableRDP = "false";
private String VDIMonitorNumber = "1";
@NoLogging
@@ -460,6 +462,14 @@ public void setEnableSecurityElement(boolean enableSecurityElement) {
this.enableSecurityElement = enableSecurityElement;
}
+ public Boolean isEnableHygonSecurityElement() {
+ return enableHygonSecurityElement;
+ }
+
+ public void setEnableHygonSecurityElement(Boolean enableHygonSecurityElement) {
+ this.enableHygonSecurityElement = enableHygonSecurityElement;
+ }
+
public void setCreatePaused(boolean createPaused) {
this.createPaused = createPaused;
}
@@ -788,6 +798,13 @@ public void setRootVolumeSystemTags(List rootVolumeSystemTags) {
this.rootVolumeSystemTags = rootVolumeSystemTags;
}
+ public void addRootVolumeSystemTag(String rootVolumeSystemTag) {
+ if (this.rootVolumeSystemTags == null) {
+ this.rootVolumeSystemTags = new ArrayList<>();
+ }
+ this.rootVolumeSystemTags.add(rootVolumeSystemTag);
+ }
+
public List getDataVolumeSystemTags() {
return dataVolumeSystemTags;
}
diff --git a/network/src/main/java/org/zstack/network/l2/L2NetworkApiInterceptor.java b/network/src/main/java/org/zstack/network/l2/L2NetworkApiInterceptor.java
index b67aea2b6e..b8b017f1d4 100755
--- a/network/src/main/java/org/zstack/network/l2/L2NetworkApiInterceptor.java
+++ b/network/src/main/java/org/zstack/network/l2/L2NetworkApiInterceptor.java
@@ -27,6 +27,8 @@
import static org.zstack.core.Platform.argerr;
import static org.zstack.core.Platform.operr;
+import static org.zstack.utils.CollectionDSL.e;
+import static org.zstack.utils.CollectionDSL.map;
/**
* Created with IntelliJ IDEA.
@@ -141,6 +143,8 @@ private void validate(APIChangeL2NetworkVlanIdMsg msg) {
throw new ApiMessageInterceptionException(argerr("cannot change vlan for l2Network[uuid:%s]" +
" because this l2Network is isolated", l2.getUuid()));
}
+ String sdnControllerUuid = L2NetworkSystemTags.L2_NETWORK_SDN_CONTROLLER_UUID
+ .getTokenByResourceUuid(msg.getL2NetworkUuid(), L2NetworkSystemTags.L2_NETWORK_SDN_CONTROLLER_UUID_TOKEN);
if (msg.getType().equals(L2NetworkConstant.L2_VLAN_NETWORK_TYPE)) {
if (msg.getVlan() == null) {
throw new ApiMessageInterceptionException(argerr("vlan is required for " +
@@ -151,15 +155,35 @@ private void validate(APIChangeL2NetworkVlanIdMsg msg) {
}
List attachedClusters = l2.getAttachedClusterRefs().stream()
.map(L2NetworkClusterRefVO::getClusterUuid).collect(Collectors.toList());
- List l2s = SQL.New("select l2" +
- " from L2NetworkVO l2, L2NetworkClusterRefVO ref" +
- " where l2.virtualNetworkId = :virtualNetworkId" +
- " and l2.physicalInterface = :physicalInterface" +
- " and ref.clusterUuid in (:clusterUuids)" +
- " and l2.type = 'L2VlanNetwork'")
- .param("virtualNetworkId", msg.getVlan())
- .param("physicalInterface", l2.getPhysicalInterface())
- .param("clusterUuids", attachedClusters).list();
+ List l2s;
+ if (sdnControllerUuid == null) {
+ l2s = SQL.New("select l2" +
+ " from L2NetworkVO l2, L2NetworkClusterRefVO ref" +
+ " where l2.uuid = ref.l2NetworkUuid" +
+ " and l2.virtualNetworkId = :virtualNetworkId" +
+ " and l2.physicalInterface = :physicalInterface" +
+ " and ref.clusterUuid in (:clusterUuids)" +
+ " and l2.type = 'L2VlanNetwork'")
+ .param("virtualNetworkId", msg.getVlan())
+ .param("physicalInterface", l2.getPhysicalInterface())
+ .param("clusterUuids", attachedClusters).list();
+ } else {
+ l2s = SQL.New("select l2" +
+ " from L2NetworkVO l2, L2NetworkClusterRefVO ref, SystemTagVO tag" +
+ " where l2.uuid = ref.l2NetworkUuid" +
+ " and l2.virtualNetworkId = :virtualNetworkId" +
+ " and l2.physicalInterface = :physicalInterface" +
+ " and ref.clusterUuid in (:clusterUuids)" +
+ " and l2.type = 'L2VlanNetwork'" +
+ " and tag.resourceUuid=l2.uuid " +
+ " and tag.resourceType='L2NetworkVO' " +
+ " and tag.tag=:tag")
+ .param("virtualNetworkId", msg.getVlan())
+ .param("physicalInterface", l2.getPhysicalInterface())
+ .param("tag", L2NetworkSystemTags.L2_NETWORK_SDN_CONTROLLER_UUID.instantiateTag(
+ map(e(L2NetworkSystemTags.L2_NETWORK_SDN_CONTROLLER_UUID_TOKEN, sdnControllerUuid))))
+ .param("clusterUuids", attachedClusters).list();
+ }
l2s = l2s.stream().filter(l -> !l.getUuid().equals(msg.getUuid())).collect(Collectors.toList());
if (!l2s.isEmpty()) {
throw new ApiMessageInterceptionException(argerr("There has been a l2Network attached to cluster with virtual network id[%s] and physical interface[%s]. Failed to change L2 network[uuid:%s]",
@@ -172,14 +196,31 @@ private void validate(APIChangeL2NetworkVlanIdMsg msg) {
}
List attachedClusters = l2.getAttachedClusterRefs().stream()
.map(L2NetworkClusterRefVO::getClusterUuid).collect(Collectors.toList());
- List l2s = SQL.New("select l2" +
- " from L2NetworkVO l2, L2NetworkClusterRefVO ref" +
- " where l2.uuid = ref.l2NetworkUuid" +
- " and l2.physicalInterface = :physicalInterface" +
- " and ref.clusterUuid in (:clusterUuids)" +
- " and type = 'L2NoVlanNetwork'")
- .param("physicalInterface", l2.getPhysicalInterface())
- .param("clusterUuids", attachedClusters).list();
+ List l2s;
+ if (sdnControllerUuid != null) {
+ l2s = SQL.New("select l2" +
+ " from L2NetworkVO l2, L2NetworkClusterRefVO ref, SystemTagVO tag" +
+ " where l2.uuid = ref.l2NetworkUuid" +
+ " and l2.physicalInterface = :physicalInterface" +
+ " and ref.clusterUuid in (:clusterUuids)" +
+ " and l2.type = 'L2NoVlanNetwork'" +
+ " and tag.resourceUuid=l2.uuid " +
+ " and tag.resourceType='L2NetworkVO' " +
+ " and tag.tag=:tag")
+ .param("physicalInterface", l2.getPhysicalInterface())
+ .param("tag", L2NetworkSystemTags.L2_NETWORK_SDN_CONTROLLER_UUID.instantiateTag(
+ map(e(L2NetworkSystemTags.L2_NETWORK_SDN_CONTROLLER_UUID_TOKEN, sdnControllerUuid))))
+ .param("clusterUuids", attachedClusters).list();
+ } else {
+ l2s = SQL.New("select l2" +
+ " from L2NetworkVO l2, L2NetworkClusterRefVO ref" +
+ " where l2.uuid = ref.l2NetworkUuid" +
+ " and l2.physicalInterface = :physicalInterface" +
+ " and ref.clusterUuid in (:clusterUuids)" +
+ " and l2.type = 'L2NoVlanNetwork'")
+ .param("physicalInterface", l2.getPhysicalInterface())
+ .param("clusterUuids", attachedClusters).list();
+ }
l2s = l2s.stream().filter(l -> !l.getUuid().equals(msg.getUuid())).collect(Collectors.toList());
if (!l2s.isEmpty()) {
throw new ApiMessageInterceptionException(argerr("There has been a l2Network attached to cluster that has physical interface[%s]. Failed to change l2Network[uuid:%s]",
diff --git a/network/src/main/java/org/zstack/network/l2/L2NoVlanNetwork.java b/network/src/main/java/org/zstack/network/l2/L2NoVlanNetwork.java
index c3449db014..6adceecec8 100755
--- a/network/src/main/java/org/zstack/network/l2/L2NoVlanNetwork.java
+++ b/network/src/main/java/org/zstack/network/l2/L2NoVlanNetwork.java
@@ -50,6 +50,8 @@
import static java.util.Arrays.asList;
import static org.zstack.core.Platform.*;
+import static org.zstack.utils.CollectionDSL.e;
+import static org.zstack.utils.CollectionDSL.map;
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class L2NoVlanNetwork implements L2Network {
@@ -935,14 +937,30 @@ private void attachL2NetworkToCluster(final AttachL2NetworkToClusterMsg msg, fi
protected void scripts() {
String type = Q.New(L2NetworkVO.class).select(L2NetworkVO_.type).eq(L2NetworkVO_.uuid, msg.getL2NetworkUuid()).findValue();
-
+ String sdnControllerUuid = L2NetworkSystemTags.L2_NETWORK_SDN_CONTROLLER_UUID
+ .getTokenByResourceUuid(msg.getL2NetworkUuid(), L2NetworkSystemTags.L2_NETWORK_SDN_CONTROLLER_UUID_TOKEN);
if (L2NetworkConstant.L2_NO_VLAN_NETWORK_TYPE.equals(type)) {
- List l2s = SQL.New("select l2" +
- " from L2NetworkVO l2, L2NetworkClusterRefVO ref" +
- " where l2.uuid = ref.l2NetworkUuid" +
- " and ref.clusterUuid = :clusterUuid" +
- " and type = 'L2NoVlanNetwork'")
- .param("clusterUuid", msg.getClusterUuid()).list();
+ List l2s;
+ if (sdnControllerUuid == null) {
+ l2s = SQL.New("select l2" +
+ " from L2NetworkVO l2, L2NetworkClusterRefVO ref" +
+ " where l2.uuid = ref.l2NetworkUuid" +
+ " and ref.clusterUuid = :clusterUuid" +
+ " and type = 'L2NoVlanNetwork'")
+ .param("clusterUuid", msg.getClusterUuid()).list();
+ } else {
+ l2s = SQL.New("select l2" +
+ " from L2NetworkVO l2, L2NetworkClusterRefVO ref, SystemTagVO tag" +
+ " where l2.uuid = ref.l2NetworkUuid" +
+ " and ref.clusterUuid = :clusterUuid" +
+ " and l2.type = 'L2NoVlanNetwork'" +
+ " and tag.resourceUuid=l2.uuid " +
+ " and tag.resourceType='L2NetworkVO' " +
+ " and tag.tag=:tag")
+ .param("tag", L2NetworkSystemTags.L2_NETWORK_SDN_CONTROLLER_UUID.instantiateTag(
+ map(e(L2NetworkSystemTags.L2_NETWORK_SDN_CONTROLLER_UUID_TOKEN, sdnControllerUuid))))
+ .param("clusterUuid", msg.getClusterUuid()).list();
+ }
if (l2s.isEmpty()) {
return;
@@ -956,11 +974,26 @@ protected void scripts() {
}
}
} else if (L2NetworkConstant.L2_VLAN_NETWORK_TYPE.equals(type)) {
- List l2s = SQL.New("select l2" +
- " from L2VlanNetworkVO l2, L2NetworkClusterRefVO ref" +
- " where l2.uuid = ref.l2NetworkUuid" +
- " and ref.clusterUuid = :clusterUuid")
- .param("clusterUuid", msg.getClusterUuid()).list();
+ List l2s;
+ if (sdnControllerUuid == null) {
+ l2s = SQL.New("select l2" +
+ " from L2VlanNetworkVO l2, L2NetworkClusterRefVO ref" +
+ " where l2.uuid = ref.l2NetworkUuid" +
+ " and ref.clusterUuid = :clusterUuid")
+ .param("clusterUuid", msg.getClusterUuid()).list();
+ } else {
+ l2s = SQL.New("select l2" +
+ " from L2VlanNetworkVO l2, L2NetworkClusterRefVO ref, SystemTagVO tag" +
+ " where l2.uuid = ref.l2NetworkUuid" +
+ " and ref.clusterUuid = :clusterUuid" +
+ " and tag.resourceUuid=l2.uuid " +
+ " and tag.resourceType='L2NetworkVO' " +
+ " and tag.tag=:tag")
+ .param("tag", L2NetworkSystemTags.L2_NETWORK_SDN_CONTROLLER_UUID.instantiateTag(
+ map(e(L2NetworkSystemTags.L2_NETWORK_SDN_CONTROLLER_UUID_TOKEN, sdnControllerUuid))))
+ .param("clusterUuid", msg.getClusterUuid()).list();
+ }
+
if (l2s.isEmpty()) {
return;
}
diff --git a/network/src/main/java/org/zstack/network/l3/L3BasicNetwork.java b/network/src/main/java/org/zstack/network/l3/L3BasicNetwork.java
index 19b9e530a5..4b12079e6e 100755
--- a/network/src/main/java/org/zstack/network/l3/L3BasicNetwork.java
+++ b/network/src/main/java/org/zstack/network/l3/L3BasicNetwork.java
@@ -13,7 +13,6 @@
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.core.db.*;
import org.zstack.core.db.SimpleQuery.Op;
-import org.zstack.core.defer.Defer;
import org.zstack.core.defer.Deferred;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.core.retry.Retry;
@@ -42,6 +41,7 @@
import org.zstack.header.network.l2.L2NetworkConstant;
import org.zstack.header.network.l2.L2NetworkVO;
import org.zstack.header.network.l3.*;
+import org.zstack.header.network.sdncontroller.SdnControllerConstant;
import org.zstack.header.network.service.*;
import org.zstack.identity.AccountManager;
import org.zstack.network.service.NetworkServiceManager;
@@ -62,10 +62,8 @@
import javax.persistence.Tuple;
import java.math.BigInteger;
import java.util.*;
-import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
-import static org.codehaus.groovy.runtime.InvokerHelper.asList;
import static org.zstack.core.Platform.err;
import static org.zstack.utils.CollectionDSL.*;
@@ -262,36 +260,28 @@ public void run(IpRangeDeletionExtensionPoint arg) {
@Override
public void run(FlowTrigger trigger, Map data) {
- boolean isLastIpRange = isLastNormalIpRangeOfVersion(msg.getIpRangeUuid(), inv.getIpVersion());
- data.put("isLastIpRange", isLastIpRange);
-
- if (!self.enableIpAddressAllocation()) {
- trigger.next();
- return;
- }
-
- SdnControllerDhcp sdnDhcp = l3NwMgr.getSdnControllerDhcp(self.getUuid());
- if (sdnDhcp == null) {
+ String sdnControllerUuid = L3NetworkHelper.getSdnControllerUuidFromL3Uuid(self.getUuid());
+ if (sdnControllerUuid == null) {
trigger.next();
return;
}
- if (isLastIpRange) {
- sdnDhcp.disableDhcp(Collections.singletonList(L3NetworkInventory.valueOf(self)), inv.getIpVersion(),
- new Completion(trigger) {
- @Override
- public void success() {
- trigger.next();
- }
-
- @Override
- public void fail(ErrorCode errorCode) {
- trigger.fail(errorCode);
- }
- });
- } else {
- trigger.next();
- }
+ SdnControllerDisableDHCPMsg msg = new SdnControllerDisableDHCPMsg();
+ msg.setL3NetworkUuid(self.getUuid());
+ msg.setIpVersion(iprvo.getIpVersion());
+ msg.setSdnControllerUuid(sdnControllerUuid);
+ msg.setCheckIpRange(true);
+ bus.makeTargetServiceIdByResourceUuid(msg, SdnControllerConstant.SERVICE_ID, sdnControllerUuid);
+ bus.send(msg, new CloudBusCallBack(trigger) {
+ @Override
+ public void run(MessageReply reply) {
+ if (!reply.isSuccess()) {
+ trigger.fail(reply.getError());
+ } else {
+ trigger.next();
+ }
+ }
+ });
}
}).then(new NoRollbackFlow() {
String __name__ = "delete-ip-range";
@@ -304,7 +294,7 @@ public void run(FlowTrigger trigger, Map data) {
return;
}
- boolean isLastIpRange = (boolean) data.get("isLastIpRange");
+ boolean isLastIpRange = isLastNormalIpRangeOfVersion(msg.getIpRangeUuid(), inv.getIpVersion());
if (isLastIpRange) {
sdnL3.deleteIpRange(inv, new Completion(trigger) {
@Override
@@ -1237,31 +1227,29 @@ public void run(FlowTrigger trigger, Map data) {
@Override
public void run(FlowTrigger trigger, Map data) {
- if (!self.enableIpAddressAllocation()) {
- trigger.next();
- return;
- }
-
- if (sdnDhcp == null) {
+ String sdnControllerUuid = L3NetworkHelper.getSdnControllerUuidFromL3Uuid(self.getUuid());
+ if (sdnControllerUuid == null) {
trigger.next();
return;
}
- List iprs = IpRangeHelper.getNormalIpRanges(self);
- if (iprs.isEmpty()) {
- trigger.next();
- return;
+ SdnControllerUpdateDHCPMsg dmsg = new SdnControllerUpdateDHCPMsg();
+ if (NetworkUtils.isIpv4Address(msg.getDns())) {
+ dmsg.setIpVersion(IPv6Constants.IPv4);
+ } else {
+ dmsg.setIpVersion(IPv6Constants.IPv6);
}
-
- sdnDhcp.enableDhcp(Collections.singletonList(L3NetworkInventory.valueOf(self)), new Completion(trigger) {
+ dmsg.setL3NetworkUuid(self.getUuid());
+ dmsg.setSdnControllerUuid(sdnControllerUuid);
+ bus.makeTargetServiceIdByResourceUuid(dmsg, SdnControllerConstant.SERVICE_ID, sdnControllerUuid);
+ bus.send(dmsg, new CloudBusCallBack(trigger) {
@Override
- public void success() {
- trigger.next();
- }
-
- @Override
- public void fail(ErrorCode errorCode) {
- trigger.fail(errorCode);
+ public void run(MessageReply reply) {
+ if (!reply.isSuccess()) {
+ trigger.fail(reply.getError());
+ } else {
+ trigger.next();
+ }
}
});
}
@@ -1355,31 +1343,29 @@ public void rollback(FlowRollback trigger, Map data) {
@Override
public void run(FlowTrigger trigger, Map data) {
- if (!self.enableIpAddressAllocation()) {
+ String sdnControllerUuid = L3NetworkHelper.getSdnControllerUuidFromL3Uuid(self.getUuid());
+ if (sdnControllerUuid == null) {
trigger.next();
return;
}
- if (sdnDhcp == null) {
- trigger.next();
- return;
- }
-
- List iprs = IpRangeHelper.getNormalIpRanges(self);
- if (iprs.isEmpty()) {
- trigger.next();
- return;
+ SdnControllerUpdateDHCPMsg dmsg = new SdnControllerUpdateDHCPMsg();
+ if (NetworkUtils.isIpv4Address(msg.getDns())) {
+ dmsg.setIpVersion(IPv6Constants.IPv4);
+ } else {
+ dmsg.setIpVersion(IPv6Constants.IPv6);
}
-
- sdnDhcp.enableDhcp(Collections.singletonList(L3NetworkInventory.valueOf(self)), new Completion(trigger) {
- @Override
- public void success() {
- trigger.next();
- }
-
+ dmsg.setL3NetworkUuid(self.getUuid());
+ dmsg.setSdnControllerUuid(sdnControllerUuid);
+ bus.makeTargetServiceIdByResourceUuid(dmsg, SdnControllerConstant.SERVICE_ID, sdnControllerUuid);
+ bus.send(dmsg, new CloudBusCallBack(trigger) {
@Override
- public void fail(ErrorCode errorCode) {
- trigger.fail(errorCode);
+ public void run(MessageReply reply) {
+ if (!reply.isSuccess()) {
+ trigger.fail(reply.getError());
+ } else {
+ trigger.next();
+ }
}
});
}
diff --git a/network/src/main/java/org/zstack/network/l3/L3NetworkManagerImpl.java b/network/src/main/java/org/zstack/network/l3/L3NetworkManagerImpl.java
index 7c1ee6da36..80ba293281 100755
--- a/network/src/main/java/org/zstack/network/l3/L3NetworkManagerImpl.java
+++ b/network/src/main/java/org/zstack/network/l3/L3NetworkManagerImpl.java
@@ -36,7 +36,9 @@
import org.zstack.header.network.l3.datatypes.IpCapacityData;
import org.zstack.header.network.service.GetSdnControllerExtensionPoint;
import org.zstack.header.network.service.SdnControllerDhcp;
+import org.zstack.header.network.sdncontroller.SdnControllerConstant;
import org.zstack.header.vm.VmNicInventory;
+
import org.zstack.header.vm.VmNicVO;
import org.zstack.header.vm.VmNicVO_;
import org.zstack.header.zone.ZoneVO;
@@ -53,7 +55,6 @@
import org.zstack.utils.ExceptionDSL;
import org.zstack.utils.ObjectUtils;
import org.zstack.utils.Utils;
-import org.zstack.utils.gson.JSONObjectUtil;
import org.zstack.utils.logging.CLogger;
import org.zstack.utils.network.IPv6Constants;
import org.zstack.utils.network.IPv6NetworkUtils;
@@ -65,7 +66,6 @@
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.Callable;
-import java.util.stream.Collectors;
import static org.zstack.core.Platform.err;
import static org.zstack.utils.CollectionDSL.*;
@@ -157,38 +157,29 @@ private void handle(final APISetL3NetworkMtuMsg msg) {
);
creator.create();
- L3NetworkVO l3Vo = dbf.findByUuid(msg.getL3NetworkUuid(), L3NetworkVO.class);
FlowChain chain = FlowChainBuilder.newSimpleFlowChain();
chain.setName("change-l3-network-mtu");
chain.then(new NoRollbackFlow() {
@Override
public void run(FlowTrigger trigger, Map data) {
- if (!l3Vo.enableIpAddressAllocation()) {
- trigger.next();
- return;
- }
-
- SdnControllerDhcp dhcp = getSdnControllerDhcp(msg.getL3NetworkUuid());
- if (dhcp == null) {
+ String sdnControllerUuid = L3NetworkHelper.getSdnControllerUuidFromL3Uuid(msg.getL3NetworkUuid());
+ if (sdnControllerUuid == null) {
trigger.next();
return;
}
- List iprs = IpRangeHelper.getNormalIpRanges(l3Vo);
- if (iprs.isEmpty()) {
- trigger.next();
- return;
- }
-
- dhcp.enableDhcp(Collections.singletonList(L3NetworkInventory.valueOf(l3Vo)), new Completion(trigger) {
+ SdnControllerUpdateDHCPMsg dmsg = new SdnControllerUpdateDHCPMsg();
+ dmsg.setL3NetworkUuid(msg.getL3NetworkUuid());
+ dmsg.setSdnControllerUuid(sdnControllerUuid);
+ bus.makeTargetServiceIdByResourceUuid(dmsg, SdnControllerConstant.SERVICE_ID, sdnControllerUuid);
+ bus.send(dmsg, new CloudBusCallBack(trigger) {
@Override
- public void success() {
- trigger.next();
- }
-
- @Override
- public void fail(ErrorCode errorCode) {
- trigger.fail(errorCode);
+ public void run(MessageReply reply) {
+ if (!reply.isSuccess()) {
+ trigger.fail(reply.getError());
+ } else {
+ trigger.next();
+ }
}
});
}
diff --git a/network/src/main/java/org/zstack/network/l3/NormalIpRangeFactory.java b/network/src/main/java/org/zstack/network/l3/NormalIpRangeFactory.java
index b27778e644..6b7d70d45e 100644
--- a/network/src/main/java/org/zstack/network/l3/NormalIpRangeFactory.java
+++ b/network/src/main/java/org/zstack/network/l3/NormalIpRangeFactory.java
@@ -1,30 +1,31 @@
package org.zstack.network.l3;
import org.springframework.beans.factory.annotation.Autowired;
-import org.zstack.core.asyncbatch.While;
+import org.zstack.core.cloudbus.CloudBus;
+import org.zstack.core.cloudbus.CloudBusCallBack;
import org.zstack.core.componentloader.PluginRegistry;
+
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.Q;
import org.zstack.core.db.SQLBatchWithReturn;
import org.zstack.core.workflow.SimpleFlowChain;
import org.zstack.header.core.Completion;
-import org.zstack.header.core.NoErrorCompletion;
import org.zstack.header.core.ReturnValueCompletion;
-import org.zstack.header.core.WhileDoneCompletion;
import org.zstack.header.core.workflow.*;
import org.zstack.header.errorcode.ErrorCode;
-import org.zstack.header.errorcode.ErrorCodeList;
import org.zstack.header.message.APICreateMessage;
+import org.zstack.header.message.MessageReply;
import org.zstack.header.network.l3.*;
+import org.zstack.header.network.sdncontroller.SdnControllerConstant;
import org.zstack.header.network.service.SdnControllerDhcp;
import org.zstack.utils.CollectionUtils;
+
import org.zstack.utils.function.ForEachFunction;
import org.zstack.utils.network.IPv6Constants;
import org.zstack.utils.network.IPv6NetworkUtils;
import org.zstack.utils.network.NetworkUtils;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -35,6 +36,9 @@ public class NormalIpRangeFactory implements IpRangeFactory {
protected PluginRegistry pluginRgty;
@Autowired
protected L3NetworkManager l3Mgr;
+ @Autowired
+ private CloudBus bus;
+
@Override
public IpRangeType getType() {
@@ -113,27 +117,25 @@ public void rollback(FlowRollback trigger, Map data) {
@Override
public void run(FlowTrigger trigger, Map data) {
- L3NetworkVO l3vo = dbf.findByUuid(iprs.get(0).getL3NetworkUuid(), L3NetworkVO.class);
- if (!l3vo.enableIpAddressAllocation()) {
- trigger.next();
- return;
- }
-
- SdnControllerDhcp sdnDhcp = l3Mgr.getSdnControllerDhcp(l3vo.getUuid());
- if (sdnDhcp == null) {
+ String sdnControllerUuid = L3NetworkHelper.getSdnControllerUuidFromL3Uuid(iprs.get(0).getL3NetworkUuid());
+ if (sdnControllerUuid == null) {
trigger.next();
return;
}
- sdnDhcp.enableDhcp(Collections.singletonList(L3NetworkInventory.valueOf(l3vo)), new Completion(trigger) {
+ SdnControllerUpdateDHCPMsg dmsg = new SdnControllerUpdateDHCPMsg();
+ dmsg.setL3NetworkUuid(iprs.get(0).getL3NetworkUuid());
+ dmsg.setIpVersion(iprs.get(0).getIpVersion());
+ dmsg.setSdnControllerUuid(sdnControllerUuid);
+ bus.makeTargetServiceIdByResourceUuid(dmsg, SdnControllerConstant.SERVICE_ID, sdnControllerUuid);
+ bus.send(dmsg, new CloudBusCallBack(trigger) {
@Override
- public void success() {
- trigger.next();
- }
-
- @Override
- public void fail(ErrorCode errorCode) {
- trigger.fail(errorCode);
+ public void run(MessageReply reply) {
+ if (!reply.isSuccess()) {
+ trigger.fail(reply.getError());
+ } else {
+ trigger.next();
+ }
}
});
}
diff --git a/network/src/main/java/org/zstack/network/service/DhcpExtension.java b/network/src/main/java/org/zstack/network/service/DhcpExtension.java
index 0dfbb39c1a..90e78646d5 100755
--- a/network/src/main/java/org/zstack/network/service/DhcpExtension.java
+++ b/network/src/main/java/org/zstack/network/service/DhcpExtension.java
@@ -2,8 +2,11 @@
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
+import org.zstack.core.cloudbus.CloudBus;
+import org.zstack.core.cloudbus.CloudBusCallBack;
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.core.db.Q;
+
import org.zstack.core.db.SimpleQuery;
import org.zstack.core.db.SimpleQuery.Op;
import org.zstack.header.Component;
@@ -12,11 +15,16 @@
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.network.l3.*;
+import org.zstack.header.network.sdncontroller.SdnControllerConstant;
import org.zstack.header.network.service.*;
import org.zstack.header.vm.*;
+import org.zstack.header.message.MessageReply;
+
import org.zstack.header.vm.VmInstanceSpec.HostName;
import org.zstack.network.l3.IpRangeHelper;
import org.zstack.network.l3.L3NetworkGlobalConfig;
+import org.zstack.network.l3.L3NetworkHelper;
+
import org.zstack.network.l3.L3NetworkManager;
import org.zstack.utils.CollectionUtils;
import org.zstack.utils.Utils;
@@ -43,6 +51,9 @@ public class DhcpExtension extends AbstractNetworkServiceExtension implements Co
private PluginRegistry pluginRgty;
@Autowired
private L3NetworkManager l3Mgr;
+ @Autowired
+ private CloudBus bus;
+
private final Map dhcpBackends = new HashMap();
@@ -395,15 +406,22 @@ public void fail(ErrorCode errorCode) {
@Override
public void enableNetworkService(L3NetworkVO l3VO, NetworkServiceProviderType providerType, List systemTags, Completion completion) {
- SdnControllerDhcp sdnDhcp = l3Mgr.getSdnControllerDhcp(l3VO.getUuid());
- if (sdnDhcp != null) {
- List normalIpRange = IpRangeHelper.getNormalIpRanges(l3VO);
- if (normalIpRange.isEmpty()) {
- completion.success();
- return;
- }
-
- sdnDhcp.allocateDhcpAndEnableDhcp(l3VO, systemTags, completion);
+ String sdnControllerUuid = L3NetworkHelper.getSdnControllerUuidFromL3Uuid(l3VO.getUuid());
+ if (sdnControllerUuid != null) {
+ SdnControllerEnableDHCPMsg msg = new SdnControllerEnableDHCPMsg();
+ msg.setL3NetworkUuid(l3VO.getUuid());
+ msg.setSdnControllerUuid(sdnControllerUuid);
+ bus.makeTargetServiceIdByResourceUuid(msg, SdnControllerConstant.SERVICE_ID, sdnControllerUuid);
+ bus.send(msg, new CloudBusCallBack(completion) {
+ @Override
+ public void run(MessageReply reply) {
+ if (!reply.isSuccess()) {
+ completion.fail(reply.getError());
+ } else {
+ completion.success();
+ }
+ }
+ });
return;
}
@@ -418,15 +436,22 @@ public void enableNetworkService(L3NetworkVO l3VO, NetworkServiceProviderType pr
@Override
public void disableNetworkService(L3NetworkVO l3VO, NetworkServiceProviderType providerType, Completion completion) {
- SdnControllerDhcp sdnDhcp = l3Mgr.getSdnControllerDhcp(l3VO.getUuid());
- if (sdnDhcp != null) {
- List normalIpRange = IpRangeHelper.getNormalIpRanges(l3VO);
- if (normalIpRange.isEmpty()) {
- completion.success();
- return;
- }
-
- sdnDhcp.disableDhcp(Collections.singletonList(L3NetworkInventory.valueOf(l3VO)), IPv6Constants.DUAL_STACK, completion);
+ String sdnControllerUuid = L3NetworkHelper.getSdnControllerUuidFromL3Uuid(l3VO.getUuid());
+ if (sdnControllerUuid != null) {
+ SdnControllerDisableDHCPMsg msg = new SdnControllerDisableDHCPMsg();
+ msg.setL3NetworkUuid(l3VO.getUuid());
+ msg.setSdnControllerUuid(sdnControllerUuid);
+ bus.makeTargetServiceIdByResourceUuid(msg, SdnControllerConstant.SERVICE_ID, sdnControllerUuid);
+ bus.send(msg, new CloudBusCallBack(completion) {
+ @Override
+ public void run(MessageReply reply) {
+ if (!reply.isSuccess()) {
+ completion.fail(reply.getError());
+ } else {
+ completion.success();
+ }
+ }
+ });
return;
}
diff --git a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmBase.java b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmBase.java
index 6f3f6e0924..8d039b0e69 100755
--- a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmBase.java
+++ b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmBase.java
@@ -96,7 +96,7 @@ protected List createBootstrapFlows(HypervisorType hvType) {
return flows;
}
- protected List createAfterConnectNewCreatedVirtualRouterFlows() {
+ protected List createAfterConnectNewCreatedFlows() {
return new ArrayList<>();
}
@@ -796,8 +796,8 @@ private FlowChain addBootstrapFlows(FlowChain chain, HypervisorType hvType) {
return chain;
}
- private FlowChain addAfterConnectNewCreatedVirtualRouterFlows(FlowChain chain) {
- for (Flow flow : createAfterConnectNewCreatedVirtualRouterFlows()) {
+ private FlowChain addAfterConnectNewCreatedFlows(FlowChain chain) {
+ for (Flow flow : createAfterConnectNewCreatedFlows()) {
chain.then(flow);
}
@@ -836,7 +836,7 @@ public void run(FlowTrigger trigger, Map data) {
}
});
- addAfterConnectNewCreatedVirtualRouterFlows(chain);
+ addAfterConnectNewCreatedFlows(chain);
boolean noRollbackOnFailure = ApplianceVmGlobalProperty.NO_ROLLBACK_ON_POST_FAILURE;
chain.noRollback(noRollbackOnFailure);
@@ -960,7 +960,7 @@ public void run(FlowTrigger trigger, Map data) {
}
});
- addAfterConnectNewCreatedVirtualRouterFlows(chain);
+ addAfterConnectNewCreatedFlows(chain);
}
boolean noRollbackOnFailure = ApplianceVmGlobalProperty.NO_ROLLBACK_ON_POST_FAILURE;
diff --git a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmCascadeExtension.java b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmCascadeExtension.java
index bef8e06bdd..d2134ad3f8 100755
--- a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmCascadeExtension.java
+++ b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmCascadeExtension.java
@@ -74,6 +74,8 @@ public class ApplianceVmCascadeExtension extends AbstractAsyncCascadeExtension {
private PluginRegistry pluginRgty;
@Autowired
protected ThreadFacade thdf;
+ @Autowired
+ private ApplianceVmFacade apvmFacade;
private static String NAME = ApplianceVmVO.class.getSimpleName();
@@ -287,10 +289,22 @@ private void handleL2NetworkDetach(CascadeAction action, final Completion comple
.map(VmInstanceVO::getUuid).collect(Collectors.toList())).list();
if (!applianceVmVOS.isEmpty()) {
- for (ApvmCascadeFilterExtensionPoint ext : pluginRgty.getExtensionList(ApvmCascadeFilterExtensionPoint.class)) {
- applianceVmVOS = ext.filterApplianceVmCascade(applianceVmVOS, action, action.getParentIssuer(), l3uuids,
- new ArrayList<>(), new ArrayList<>());
+ List toMigrateVms = new ArrayList<>();
+ Map> apvmsByType = applianceVmVOS.stream()
+ .collect(Collectors.groupingBy(ApplianceVmVO::getApplianceVmType));
+
+ for (Map.Entry> entry : apvmsByType.entrySet()) {
+ ApplianceVmType vmType = ApplianceVmType.valueOf(entry.getKey());
+ List vmsOfType = entry.getValue();
+
+ ApvmCascadeFilterExtensionPoint ext = apvmFacade.getApvmCascadeFilterExtensionPoint(vmType);
+ if (ext != null) {
+ vmsOfType = ext.filterApplianceVmCascade(vmsOfType, action, action.getParentIssuer(), l3uuids,
+ new ArrayList<>(), new ArrayList<>());
+ }
+ toMigrateVms.addAll(vmsOfType);
}
+ applianceVmVOS = toMigrateVms;
}
if (applianceVmVOS.isEmpty()) {
@@ -788,12 +802,32 @@ public String call(L3NetworkInventory arg) {
q.setParameter("l3Uuids", l3uuids);
List apvms = q.getResultList();
if (!apvms.isEmpty()) {
- for (ApvmCascadeFilterExtensionPoint ext : pluginRgty.getExtensionList(ApvmCascadeFilterExtensionPoint.class)) {
- apvms = ext.filterApplianceVmCascade(apvms, action, action.getParentIssuer(), l3uuids,
- toDeleteNics, toDeleteIps);
+ List toDeleteVms = new ArrayList<>();
+ List vmNics = new ArrayList<>();
+ List ips = new ArrayList<>();
+ Map> apvmsByType = apvms.stream()
+ .collect(Collectors.groupingBy(ApplianceVmVO::getApplianceVmType));
+
+ for (Map.Entry> entry : apvmsByType.entrySet()) {
+ ApplianceVmType vmType = ApplianceVmType.valueOf(entry.getKey());
+ List vmsOfType = entry.getValue();
+
+ ApvmCascadeFilterExtensionPoint ext = apvmFacade.getApvmCascadeFilterExtensionPoint(vmType);
+ if (ext != null) {
+ vmsOfType = ext.filterApplianceVmCascade(vmsOfType, action, action.getParentIssuer(), l3uuids,
+ vmNics, ips);
+ if (!vmNics.isEmpty()) {
+ toDeleteNics.addAll(vmNics);
+ }
+ if (!ips.isEmpty()) {
+ toDeleteIps.addAll(ips);
+ }
+ }
+ toDeleteVms.addAll(vmsOfType);
}
- if (!apvms.isEmpty()) {
- ret = ApplianceVmInventory.valueOf1(apvms);
+
+ if (!toDeleteVms.isEmpty()) {
+ ret = ApplianceVmInventory.valueOf1(toDeleteVms);
}
}
} else if (IpRangeVO.class.getSimpleName().equals(action.getParentIssuer())) {
@@ -857,13 +891,32 @@ public List call() {
}
}
}
- for (ApvmCascadeFilterExtensionPoint ext : pluginRgty.getExtensionList(ApvmCascadeFilterExtensionPoint.class)) {
- vmvos = ext.filterApplianceVmCascade(vmvos, action, action.getParentIssuer(), ipruuids,
- toDeleteNics, toDeleteIps);
+
+ List toDeleteVms = new ArrayList<>();
+ Map> vmvosByType = vmvos.stream()
+ .collect(Collectors.groupingBy(ApplianceVmVO::getApplianceVmType));
+
+ for (Map.Entry> entry : vmvosByType.entrySet()) {
+ ApplianceVmType vmType = ApplianceVmType.valueOf(entry.getKey());
+ List vmsOfType = entry.getValue();
+ List vmNics = new ArrayList<>();
+ List ips = new ArrayList<>();
+ ApvmCascadeFilterExtensionPoint ext = apvmFacade.getApvmCascadeFilterExtensionPoint(vmType);
+ if (ext != null) {
+ vmsOfType = ext.filterApplianceVmCascade(vmsOfType, action, action.getParentIssuer(), ipruuids,
+ vmNics, ips);
+ if (!vmNics.isEmpty()) {
+ toDeleteNics.addAll(vmNics);
+ }
+ if (!ips.isEmpty()) {
+ toDeleteIps.addAll(ips);
+ }
+ }
+ toDeleteVms.addAll(vmsOfType);
}
- if (!vmvos.isEmpty()) {
- ret = ApplianceVmInventory.valueOf1(vmvos);
+ if (!toDeleteVms.isEmpty()) {
+ ret = ApplianceVmInventory.valueOf1(toDeleteVms);
}
} else if (AccountVO.class.getSimpleName().equals(action.getParentIssuer())) {
final List auuids = CollectionUtils.transformToList((List) action.getParentIssuerContext(), new Function() {
diff --git a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmFacade.java b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmFacade.java
index 261c1ee638..fa8411218c 100755
--- a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmFacade.java
+++ b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmFacade.java
@@ -43,4 +43,6 @@ public interface ApplianceVmFacade {
void attachApplianceVmToHaGroup(String vmUuid, String haGroupUuid);
void dettachVmInstanceFromAffinityGroup(String vmUuid);
void detachVirtualRouterFromHaGroup(String vmUuid, String haGroupUuid);
+
+ ApvmCascadeFilterExtensionPoint getApvmCascadeFilterExtensionPoint(ApplianceVmType applianceVmType);
}
diff --git a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmFacadeImpl.java b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmFacadeImpl.java
index 9ae61e10c7..4f760dde45 100755
--- a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmFacadeImpl.java
+++ b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmFacadeImpl.java
@@ -40,15 +40,12 @@
import org.zstack.network.service.MtuGetter;
import org.zstack.header.vm.hooks.VmInstanceAfterCreateHook;
import org.zstack.header.vm.hooks.VmInstanceAfterDestroyHook;
-import org.zstack.header.vm.hooks.VmInstanceBeforeCreateHook;
import org.zstack.header.vm.hooks.VmInstanceBeforeDestroyHook;
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 org.zstack.utils.zsha2.ZSha2Helper;
-import org.zstack.utils.zsha2.ZSha2Info;
import javax.persistence.Query;
import java.util.*;
@@ -88,6 +85,8 @@ public class ApplianceVmFacadeImpl extends AbstractService implements ApplianceV
private FlowChainBuilder createApplianceVmWorkFlowBuilder;
private Map bootstrapInfoFlowFactories = new HashMap();
private Map l2NetworkGetVniExtensionPointMap = new HashMap<>();
+ private Map apvmCascadeFilterExtensionPointMap = new HashMap<>();
+ private List nicBootstrapExtensions = Collections.emptyList();
private String OWNER = String.format("ApplianceVm.%s", Platform.getManagementServerId());
@@ -224,6 +223,23 @@ private void populateExtensions() {
l2NetworkGetVniExtensionPointMap.put(ext.getL2NetworkVniType(), ext);
logger.debug(String.format("add new l2NetworkGetVniExtensionPoint, %s: %s", ext.getL2NetworkVniType(), ext.getClass().getCanonicalName()));
}
+
+ for (ApvmCascadeFilterExtensionPoint ext : pluginRgty.getExtensionList(ApvmCascadeFilterExtensionPoint.class)) {
+ ApplianceVmType type = ext.getApplianceVmType();
+ ApvmCascadeFilterExtensionPoint old = apvmCascadeFilterExtensionPointMap.get(type);
+ if (old != null) {
+ throw new CloudRuntimeException(String.format("two extensions[%s, %s] declare ApvmCascadeFilterExtensionPoint for appliance vm type[%s]", old.getClass().getName(), ext.getClass().getName(), type));
+ }
+
+ apvmCascadeFilterExtensionPointMap.put(type, ext);
+ logger.debug(String.format("add new apvmCascadeFilterExtensionPoint, %s: %s", type, ext.getClass().getCanonicalName()));
+
+ }
+
+ nicBootstrapExtensions = pluginRgty.getExtensionList(ApplianceVmNicBootstrapExtensionPoint.class);
+ if (nicBootstrapExtensions == null) {
+ nicBootstrapExtensions = Collections.emptyList();
+ }
}
private void deployAnsible() {
@@ -337,6 +353,13 @@ private List reduceNic(List nics, VmNicInventory
return ret;
}
+ private void fillVfNicBootstrapInfo(VmNicInventory nic, ApplianceVmNicTO to) {
+ to.setBondMode("none");
+ for (ApplianceVmNicBootstrapExtensionPoint ext : nicBootstrapExtensions) {
+ ext.fillNicBootstrapInfo(nic, to);
+ }
+ }
+
@Override
public Map prepareBootstrapInformation(VmInstanceSpec spec) {
VmNicInventory mgmtNic = null;
@@ -376,6 +399,7 @@ public Map prepareBootstrapInformation(VmInstanceSpec spec) {
mto.setCategory(l3NetworkVO.getCategory().toString());
mto.setL2type(l2NetworkVO.getType());
mto.setPhysicalInterface(l2NetworkVO.getPhysicalInterface());
+ fillVfNicBootstrapInfo(mgmtNic, mto);
if (l2NetworkGetVniExtensionPointMap == null || l2NetworkGetVniExtensionPointMap.isEmpty() ||
l2NetworkGetVniExtensionPointMap.get(l2NetworkVO.getType()) == null) {
logger.debug("l2NetworkGetVniExtensionPointMap is null. skip to get vni");
@@ -414,6 +438,7 @@ public Map prepareBootstrapInformation(VmInstanceSpec spec) {
t.setL2type(l2NetworkVO.getType());
t.setVni(l2NetworkGetVniExtensionPointMap.get(l2NetworkVO.getType()).getL2NetworkVni(l2NetworkVO.getUuid(), spec.getVmInventory().getHostUuid()));
t.setPhysicalInterface(l2NetworkVO.getPhysicalInterface());
+ fillVfNicBootstrapInfo(defaultRouteNic, t);
t.setMtu(new MtuGetter().getMtu(l3NetworkVO.getUuid()));
deviceId ++;
extraTos.add(t);
@@ -430,6 +455,7 @@ public Map prepareBootstrapInformation(VmInstanceSpec spec) {
nto.setL2type(l2NetworkVO.getType());
nto.setVni(l2NetworkGetVniExtensionPointMap.get(l2NetworkVO.getType()).getL2NetworkVni(l2NetworkVO.getUuid(), spec.getVmInventory().getHostUuid()));
nto.setPhysicalInterface(l2NetworkVO.getPhysicalInterface());
+ fillVfNicBootstrapInfo(nic, nto);
nto.setMtu(new MtuGetter().getMtu(l3NetworkVO.getUuid()));
extraTos.add(nto);
deviceId ++;
@@ -622,9 +648,14 @@ public void attachApplianceVmToHaGroup(String vmUuid, String haGroupUuid) {
}
}
+ @Override
public void detachVirtualRouterFromHaGroup(String vmUuid, String haGroupUuid) {
for (ApplianceVmHaExtensionPoint ext : pluginRgty.getExtensionList(ApplianceVmHaExtensionPoint.class)) {
ext.detachVirtualRouterFromHaGroup(vmUuid, haGroupUuid);
}
}
+
+ public ApvmCascadeFilterExtensionPoint getApvmCascadeFilterExtensionPoint(ApplianceVmType type) {
+ return apvmCascadeFilterExtensionPointMap.get(type);
+ }
}
diff --git a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmHaStatus.java b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmHaStatus.java
index 99a1fd4c7c..9fdf9da37c 100644
--- a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmHaStatus.java
+++ b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmHaStatus.java
@@ -3,5 +3,6 @@
public enum ApplianceVmHaStatus {
NoHa,
Master,
- Backup
+ Backup,
+ Fault
}
diff --git a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmInventoryDoc_zh_cn.groovy b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmInventoryDoc_zh_cn.groovy
index 18d5a20dbf..f8bce85f6b 100644
--- a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmInventoryDoc_zh_cn.groovy
+++ b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmInventoryDoc_zh_cn.groovy
@@ -43,6 +43,12 @@ doc {
type "Integer"
since "0.6"
}
+ field {
+ name "haStatus"
+ desc ""
+ type "String"
+ since "5.4.2"
+ }
field {
name "uuid"
desc "资源的UUID,唯一标示该资源"
@@ -109,6 +115,12 @@ doc {
type "String"
since "0.6"
}
+ field {
+ name "architecture"
+ desc ""
+ type "String"
+ since "5.4.2"
+ }
field {
name "defaultL3NetworkUuid"
desc ""
@@ -133,6 +145,12 @@ doc {
type "Long"
since "0.6"
}
+ field {
+ name "reservedMemorySize"
+ desc ""
+ type "Long"
+ since "5.4.2"
+ }
field {
name "cpuNum"
desc ""
@@ -185,4 +203,10 @@ doc {
since "0.6"
clz VolumeInventory.class
}
+ field {
+ name "guestOsType"
+ desc ""
+ type "String"
+ since "5.4.2"
+ }
}
diff --git a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmNicBootstrapExtensionPoint.java b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmNicBootstrapExtensionPoint.java
new file mode 100644
index 0000000000..ce9173f169
--- /dev/null
+++ b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmNicBootstrapExtensionPoint.java
@@ -0,0 +1,7 @@
+package org.zstack.appliancevm;
+
+import org.zstack.header.vm.VmNicInventory;
+
+public interface ApplianceVmNicBootstrapExtensionPoint {
+ void fillNicBootstrapInfo(VmNicInventory nic, ApplianceVmNicTO nicTo);
+}
diff --git a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmNicTO.java b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmNicTO.java
index 3f58eacd3a..c9905a7866 100755
--- a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmNicTO.java
+++ b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmNicTO.java
@@ -24,6 +24,7 @@ public class ApplianceVmNicTO {
private Integer prefixLength;
private String gateway6;
private String addressMode;
+ private String bondMode;
public ApplianceVmNicTO(VmNicInventory inv) {
for (UsedIpInventory uip : inv.getUsedIps()) {
@@ -178,4 +179,12 @@ public String getAddressMode() {
public void setAddressMode(String addressMode) {
this.addressMode = addressMode;
}
+
+ public String getBondMode() {
+ return bondMode;
+ }
+
+ public void setBondMode(String bondMode) {
+ this.bondMode = bondMode;
+ }
}
diff --git a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmSubTypeFactory.java b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmSubTypeFactory.java
index 0f4a9d892f..b0bc0470c7 100755
--- a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmSubTypeFactory.java
+++ b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmSubTypeFactory.java
@@ -10,4 +10,6 @@ public interface ApplianceVmSubTypeFactory {
ApplianceVmVO persistApplianceVm(ApplianceVmSpec spec, ApplianceVmVO apvm);
void removeApplianceVm(ApplianceVmSpec spec, ApplianceVmVO apvm);
+
+ default void createApplianceNicSpec(ApplianceVmSpec spec) {}
}
diff --git a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApvmCascadeFilterExtensionPoint.java b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApvmCascadeFilterExtensionPoint.java
index be9ab31b22..cd6d890359 100644
--- a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApvmCascadeFilterExtensionPoint.java
+++ b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApvmCascadeFilterExtensionPoint.java
@@ -3,16 +3,35 @@
import org.zstack.core.cascade.CascadeAction;
import org.zstack.header.network.l3.UsedIpInventory;
import org.zstack.header.vm.VmNicInventory;
-import org.zstack.network.service.vip.VipInventory;
import java.util.List;
/**
+ * Appliance VM cascade deletion filter extension point - Factory pattern
+ * Each implementation handles cascade deletion logic for specific appliance VM type
+ *
* Created by weiwang on 22/10/2017
*/
public interface ApvmCascadeFilterExtensionPoint {
+ /**
+ * Filter appliance VMs that need to be cascade deleted
+ *
+ * @param applianceVmVOS appliance VM list to process
+ * @param action cascade action
+ * @param parentIssuer parent resource type
+ * @param parentIssuerUuids parent resource UUID list
+ * @param toDeleteNics nics to be deleted (output parameter)
+ * @param toDeleteIps IPs to be deleted (output parameter)
+ * @return filtered VM list to delete
+ */
List filterApplianceVmCascade(List applianceVmVOS, CascadeAction action,
String parentIssuer, List parentIssuerUuids,
List toDeleteNics,
List toDeleteIps);
+
+ /**
+ * Check if this factory supports the specified appliance VM type
+ * @return true if supported, false otherwise
+ */
+ ApplianceVmType getApplianceVmType();
}
diff --git a/plugin/cbd/src/main/java/org/zstack/cbd/CbdConstants.java b/plugin/cbd/src/main/java/org/zstack/cbd/CbdConstants.java
deleted file mode 100644
index 4e96f6cf85..0000000000
--- a/plugin/cbd/src/main/java/org/zstack/cbd/CbdConstants.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.zstack.cbd;
-
-import org.zstack.header.configuration.PythonClass;
-
-/**
- * @author Xingwei Yu
- * @date 2024/4/10 23:28
- */
-@PythonClass
-public interface CbdConstants {
- String MDS_PARAM_MDS_PORT = "mdsPort";
-}
diff --git a/plugin/cbd/src/main/java/org/zstack/cbd/Config.java b/plugin/cbd/src/main/java/org/zstack/cbd/Config.java
deleted file mode 100644
index 99a08cf62d..0000000000
--- a/plugin/cbd/src/main/java/org/zstack/cbd/Config.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.zstack.cbd;
-
-import java.util.List;
-
-/**
- * @author Xingwei Yu
- * @date 2024/4/2 11:13
- */
-public class Config {
- private List mdsUrls;
- private String logicalPoolName;
-
- public List getMdsUrls() {
- return mdsUrls;
- }
-
- public void setMdsUrls(List mdsUrls) {
- this.mdsUrls = mdsUrls;
- }
-
- public String getLogicalPoolName() {
- return logicalPoolName;
- }
-
- public void setLogicalPoolName(String logicalPoolName) {
- this.logicalPoolName = logicalPoolName;
- }
-}
diff --git a/plugin/cbd/src/main/java/org/zstack/cbd/kvm/KvmCbdCommands.java b/plugin/cbd/src/main/java/org/zstack/cbd/kvm/KvmCbdCommands.java
index 52653a0bc4..e761c33193 100644
--- a/plugin/cbd/src/main/java/org/zstack/cbd/kvm/KvmCbdCommands.java
+++ b/plugin/cbd/src/main/java/org/zstack/cbd/kvm/KvmCbdCommands.java
@@ -1,9 +1,9 @@
package org.zstack.cbd.kvm;
-import org.zstack.cbd.MdsInfo;
import org.zstack.kvm.KVMAgentCommands;
import java.util.List;
+import java.util.Map;
/**
* @author Xingwei Yu
@@ -19,23 +19,10 @@ public static class AgentRsp {
public String error;
}
- public static class KvmUpdateClientConfCmd extends AgentCmd {
- private List mdsInfos;
-
- public List getMdsInfos() {
- return mdsInfos;
- }
-
- public void setMdsInfos(List mdsInfos) {
- this.mdsInfos = mdsInfos;
- }
- }
-
public static class KvmSetupSelfFencerCmd extends AgentCmd {
public long interval;
public int maxAttempts;
- public List coveringPaths;
- public String heartbeatUrl;
+ public Map heartbeatPathByCoveringPaths;
public int storageCheckerTimeout;
public String hostUuid;
public Integer hostId;
diff --git a/plugin/cbd/src/main/java/org/zstack/cbd/kvm/KvmCbdNodeServer.java b/plugin/cbd/src/main/java/org/zstack/cbd/kvm/KvmCbdNodeServer.java
index 006d726054..d53cfa3bb9 100644
--- a/plugin/cbd/src/main/java/org/zstack/cbd/kvm/KvmCbdNodeServer.java
+++ b/plugin/cbd/src/main/java/org/zstack/cbd/kvm/KvmCbdNodeServer.java
@@ -19,22 +19,22 @@
import org.zstack.header.host.HostInventory;
import org.zstack.header.host.HostVO;
import org.zstack.header.message.MessageReply;
-import org.zstack.header.storage.addon.primary.HeartbeatVolumeTO;
-import org.zstack.header.storage.addon.primary.PrimaryStorageNodeSvc;
-import org.zstack.header.storage.addon.primary.ExternalPrimaryStorageHostRefVO;
-import org.zstack.header.storage.addon.primary.ExternalPrimaryStorageHostRefVO_;
+import org.zstack.header.storage.addon.primary.*;
+import org.zstack.header.vm.VmInstanceInventory;
+import org.zstack.header.vm.VmInstanceSpec;
+import org.zstack.header.volume.VolumeInventory;
import org.zstack.header.volume.VolumeProtocol;
-import org.zstack.kvm.KVMAgentCommands;
-import org.zstack.kvm.KVMHostAsyncHttpCallMsg;
-import org.zstack.kvm.KVMHostAsyncHttpCallReply;
-import org.zstack.kvm.KvmSetupSelfFencerExtensionPoint;
+import org.zstack.kvm.*;
import org.zstack.storage.addon.primary.ExternalHostIdGetter;
import org.zstack.storage.addon.primary.ExternalPrimaryStorageFactory;
import org.zstack.utils.DebugUtils;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
import static org.zstack.core.Platform.operr;
@@ -42,7 +42,8 @@
* @author Xingwei Yu
* @date 2024/4/9 16:22
*/
-public class KvmCbdNodeServer implements Component, KvmSetupSelfFencerExtensionPoint {
+public class KvmCbdNodeServer implements Component, KvmSetupSelfFencerExtensionPoint, KVMStartVmExtensionPoint,
+ KVMConvertVolumeExtensionPoint, KVMDetachVolumeExtensionPoint, KVMAttachVolumeExtensionPoint {
private static final CLogger logger = Utils.getLogger(KvmCbdNodeServer.class);
@Autowired
@@ -74,7 +75,7 @@ public void kvmSetupSelfFencer(KvmSetupSelfFencerParam param, Completion complet
FlowChain chain = FlowChainBuilder.newShareFlowChain();
chain.setName(String.format("setup-self-fencer-for-external-primary-storage-%s-on-kvm-%s", param.getPrimaryStorage().getUuid(), host.getUuid()));
chain.then(new ShareFlow() {
- HeartbeatVolumeTO heartbeatVol;
+ HeartbeatVolumeTopology heartbeatVolumeTopology;
@Override
public void setup() {
@@ -102,10 +103,10 @@ public void fail(ErrorCode errorCode) {
@Override
public void run(FlowTrigger trigger, Map data) {
- nodeSvc.activateHeartbeatVolume(host, new ReturnValueCompletion(trigger) {
+ nodeSvc.activateHeartbeatVolume(host, new ReturnValueCompletion(trigger) {
@Override
- public void success(HeartbeatVolumeTO returnValue) {
- heartbeatVol = returnValue;
+ public void success(HeartbeatVolumeTopology topology) {
+ heartbeatVolumeTopology = topology;
trigger.next();
}
@@ -134,10 +135,13 @@ public void run(FlowTrigger trigger, Map data) {
KvmSetupSelfFencerCmd cmd = new KvmSetupSelfFencerCmd();
cmd.interval = param.getInterval();
cmd.maxAttempts = param.getMaxAttempts();
- cmd.coveringPaths = heartbeatVol.getCoveringPaths();
- cmd.heartbeatUrl = heartbeatVol.getInstallPath();
+ cmd.heartbeatPathByCoveringPaths = heartbeatVolumeTopology
+ .getHeartbeatVolumeByCoveringPaths().entrySet().stream().collect(Collectors.toMap(
+ Map.Entry::getKey, it -> it.getValue().getInstallPath()
+ ));
cmd.storageCheckerTimeout = param.getStorageCheckerTimeout();
- cmd.heartbeatRequiredSpace = heartbeatVol.getHeartbeatRequiredSpace();
+ cmd.heartbeatRequiredSpace = heartbeatVolumeTopology.getHeartbeatVolumeByCoveringPaths()
+ .values().iterator().next().getHeartbeatRequiredSpace();
cmd.hostUuid = param.getHostUuid();
cmd.hostId = ref.getHostId();
cmd.strategy = param.getStrategy();
@@ -220,4 +224,89 @@ public void run(MessageReply reply) {
}
});
}
+
+ private PrimaryStorageNodeSvc getNodeService(VolumeInventory volumeInventory) {
+ String identity = volumeInventory.getInstallPath().split("://")[0];
+ if (!extPsFactory.support(identity)) {
+ return null;
+ }
+
+ return extPsFactory.getNodeSvc(volumeInventory.getPrimaryStorageUuid());
+ }
+
+ private VolumeTO convertVolumeIfNeeded(VolumeInventory volumeInventory, HostInventory host, VolumeTO volumeTO) {
+ if (!VolumeProtocol.CBD.name().equals(volumeInventory.getProtocol())) {
+ return volumeTO;
+ }
+
+ PrimaryStorageNodeSvc nodeSvc = getNodeService(volumeInventory);
+ if (nodeSvc == null) {
+ return volumeTO;
+ }
+
+ String path = nodeSvc.getActivePath(BaseVolumeInfo.valueOf(volumeInventory), host,false);
+ volumeTO.setInstallPath(path);
+ return volumeTO;
+ }
+
+ @Override
+ public void beforeAttachVolume(KVMHostInventory host, VmInstanceInventory vm, VolumeInventory volume, KVMAgentCommands.AttachDataVolumeCmd cmd, Map data) {
+ cmd.setVolume(convertVolumeIfNeeded(volume, host, cmd.getVolume()));
+ }
+
+ @Override
+ public void afterAttachVolume(KVMHostInventory host, VmInstanceInventory vm, VolumeInventory volume, KVMAgentCommands.AttachDataVolumeCmd cmd) {
+ }
+
+ @Override
+ public void attachVolumeFailed(KVMHostInventory host, VmInstanceInventory vm, VolumeInventory volume, KVMAgentCommands.AttachDataVolumeCmd cmd, ErrorCode err, Map data) {
+
+ }
+
+ @Override
+ public VolumeTO convertVolumeIfNeed(KVMHostInventory host, VolumeInventory inventory, VolumeTO to) {
+ return convertVolumeIfNeeded(inventory, host, to);
+ }
+
+ @Override
+ public void beforeDetachVolume(KVMHostInventory host, VmInstanceInventory vm, VolumeInventory volume, KVMAgentCommands.DetachDataVolumeCmd cmd) {
+ cmd.setVolume(convertVolumeIfNeeded(volume, host, cmd.getVolume()));
+ }
+
+ @Override
+ public void afterDetachVolume(KVMHostInventory host, VmInstanceInventory vm, VolumeInventory volume, KVMAgentCommands.DetachDataVolumeCmd cmd) {
+
+ }
+
+ @Override
+ public void detachVolumeFailed(KVMHostInventory host, VmInstanceInventory vm, VolumeInventory volume, KVMAgentCommands.DetachDataVolumeCmd cmd, ErrorCode err) {
+
+ }
+
+ @Override
+ public void beforeStartVmOnKvm(KVMHostInventory host, VmInstanceSpec spec, KVMAgentCommands.StartVmCmd cmd) {
+ cmd.setRootVolume(convertVolumeIfNeeded(spec.getDestRootVolume(), host, cmd.getRootVolume()));
+
+ List dtos = new ArrayList<>();
+ for (VolumeTO to : cmd.getDataVolumes()) {
+ for (VolumeInventory vol : spec.getDestDataVolumes()) {
+ if (vol.getUuid().equals(to.getVolumeUuid())) {
+ dtos.add(convertVolumeIfNeeded(vol, host, to));
+ break;
+ }
+ }
+ }
+
+ cmd.setDataVolumes(dtos);
+ }
+
+ @Override
+ public void startVmOnKvmSuccess(KVMHostInventory host, VmInstanceSpec spec) {
+
+ }
+
+ @Override
+ public void startVmOnKvmFailed(KVMHostInventory host, VmInstanceSpec spec, ErrorCode err) {
+
+ }
}
diff --git a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java
index 562067654c..00dcaebe02 100755
--- a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java
+++ b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageBase.java
@@ -1848,6 +1848,7 @@ public void run(MessageReply reply) {
chain.done(new FlowDoneHandler(completion) {
@Override
public void handle(Map data) {
+ //TODO: replace with ReleasePrimaryStorageSpaceMsg
IncreasePrimaryStorageCapacityMsg imsg = new IncreasePrimaryStorageCapacityMsg();
imsg.setPrimaryStorageUuid(self.getUuid());
imsg.setDiskSize(inv.getSize());
@@ -1944,6 +1945,7 @@ public void run(MessageReply reply) {
chain.done(new FlowDoneHandler(coml) {
@Override
public void handle(Map data) {
+ // TODO: replace with ReleasePrimaryStorageSpaceMsg
IncreasePrimaryStorageCapacityMsg imsg = new IncreasePrimaryStorageCapacityMsg();
imsg.setPrimaryStorageUuid(self.getUuid());
imsg.setDiskSize(inv.getSize());
@@ -2512,7 +2514,7 @@ public void run(final SyncTaskChain chain) {
if (cache != null) {
final CheckIsBitsExistingCmd cmd = new CheckIsBitsExistingCmd();
- cmd.setInstallPath(ImageCacheUtil.getImageCachePath(cache.toInventory()));
+ cmd.setInstallPath(ImageCacheUtil.getImageCachePath(cache.getInstallUrl()));
httpCall(CHECK_BITS_PATH, cmd, CheckIsBitsExistingRsp.class, new ReturnValueCompletion(chain) {
@Override
public void success(CheckIsBitsExistingRsp returnValue) {
@@ -2527,9 +2529,10 @@ public void success(CheckIsBitsExistingRsp returnValue) {
q.add(ImageCacheVO_.imageUuid, Op.EQ, image.getInventory().getUuid());
ImageCacheVO cvo = q.find();
- IncreasePrimaryStorageCapacityMsg imsg = new IncreasePrimaryStorageCapacityMsg();
+ ReleasePrimaryStorageSpaceMsg imsg = new ReleasePrimaryStorageSpaceMsg();
imsg.setDiskSize(cvo.getSize());
imsg.setPrimaryStorageUuid(cvo.getPrimaryStorageUuid());
+ imsg.setAllocatedInstallUrl(cvo.getInstallUrl());
bus.makeTargetServiceIdByResourceUuid(imsg, PrimaryStorageConstant.SERVICE_ID, cvo.getPrimaryStorageUuid());
bus.send(imsg);
dbf.remove(cvo);
@@ -3320,7 +3323,8 @@ protected void handle(AskVolumeSnapshotCapabilityMsg msg) {
if (VolumeType.Data.toString().equals(volumeType) || VolumeType.Root.toString().equals(volumeType)) {
cap.setSupport(true);
cap.setArrangementType(VolumeSnapshotArrangementType.INDIVIDUAL);
- cap.setVolumePathFromInnerSnapshotRegex("^[^@]+");
+ cap.setPlacementType(VolumeSnapshotCapability.VolumeSnapshotPlacementType.INTERNAL);
+ cap.setVolumePathFromInternalSnapshotRegex("^[^@]+");
} else if (VolumeType.Memory.toString().equals(volumeType)) {
cap.setSupport(false);
} else {
@@ -4722,7 +4726,7 @@ private void deleteImageCacheOnPrimaryStorage(DeleteImageCacheOnPrimaryStorageMs
DeleteImageCacheCmd cmd = new DeleteImageCacheCmd();
cmd.setFsId(getSelf().getFsid());
cmd.setUuid(self.getUuid());
- cmd.imagePath = msg.getInstallPath().split("@")[0];
+ cmd.imagePath = getVolumePathFromSnapshot(msg.getInstallPath());
cmd.snapshotPath = msg.getInstallPath();
httpCall(DELETE_IMAGE_CACHE, cmd, AgentResponse.class, new ReturnValueCompletion(msg) {
@Override
@@ -5172,7 +5176,7 @@ public void setup() {
boolean fastRevert = VolumeSnapshotGlobalConfig.ENABLE_FAST_REVERT.value(Boolean.class);
String snapShotPath = msg.getSnapshot().getPrimaryStorageInstallPath();
// get volume path from snapshot path, just split @
- String volumePath = snapShotPath.split("@")[0];
+ String volumePath = getVolumePathFromSnapshot(snapShotPath);
final String newVolumePath = makeVolumeInstallPathByTargetPool(Platform.getUuid(), getTargetPoolNameFromAllocatedUrl(snapShotPath));
flow(new NoRollbackFlow() {
@@ -5437,7 +5441,7 @@ private void deleteSnapshotOnPrimaryStorage(final DeleteSnapshotOnPrimaryStorage
httpCall(DELETE_SNAPSHOT_PATH, cmd, DeleteSnapshotRsp.class, new ReturnValueCompletion(msg) {
@Override
public void success(DeleteSnapshotRsp returnValue) {
- osdHelper.releaseAvailableCapWithRatio(msg.getSnapshot().getPrimaryStorageInstallPath(), msg.getSnapshot().getSize());
+ osdHelper.releaseAvailableCapacity(msg.getSnapshot().getPrimaryStorageInstallPath(), msg.getSnapshot().getSize());
bus.reply(msg, reply);
completion.done();
}
@@ -6078,6 +6082,18 @@ private void handle(GetPrimaryStorageUsageReportMsg msg) {
bus.reply(msg, reply);
}
+ @Override
+ protected void handle(GetOwningVolumePathFromInternalSnapshotMsg msg) {
+ GetOwningVolumePathFromInternalSnapshotReply reply = new GetOwningVolumePathFromInternalSnapshotReply();
+ if (msg.getSnapshotPaths() != null) {
+ for (String snapshotPath : msg.getSnapshotPaths()) {
+ reply.putOwningVolumePath(snapshotPath, getVolumePathFromSnapshot(snapshotPath));
+ }
+ }
+
+ bus.reply(msg, reply);
+ }
+
protected void handle(CleanUpStorageTrashOnPrimaryStorageMsg msg) {
CleanUpStorageTrashOnPrimaryStorageReply reply = new CleanUpStorageTrashOnPrimaryStorageReply();
thdf.singleFlightSubmit(new SingleFlightTask(msg)
@@ -6142,6 +6158,10 @@ private String makeCephPath(String originPath) {
return String.format("ceph://%s", originPath);
}
+ private static String getVolumePathFromSnapshot(String snapshotPath) {
+ return snapshotPath.split("@")[0];
+ }
+
protected String getTargetPoolNameFromAllocatedUrl(String allocatedUrl) {
if (allocatedUrl == null) {
throw new OperationFailureException(operr("allocated url not found"));
diff --git a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageFactory.java b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageFactory.java
index cb7dde9c5c..a3906011ef 100755
--- a/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageFactory.java
+++ b/plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephPrimaryStorageFactory.java
@@ -1249,10 +1249,12 @@ public void preReleaseVmResource(VmInstanceSpec spec, Completion completion) {
}
@Override
- public String buildAllocatedInstallUrl(AllocatePrimaryStorageSpaceMsg msg, PrimaryStorageInventory psInv) {
+ public String allocateSpaceDryRun(AllocatePrimaryStorageSpaceMsg msg, PrimaryStorageInventory psInv) {
if (msg.getRequiredInstallUri() != null) {
CephRequiredUrlParser.InstallPath path = CephRequiredUrlParser.getInstallPathFromUri(msg.getRequiredInstallUri());
- checkCephPoolCapacityForNewVolume(path.poolName, msg.getSize(), psInv.getUuid());
+ if (!msg.isForce()) {
+ checkCephPoolCapacityForNewVolume(path.poolName, msg.getSize(), psInv.getUuid());
+ }
return path.fullPath;
}
diff --git a/plugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java b/plugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java
index ca72e1a08b..8092ce34d6 100644
--- a/plugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java
+++ b/plugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java
@@ -91,9 +91,10 @@ public class ExponStorageController implements PrimaryStorageControllerSvc, Prim
VolumeSnapshotCapability scap = new VolumeSnapshotCapability();
scap.setSupport(true);
scap.setArrangementType(VolumeSnapshotCapability.VolumeSnapshotArrangementType.INDIVIDUAL);
+ scap.setPlacementType(VolumeSnapshotCapability.VolumeSnapshotPlacementType.INTERNAL);
scap.setSupportCreateOnHypervisor(false);
scap.setSupportLazyDelete(true);
- scap.setVolumePathFromInnerSnapshotRegex("^[^@]+");
+ scap.setVolumePathFromInternalSnapshotRegex("^[^@]+");
capabilities.setSnapshotCapability(scap);
capabilities.setSupportCloneFromVolume(false);
capabilities.setSupportStorageQos(true);
@@ -624,7 +625,7 @@ public void blacklist(String installPath, String protocol, HostInventory h, Comp
}
@Override
- public synchronized void activateHeartbeatVolume(HostInventory h, ReturnValueCompletion comp) {
+ public synchronized void activateHeartbeatVolume(HostInventory h, ReturnValueCompletion comp) {
String clientIqn = IscsiUtils.getHostInitiatorName(h.getUuid());
if (clientIqn == null) {
throw new RuntimeException(String.format("cannot get host[uuid:%s] initiator name", h.getUuid()));
@@ -661,7 +662,9 @@ public synchronized void activateHeartbeatVolume(HostInventory h, ReturnValueCom
to.setHostId(getHostId(h));
to.setHeartbeatRequiredSpace(SizeUnit.MEGABYTE.toByte(1));
to.setCoveringPaths(Collections.singletonList(vhostSocketDir));
- comp.success(to);
+ HeartbeatVolumeTopology topology = new HeartbeatVolumeTopology();
+ topology.setHeartbeatVolumeByCoveringPaths(Collections.singletonMap(vhostSocketDir, to));
+ comp.success(topology);
}
// hardcode
@@ -703,7 +706,7 @@ public void deactivateHeartbeatVolume(HostInventory h, Completion comp) {
}
@Override
- public HeartbeatVolumeTO getHeartbeatVolumeActiveInfo(HostInventory h) {
+ public HeartbeatVolumeTopology getHeartbeatVolumeActiveInfo(HostInventory h) {
String tianshuId = addonInfo.getClusters().get(0).getId();
List nodes = getIscsiServers(tianshuId);
@@ -729,7 +732,10 @@ public HeartbeatVolumeTO getHeartbeatVolumeActiveInfo(HostInventory h) {
to.setHostId(getHostId(h));
to.setHeartbeatRequiredSpace(SizeUnit.MEGABYTE.toByte(1));
to.setCoveringPaths(Collections.singletonList(vhostSocketDir));
- return to;
+
+ HeartbeatVolumeTopology topology = new HeartbeatVolumeTopology();
+ topology.setHeartbeatVolumeByCoveringPaths(Collections.singletonMap(vhostSocketDir, to));
+ return topology;
}
private void deactivateVhost(String installPath, HostInventory h) {
@@ -884,6 +890,26 @@ private void reloadDbInfo() {
config = StringUtils.isEmpty(self.getConfig()) ? new ExponConfig() : JSONObjectUtil.toObject(self.getConfig(), ExponConfig.class);
}
+ // TODO: add more not found handling when support multi pool
+ @Override
+ public void getCapacity(List locationUrl, ReturnValueCompletion comp) {
+ List pools = getSelfPools();
+ StorageCapacity cap = new StorageCapacity();
+ long total = pools.stream().mapToLong(FailureDomainModule::getValidSize).sum();
+ long avail = total - pools.stream().mapToLong(FailureDomainModule::getRealDataSize).sum();
+ cap.setAvailableCapacity(avail);
+ cap.setTotalCapacity(total);
+ for (String url : locationUrl) {
+ String poolName = getPoolNameFromPath(url);
+ FailureDomainModule pool = pools.stream().filter(it -> it.getFailureDomainName().equals(poolName)).findFirst().orElse(null);
+ if (pool != null) {
+ cap.putCapacity(url, pool.getValidSize() - pool.getRealDataSize(), pool.getValidSize());
+ }
+ }
+
+ comp.success(cap);
+ }
+
@Override
public void reportCapacity(ReturnValueCompletion comp) {
reloadDbInfo();
@@ -1309,8 +1335,8 @@ public void revertVolumeSnapshot(String snapshotInstallPath, ReturnValueCompleti
}
@Override
- public void validateConfig(String config) {
-
+ public String validateConfig(String config) {
+ return config;
}
@Override
diff --git a/plugin/externalStorage/src/main/java/org/zstack/externalStorage/primary/ExternalPrimaryStorageAllocator.java b/plugin/externalStorage/src/main/java/org/zstack/externalStorage/primary/ExternalPrimaryStorageAllocator.java
new file mode 100644
index 0000000000..99b5849d1f
--- /dev/null
+++ b/plugin/externalStorage/src/main/java/org/zstack/externalStorage/primary/ExternalPrimaryStorageAllocator.java
@@ -0,0 +1,128 @@
+package org.zstack.externalStorage.primary;
+
+import groovy.lang.Tuple;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.zstack.compute.vm.VmAllocateHostAndPrimaryStorageFlow;
+import org.zstack.compute.vm.VmAllocateHostFlow;
+import org.zstack.core.db.Q;
+import org.zstack.externalStorage.primary.kvm.ExternalPrimaryStorageKvmFactory;
+import org.zstack.header.core.workflow.Flow;
+import org.zstack.header.core.workflow.FlowChain;
+import org.zstack.header.core.workflow.FlowTrigger;
+import org.zstack.header.core.workflow.NoRollbackFlow;
+import org.zstack.header.storage.addon.primary.PrimaryStorageControllerSvc;
+import org.zstack.header.storage.addon.primary.StorageCapabilities;
+import org.zstack.header.storage.primary.ImageCacheVO;
+import org.zstack.header.storage.primary.ImageCacheVO_;
+import org.zstack.header.vm.MarshalVmOperationFlowExtensionPoint;
+import org.zstack.header.vm.VmInstanceConstant;
+import org.zstack.header.vm.VmInstanceSpec;
+import org.zstack.storage.addon.primary.ExternalPrimaryStorageFactory;
+import org.zstack.storage.addon.primary.ExternalPrimaryStorageSpaceHelper;
+import org.zstack.storage.addon.primary.ExternalPrimaryStorageSystemTags;
+import org.zstack.storage.primary.ImageCacheUtil;
+import org.zstack.utils.Utils;
+import org.zstack.utils.logging.CLogger;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static org.zstack.core.Platform.operr;
+
+public class ExternalPrimaryStorageAllocator implements MarshalVmOperationFlowExtensionPoint {
+ private static final CLogger logger = Utils.getLogger(ExternalPrimaryStorageAllocator.class);
+
+ @Autowired
+ private ExternalPrimaryStorageFactory extPsFactory;
+
+ @Override
+ public Flow marshalVmOperationFlow(String previousFlowName, String nextFlowName, FlowChain chain, VmInstanceSpec spec) {
+ if (VmAllocateHostAndPrimaryStorageFlow.class.getName().equals(nextFlowName)) {
+ if (spec.getCurrentVmOperation() != VmInstanceConstant.VmOperation.NewCreate || !spec.getImageSpec().relyOnImageCache()) {
+ return null;
+ }
+
+ if (extPsFactory.getAllControllerSvcs().isEmpty()) {
+ return null;
+ }
+
+ List candidatePsUuid = spec.getCandidatePrimaryStorageUuidsForRootVolume();
+ List ts = null;
+ if (candidatePsUuid == null || candidatePsUuid.isEmpty()) {
+ ts = Q.New(ImageCacheVO.class).select(ImageCacheVO_.primaryStorageUuid, ImageCacheVO_.installUrl)
+ .eq(ImageCacheVO_.imageUuid, spec.getImageSpec().getInventory().getUuid())
+ .listValues();
+ candidatePsUuid = ts.stream().map(it -> (String) it.get(0)).distinct().collect(Collectors.toList());
+ }
+
+ // TODO only consider the situation that there is only one candidate primary storage such as fast create
+ if (candidatePsUuid.size() != 1) {
+ logger.warn(String.format("ExternalPrimaryStorageAllocator only supports one candidate primary storage, found candidates: %s", candidatePsUuid));
+ return null;
+ }
+
+ String requiredPsUuid = candidatePsUuid.get(0);
+ PrimaryStorageControllerSvc controller = extPsFactory.getControllerSvc(requiredPsUuid);
+ if (controller == null) {
+ return null;
+ }
+ StorageCapabilities cap = controller.reportCapabilities();
+ if (!cap.isSupportMultiSpace() || cap.isSupportCloneFromAnotherSpace()) {
+ return null;
+ }
+
+ List rootSysTags = spec.getRootVolumeSystemTags();
+ List cacheInstallUrls = new ArrayList<>();
+ if (ts != null) {
+ for (Tuple t : ts) {
+ if (requiredPsUuid.equals(t.get(0))) {
+ cacheInstallUrls.add(ImageCacheUtil.getImageCachePath((String) t.get(1)));
+ }
+ }
+ } else {
+ cacheInstallUrls = Q.New(ImageCacheVO.class).select(ImageCacheVO_.installUrl)
+ .eq(ImageCacheVO_.imageUuid, spec.getImageSpec().getInventory().getUuid())
+ .eq(ImageCacheVO_.primaryStorageUuid, requiredPsUuid)
+ .listValues().stream().map(it -> ImageCacheUtil.getImageCachePath((String) it)).collect(Collectors.toList());
+ }
+ if (cacheInstallUrls.isEmpty()) {
+ logger.warn(String.format("no candidate URLs found for image cache[uuid:%s] on primary storage[uuid:%s]",
+ spec.getImageSpec().getInventory().getUuid(), requiredPsUuid));
+ return null;
+ }
+
+ ExternalPrimaryStorageSpaceHelper helper = new ExternalPrimaryStorageSpaceHelper(requiredPsUuid, controller.getIdentity());
+ List candidateUrls = cacheInstallUrls.stream()
+ .map(helper::getLocationSpaceUrl)
+ .collect(Collectors.toList());
+
+ String requiredUrlTag = rootSysTags == null ? null :
+ rootSysTags.stream().filter(ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL::isMatch).findFirst().orElse(null);
+ if (requiredUrlTag != null) {
+ String requiredUrl = ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL.getTokenByTag(
+ requiredUrlTag, ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL_TOKEN).replaceAll("/$", "");
+ if (candidateUrls.contains(requiredUrl)) {
+ return null;
+ } else {
+ return new NoRollbackFlow() {
+ @Override
+ public void run(FlowTrigger trigger, Map data) {
+ trigger.fail(operr("creation relies on image cache[uuid:%s, locate urls: [%s]], cannot create other places.", spec.getImageSpec().getInventory().getUuid(), candidateUrls));
+
+ }
+ };
+ }
+ } else {
+ spec.addRootVolumeSystemTag(ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL.instantiateTag(
+ Collections.singletonMap(ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL_TOKEN, candidateUrls.get(0)))
+ );
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/plugin/externalStorage/src/main/java/org/zstack/externalStorage/primary/ExternalStorageFencerType.java b/plugin/externalStorage/src/main/java/org/zstack/externalStorage/primary/ExternalStorageFencerType.java
index 50031d7b4e..5213c81482 100644
--- a/plugin/externalStorage/src/main/java/org/zstack/externalStorage/primary/ExternalStorageFencerType.java
+++ b/plugin/externalStorage/src/main/java/org/zstack/externalStorage/primary/ExternalStorageFencerType.java
@@ -8,12 +8,14 @@
* @author Xingwei Yu
* @date 2024/8/21 10:38
*/
+// TODO refactor it, use controller interface not this fencer type class
public class ExternalStorageFencerType {
private static Map types = Collections.synchronizedMap(new HashMap());
private final String identity;
private final String protocol;
+ // TODO: refactor it, remove protocol
public ExternalStorageFencerType(String identity, String protocol) {
if (types.containsKey(identity)) {
throw new IllegalArgumentException(String.format("duplicate ExternalStorageNodeServer for identity[%s]", identity));
diff --git a/plugin/externalStorage/src/main/java/org/zstack/externalStorage/primary/kvm/ExternalPrimaryStorageKvmFactory.java b/plugin/externalStorage/src/main/java/org/zstack/externalStorage/primary/kvm/ExternalPrimaryStorageKvmFactory.java
index e8b55f2343..c6eb04a855 100644
--- a/plugin/externalStorage/src/main/java/org/zstack/externalStorage/primary/kvm/ExternalPrimaryStorageKvmFactory.java
+++ b/plugin/externalStorage/src/main/java/org/zstack/externalStorage/primary/kvm/ExternalPrimaryStorageKvmFactory.java
@@ -131,7 +131,12 @@ public void run(FlowTrigger trigger, Map data) {
deployClient(context, extPss, new WhileDoneCompletion(trigger) {
@Override
public void done(ErrorCodeList errorCodeList) {
- trigger.next();
+ if (errorCodeList.getCauses().isEmpty()) {
+ trigger.next();
+ } else {
+ // todo rollback
+ trigger.fail(errorCodeList.getCauses().get(0));
+ }
}
});
}
diff --git a/plugin/flatNetworkProvider/src/main/java/org/zstack/network/service/flat/FlatDhcpBackend.java b/plugin/flatNetworkProvider/src/main/java/org/zstack/network/service/flat/FlatDhcpBackend.java
index 2300f17cae..7daff5e7b4 100755
--- a/plugin/flatNetworkProvider/src/main/java/org/zstack/network/service/flat/FlatDhcpBackend.java
+++ b/plugin/flatNetworkProvider/src/main/java/org/zstack/network/service/flat/FlatDhcpBackend.java
@@ -39,7 +39,11 @@
import org.zstack.header.network.l2.L2NetworkInventory;
import org.zstack.header.network.l2.L2NetworkVO;
import org.zstack.header.network.l3.*;
+import org.zstack.header.network.l3.SdnControllerUpdateDHCPMsg;
+import org.zstack.header.network.sdncontroller.SdnControllerConstant;
import org.zstack.header.network.service.*;
+import org.zstack.network.l3.L3NetworkHelper;
+
import org.zstack.header.vm.*;
import org.zstack.header.vm.VmAbnormalLifeCycleStruct.VmAbnormalLifeCycleOperation;
import org.zstack.identity.AccountManager;
@@ -363,21 +367,24 @@ public void fail(ErrorCode errorCode) {
@Override
public void run(FlowTrigger trigger, Map data) {
- if (sdnDhcp == null) {
+ String sdnControllerUuid = L3NetworkHelper.getSdnControllerUuidFromL3Uuid(l3VO.getUuid());
+ if (sdnControllerUuid == null) {
trigger.next();
return;
}
- sdnDhcp.enableDhcp(Collections.singletonList(L3NetworkInventory.valueOf(l3VO)),
- new Completion(trigger) {
+ SdnControllerUpdateDHCPMsg dmsg = new SdnControllerUpdateDHCPMsg();
+ dmsg.setL3NetworkUuid(l3VO.getUuid());
+ dmsg.setSdnControllerUuid(sdnControllerUuid);
+ bus.makeTargetServiceIdByResourceUuid(dmsg, SdnControllerConstant.SERVICE_ID, sdnControllerUuid);
+ bus.send(dmsg, new CloudBusCallBack(trigger) {
@Override
- public void success() {
- trigger.next();
- }
-
- @Override
- public void fail(ErrorCode errorCode) {
- trigger.fail(errorCode);
+ public void run(MessageReply reply) {
+ if (!reply.isSuccess()) {
+ trigger.fail(reply.getError());
+ } else {
+ trigger.next();
+ }
}
});
}
diff --git a/plugin/iscsi/src/main/java/org/zstack/iscsi/kvm/KvmIscsiNodeServer.java b/plugin/iscsi/src/main/java/org/zstack/iscsi/kvm/KvmIscsiNodeServer.java
index 31dddaa078..5ed3af6d28 100644
--- a/plugin/iscsi/src/main/java/org/zstack/iscsi/kvm/KvmIscsiNodeServer.java
+++ b/plugin/iscsi/src/main/java/org/zstack/iscsi/kvm/KvmIscsiNodeServer.java
@@ -9,7 +9,6 @@
import org.zstack.core.db.Q;
import org.zstack.core.workflow.FlowChainBuilder;
import org.zstack.core.workflow.ShareFlow;
-import org.zstack.externalStorage.primary.ExternalStorageConstant;
import org.zstack.header.Component;
import org.zstack.header.core.Completion;
import org.zstack.header.core.ReturnValueCompletion;
@@ -23,6 +22,7 @@
import org.zstack.header.message.MessageReply;
import org.zstack.header.storage.addon.primary.BaseVolumeInfo;
import org.zstack.header.storage.addon.primary.HeartbeatVolumeTO;
+import org.zstack.header.storage.addon.primary.HeartbeatVolumeTopology;
import org.zstack.header.storage.addon.primary.PrimaryStorageNodeSvc;
import org.zstack.header.vm.VmInstanceInventory;
import org.zstack.header.vm.VmInstanceMigrateExtensionPoint;
@@ -213,10 +213,11 @@ public void setup() {
@Override
public void run(FlowTrigger trigger, Map data) {
- nodeSvc.activateHeartbeatVolume(host, new ReturnValueCompletion(trigger) {
+ nodeSvc.activateHeartbeatVolume(host, new ReturnValueCompletion(trigger) {
@Override
- public void success(HeartbeatVolumeTO vol) {
- heartbeatVol = vol;
+ public void success(HeartbeatVolumeTopology topology) {
+ // TODO handle multiple heartbeat volumes
+ heartbeatVol = topology.getHeartbeatVolumeByCoveringPaths().values().iterator().next();
trigger.next();
}
diff --git a/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java b/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java
index 91e5d885bd..cf977cf23d 100755
--- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java
+++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java
@@ -1,6 +1,7 @@
package org.zstack.kvm;
import com.fasterxml.jackson.annotation.JsonAnySetter;
+import org.jetbrains.annotations.NotNull;
import org.zstack.core.upgrade.GrayUpgradeAgent;
import org.zstack.core.upgrade.GrayVersion;
import org.zstack.core.validation.ConditionalValidation;
@@ -992,6 +993,17 @@ public void setMldVersion(Integer mldVersion) {
public static class CreateBridgeResponse extends AgentResponse {
}
+ public static class SetVmConsolePasswordLiveCmd extends AgentCommand implements Serializable {
+ private String vmUuid;
+ @NoLogging
+ private String password;
+
+ public String getVmUuid() { return vmUuid; }
+ public void setVmUuid(String vmUuid) { this.vmUuid = vmUuid; }
+ public String getPassword() { return password; }
+ public void setPassword(String password) { this.password = password; }
+ }
+
public static class UpdateL2NetworkCmd extends AgentCommand {
private String physicalInterfaceName;
private String bridgeName;
@@ -1208,6 +1220,7 @@ public static class NicTO extends BaseVirtualDeviceTO {
// only for vf nic
private String vlanId;
private String pciDeviceAddress;
+ private List extraPciDeviceAddresses;
// only for tf nic
private String ipForTf;
private String l2NetworkUuid;
@@ -1315,6 +1328,14 @@ public void setPciDeviceAddress(String pciDeviceAddress) {
this.pciDeviceAddress = pciDeviceAddress;
}
+ public List getExtraPciDeviceAddresses() {
+ return extraPciDeviceAddresses;
+ }
+
+ public void setExtraPciDeviceAddresses(List extraPciDeviceAddresses) {
+ this.extraPciDeviceAddresses = extraPciDeviceAddresses;
+ }
+
public Integer getMtu() {
return mtu;
}
@@ -2289,6 +2310,9 @@ public static class StartVmCmd extends vdiCmd implements VmAddOnsCmd {
@GrayVersion(value = "5.0.0")
private List oemStrings = new ArrayList<>();
+ @GrayVersion(value = "5.4.0")
+ private Long HostMinimumFreeMemorySize;
+
// TODO: only for test
@GrayVersion(value = "5.0.0")
private boolean useColoBinary;
@@ -2297,6 +2321,9 @@ public static class StartVmCmd extends vdiCmd implements VmAddOnsCmd {
@GrayVersion(value = "5.0.0")
private Boolean qemu64BitPciMmioSetup;
+ @GrayVersion(value = "5.5.0")
+ private Boolean enableHygonSecurityElement;
+
public Boolean getQemu64BitPciMmioSetup() {
return qemu64BitPciMmioSetup;
}
@@ -2500,6 +2527,15 @@ public boolean isEnableSecurityElement() {
public void setEnableSecurityElement(boolean enableSecurityElement) {
this.enableSecurityElement = enableSecurityElement;
}
+
+ public Boolean isEnableHygonSecurityElement() {
+ return enableHygonSecurityElement;
+ }
+
+ public void setEnableHygonSecurityElement(Boolean enableHygonSecurityElement) {
+ this.enableHygonSecurityElement = enableHygonSecurityElement;
+ }
+
public boolean isUseNuma() {
return useNuma;
}
@@ -2856,6 +2892,14 @@ public String getVmCpuVendorId() {
public void setVmCpuVendorId(String vmCpuVendorId) {
this.vmCpuVendorId = vmCpuVendorId;
}
+
+ public Long getHostMinimumFreeMemorySize() {
+ return HostMinimumFreeMemorySize;
+ }
+
+ public void setHostMinimumFreeMemorySize(Long hostMinimumFreeMemorySize) {
+ HostMinimumFreeMemorySize = hostMinimumFreeMemorySize;
+ }
}
public static class StartVmResponse extends VmDevicesInfoResponse {
@@ -4848,14 +4892,28 @@ public static class OvsAddPortCmd extends AgentCommand {
public Boolean reInstall;
@GrayVersion(value = "5.4.0")
public Map nicMap = new HashMap<>();
+ @GrayVersion(value = "5.4.0")
+ public Map nicVmInstanceUuidMap = new HashMap<>();
}
public static class OvsAddPortRsp extends AgentResponse {
}
+ public static class OvsSyncPortCmd extends AgentCommand {
+ @GrayVersion(value = "5.4.0")
+ public String vSwitchType;
+ @GrayVersion(value = "5.4.0")
+ public Map nicMap = new HashMap<>();
+ @GrayVersion(value = "5.4.0")
+ public String vmUuid;
+ }
+
+ public static class OvsSyncPortRsp extends AgentResponse {
+ }
+
public static class OvsDelPortCmd extends AgentCommand {
@GrayVersion(value = "5.4.0")
- public String vswitchType;
+ public String vSwitchType;
@GrayVersion(value = "5.4.0")
public Map nicMap = new HashMap<>();
}
@@ -4863,6 +4921,55 @@ public static class OvsDelPortCmd extends AgentCommand {
public static class OvsDelPortRsp extends AgentResponse {
}
+ public static class OvsSetDbConnectionCmd extends AgentCommand {
+ @GrayVersion(value = "5.5.0")
+ public boolean refreshCache;
+ @GrayVersion(value = "5.5.0")
+ public List nodes;
+ }
+
+ public static class OvsSetDbConnectionRsp extends AgentResponse {
+ }
+
+ public static class OvsCheckPortCmd extends AgentCommand {
+ @GrayVersion(value = "5.4.0")
+ public String vSwitchType;
+ // TODO: only for test
+ @GrayVersion(value = "5.4.0")
+ public String hostUuid;
+ }
+
+ public static class OvsCheckPortRsp extends AgentResponse {
+ //vm uuid to all of its nics in the ovs bridge of the host
+ @GrayVersion(value = "5.4.0")
+ public Map> vmNicsMap = new HashMap<>();
+ //vnic name to vm uuid map
+ @GrayVersion(value = "5.4.0")
+ public Map vnicVmMap = new HashMap<>();
+ @GrayVersion(value = "5.4.0")
+ public Map> lspRequestedChassisMap = new HashMap<>();
+ }
+
+ public static class OvsSetRequestedChassisCmd extends AgentCommand {
+ @GrayVersion(value = "5.4.0")
+ public String vSwitchType;
+ @GrayVersion(value = "5.4.0")
+ public Map> lspRequestedChassisMap = new HashMap<>();
+ }
+
+ public static class OvsSetRequestedChassisRsp extends AgentResponse {}
+
+ public static class OvsSyncVmPortsCmd extends AgentCommand {
+ @GrayVersion(value = "5.4.0")
+ public String vSwitchType;
+ @GrayVersion(value = "5.4.0")
+ public Map nicVmInstanceUuidMap = new HashMap<>();
+ @GrayVersion(value = "5.4.0")
+ public Map nicNamePciAddressMap = new HashMap<>();
+ @GrayVersion(value = "5.4.0")
+ public Map nicNameDriverMap = new HashMap<>();
+ }
+
public static class HardwareMonitorCmd extends KVMAgentCommands.AgentCommand {
}
diff --git a/plugin/kvm/src/main/java/org/zstack/kvm/KVMConstant.java b/plugin/kvm/src/main/java/org/zstack/kvm/KVMConstant.java
index f40157764e..1b2df9f8f2 100755
--- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMConstant.java
+++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMConstant.java
@@ -41,7 +41,11 @@ public interface KVMConstant {
String KVM_START_OVS_SERVICE_PATH = "/network/ovn/start";
String KVM_STOP_OVS_SERVICE_PATH = "/network/ovn/stop";
String KVM_OVS_ADD_PORT_PATH = "/network/ovn/addport";
+ String KVM_OVS_SYNC_PORT_PATH = "/network/ovn/syncports";
String KVM_OVS_DEL_PORT_PATH = "/network/ovn/delport";
+ String KVM_OVS_SET_DB_CONNECTION_PATH = "/network/ovn/controller/setConnection";
+ String KVM_OVS_CHECK_LOCAL_PORT_PATH = "/network/ovn/checklocalport";
+ String KVM_OVS_SET_REQUESTED_CHASSIS_PATH = "/network/ovn/setrequestedchassis";
String KVM_ATTACH_ISO_PATH = "/vm/iso/attach";
String KVM_DETACH_ISO_PATH = "/vm/iso/detach";
String KVM_SYNC_VM_DEVICEINFO_PATH = "/sync/vm/deviceinfo";
@@ -65,6 +69,7 @@ public interface KVMConstant {
String KVM_DETACH_NIC_PATH = "/vm/detachnic";
String KVM_CHANGE_NIC_STATE_PATH = "/vm/changenicstate";
String KVM_UPDATE_NIC_PATH = "/vm/updatenic";
+ String KVM_SET_VF_NIC_MAC_PATH = "/vm/setvfnicmac";
String KVM_VM_CHECK_STATE = "/vm/checkstate";
String KVM_VM_UPDATE_PRIORITY_PATH = "/vm/priority";
String KVM_TAKE_VOLUME_SNAPSHOT_PATH = "/vm/volume/takesnapshot";
@@ -121,6 +126,7 @@ public interface KVMConstant {
String KVM_BLOCK_COMMIT_VOLUME_PATH = "/vm/volume/blockcommit";
String KVM_BLOCK_PULL_VOLUME_PATH = "/vm/volume/blockpull";
String TAKE_VM_CONSOLE_SCREENSHOT_PATH = "/vm/console/screenshot";
+ String UPDATE_VM_CONSOLE_PASSWORD_PATH = "/host/vm/updateConsolePassword/live";
String KVM_HOST_IPSET_ATTACH_NIC_PATH = "/network/ipset/attach";
String KVM_HOST_IPSET_DETACH_NIC_PATH = "/network/ipset/detach";
diff --git a/plugin/kvm/src/main/java/org/zstack/kvm/KVMGlobalConfig.java b/plugin/kvm/src/main/java/org/zstack/kvm/KVMGlobalConfig.java
index aa0fd787be..f4691e6fb0 100755
--- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMGlobalConfig.java
+++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMGlobalConfig.java
@@ -140,4 +140,9 @@ public class KVMGlobalConfig {
@GlobalConfigValidation
public static GlobalConfig KVMAGENT_PHYSICAL_MEMORY_USAGE_HARD_LIMIT = new GlobalConfig(CATEGORY, "kvmagent.physicalmemory.usage.hardlimit");
+
+ @GlobalConfigDef(defaultValue = "0G", description = "minimum free memory size to start vm, size in GB")
+ @BindResourceConfig({HostVO.class, ClusterVO.class})
+ public static GlobalConfig MINIMUM_MEMORY_SIZE_BEFORE_START_VM = new GlobalConfig(CATEGORY, "min.free.memory.size");
+
}
diff --git a/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java b/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java
index ab8c29640f..c82a8ba8ae 100755
--- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java
+++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java
@@ -565,13 +565,8 @@ void runBeforeAsyncJsonPostExts(Map header) {
}
}
- if (commandStr.equals("{}")) {
- commandStr = commandStr.replaceAll("\\}$",
- String.format("\"%s\":%s}", KVMConstant.KVM_HOST_ADDONS, JSONObjectUtil.toJsonString(kvmHostAddon)));
- } else {
- commandStr = commandStr.replaceAll("\\}$",
- String.format(",\"%s\":%s}", KVMConstant.KVM_HOST_ADDONS, JSONObjectUtil.toJsonString(kvmHostAddon)));
- }
+ commandMap.put(KVMConstant.KVM_HOST_ADDONS, kvmHostAddon);
+ commandStr = JSONObjectUtil.toJsonString(commandMap);
}
}
@@ -704,6 +699,8 @@ protected void handleLocalMessage(Message msg) {
handle((TakeVmConsoleScreenshotMsg) msg);
} else if (msg instanceof RestartKvmAgentMsg) {
handle((RestartKvmAgentMsg) msg);
+ } else if (msg instanceof UpdateVmConsolePasswordOnHypervisorMsg) {
+ handle((UpdateVmConsolePasswordOnHypervisorMsg) msg);
} else {
super.handleLocalMessage(msg);
}
@@ -4369,6 +4366,27 @@ protected void startVm(final VmInstanceSpec spec, final NeedReplyMessage msg, fi
cmd.setUseNuma(rcf.getResourceConfigValue(VmGlobalConfig.NUMA, spec.getVmInventory().getUuid(), Boolean.class));
setStartVmCpuTopology(spec, cmd, platform);
+ String value = KVMGlobalConfig.MINIMUM_MEMORY_SIZE_BEFORE_START_VM.value();
+ value = value.toUpperCase();
+ if (value.endsWith("GB")) {
+ value = value.substring(0, value.length() - 2);
+ } else if (value.endsWith("G")) {
+ value = value.substring(0, value.length() - 1);
+ }
+
+ Long minMemSize = 0L;
+ try {
+ minMemSize = Long.parseLong(value);
+ // Convert GB to bytes (1GB = 1024 * 1024 * 1024 bytes)
+ minMemSize = minMemSize * 1024 * 1024 * 1024;
+ } catch (NumberFormatException e) {
+ logger.warn(String.format("Invalid memory size format: %s, using default",
+ KVMGlobalConfig.MINIMUM_MEMORY_SIZE_BEFORE_START_VM.value()));
+ }
+ if (minMemSize != 0L) {
+ cmd.setHostMinimumFreeMemorySize(minMemSize);
+ }
+
cmd.setImagePlatform(platform);
cmd.setImageArchitecture(architecture);
cmd.setVmName(spec.getVmInventory().getName());
@@ -4524,6 +4542,9 @@ protected void startVm(final VmInstanceSpec spec, final NeedReplyMessage msg, fi
cmd.setConsolePassword(spec.getConsolePassword());
cmd.setUsbRedirect(spec.isUsbRedirect());
cmd.setEnableSecurityElement(spec.isEnableSecurityElement());
+ if (spec.isEnableHygonSecurityElement() != null) {
+ cmd.setEnableHygonSecurityElement(spec.isEnableHygonSecurityElement());
+ }
cmd.setVDIMonitorNumber(Integer.valueOf(spec.getVDIMonitorNumber()));
cmd.setVmPortOff(rcf.getResourceConfigValue(VmGlobalConfig.VM_PORT_OFF, spec.getVmInventory().getUuid(), Boolean.class));
cmd.setConsoleMode("vnc");
@@ -6893,4 +6914,69 @@ public void fail(ErrorCode errorCode) {
}
});
}
+
+ private void handle(UpdateVmConsolePasswordOnHypervisorMsg msg) {
+ final UpdateVmConsolePasswordOnHypervisorReply reply = new UpdateVmConsolePasswordOnHypervisorReply();
+
+ thdf.singleFlightSubmit(new SingleFlightTask(msg)
+ .setSyncSignature(String.format("update-vm-%s-console-password-on-host-%s", msg.getVmInstanceUuid(), msg.getHostUuid()))
+ .run(completion -> {
+ doUpdateVmConsolePasswordOnHypervisor(
+ msg.getVmInstanceUuid(),
+ msg.getHostUuid(),
+ msg.getPassword(),
+ new ReturnValueCompletion(completion) {
+ @Override
+ public void success(UpdateVmConsolePasswordOnHypervisorReply returnValue) {
+ completion.success(returnValue);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ completion.fail(errorCode);
+ }
+ });
+ })
+ .done(result -> {
+ if (result.isSuccess()) {
+ bus.reply(msg, reply);
+ } else {
+ reply.setError(result.getErrorCode());
+ bus.reply(msg, reply);
+ }
+ })
+ );
+ }
+
+ private void doUpdateVmConsolePasswordOnHypervisor(String vmUuid, String hostUuid, String password,
+ ReturnValueCompletion completion) {
+ SetVmConsolePasswordLiveCmd cmd = new SetVmConsolePasswordLiveCmd();
+ cmd.setVmUuid(vmUuid);
+ cmd.setPassword(password);
+
+ KVMHostAsyncHttpCallMsg kmsg = new KVMHostAsyncHttpCallMsg();
+ kmsg.setCommand(cmd);
+ kmsg.setHostUuid(hostUuid);
+ kmsg.setPath(KVMConstant.UPDATE_VM_CONSOLE_PASSWORD_PATH);
+ kmsg.setNoStatusCheck(true);
+
+ bus.makeTargetServiceIdByResourceUuid(kmsg, HostConstant.SERVICE_ID, hostUuid);
+ bus.send(kmsg, new CloudBusCallBack(completion) {
+ @Override
+ public void run(MessageReply reply) {
+ if (!reply.isSuccess()) {
+ completion.fail(reply.getError());
+ return;
+ }
+
+ KVMHostAsyncHttpCallReply r = reply.castReply();
+ AgentResponse rsp = r.toResponse(AgentResponse.class);
+ if (!rsp.isSuccess()) {
+ completion.fail(operr(rsp.getError()));
+ } else {
+ completion.success(new UpdateVmConsolePasswordOnHypervisorReply());
+ }
+ }
+ });
+ }
}
diff --git a/plugin/kvm/src/main/java/org/zstack/kvm/KvmSetupSelfFencerExtensionPoint.java b/plugin/kvm/src/main/java/org/zstack/kvm/KvmSetupSelfFencerExtensionPoint.java
index 48ae2f6882..a202505f70 100755
--- a/plugin/kvm/src/main/java/org/zstack/kvm/KvmSetupSelfFencerExtensionPoint.java
+++ b/plugin/kvm/src/main/java/org/zstack/kvm/KvmSetupSelfFencerExtensionPoint.java
@@ -38,6 +38,8 @@ class KvmSetupSelfFencerParam {
private PrimaryStorageInventory primaryStorage;
private String strategy;
private List fencers;
+ // all previous self-fencer configurations on the ps will be removed after applying the new one
+ private boolean flushPrevious = true;
public String getHostUuid() {
return hostUuid;
@@ -94,6 +96,14 @@ public List getFencers() {
public void setFencers(List fencers) {
this.fencers = fencers;
}
+
+ public boolean isFlushPrevious() {
+ return flushPrevious;
+ }
+
+ public void setFlushPrevious(boolean flushPrevious) {
+ this.flushPrevious = flushPrevious;
+ }
}
String kvmSetupSelfFencerStorageType();
diff --git a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageAllocatorFactory.java b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageAllocatorFactory.java
index 9d84ec2a0f..3d3a2c7f47 100755
--- a/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageAllocatorFactory.java
+++ b/plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageAllocatorFactory.java
@@ -16,6 +16,7 @@
import org.zstack.header.allocator.HostAllocatorSpec;
import org.zstack.header.allocator.HostAllocatorStrategyExtensionPoint;
import org.zstack.header.errorcode.OperationFailureException;
+import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.host.HostInventory;
import org.zstack.header.host.HostVO;
import org.zstack.header.storage.primary.*;
@@ -345,7 +346,7 @@ public String getHostUuidByResourceUuid(String primaryStorageUuid, String resUui
}
@Override
- public String buildAllocatedInstallUrl(AllocatePrimaryStorageSpaceMsg msg, PrimaryStorageInventory psInv) {
+ public String allocateSpaceDryRun(AllocatePrimaryStorageSpaceMsg msg, PrimaryStorageInventory psInv) {
String hostUuid = getHostUuidFromAllocateMsg(msg);
if (hostUuid == null) {
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 c7b39fc161..5e4697ac8f 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
@@ -2672,6 +2672,7 @@ protected void handle(AskVolumeSnapshotCapabilityMsg msg) {
String volumeType = msg.getVolume().getType();
if (VolumeType.Data.toString().equals(volumeType) || VolumeType.Root.toString().equals(volumeType)) {
capability.setArrangementType(VolumeSnapshotArrangementType.CHAIN);
+ capability.setPlacementType(VolumeSnapshotCapability.VolumeSnapshotPlacementType.EXTERNAL);
} else if (VolumeType.Memory.toString().equals(volumeType)) {
capability.setArrangementType(VolumeSnapshotArrangementType.INDIVIDUAL);
} else {
diff --git a/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsDownloadImageToCacheJob.java b/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsDownloadImageToCacheJob.java
index 3ba33c480f..cf56ff5e5a 100755
--- a/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsDownloadImageToCacheJob.java
+++ b/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsDownloadImageToCacheJob.java
@@ -256,7 +256,7 @@ public void handle(ErrorCode errCode, Map data) {
private void useExistingCache(final ImageCacheVO cvo, final ReturnValueCompletion