From bc338a431315c00e92ff6819e579509dd8de3e22 Mon Sep 17 00:00:00 2001 From: "shixin.ruan" Date: Thu, 6 Nov 2025 14:11:27 +0800 Subject: [PATCH 01/48] [compute]: fix enum value of error Resolves: ZSTAC-79450 Change-Id: I61626e7667637a76736d7674676e6e70656d6565 --- .../src/main/java/org/zstack/compute/vm/MacOperator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compute/src/main/java/org/zstack/compute/vm/MacOperator.java b/compute/src/main/java/org/zstack/compute/vm/MacOperator.java index ea1c9bf133..5d500f451b 100644 --- a/compute/src/main/java/org/zstack/compute/vm/MacOperator.java +++ b/compute/src/main/java/org/zstack/compute/vm/MacOperator.java @@ -127,7 +127,7 @@ public boolean checkDuplicateMac(String hypervisorType, String l3Uuid, String ma public static String generateMacWithDeviceId(short deviceId) { VmMacAddressSchemaType type; try { - type = VmMacAddressSchemaType.valueOf(VmGlobalProperty.vmMacAddressSchema.toLowerCase()); + type = VmMacAddressSchemaType.valueOf(VmGlobalProperty.vmMacAddressSchema); } catch (Exception e) { type = VmMacAddressSchemaType.Random; } @@ -148,8 +148,8 @@ public static String generateMacWithDeviceIdIp(short deviceId) { } /* encode mgt ip address into mac address: for example, - * mgt ip is: 172.24.0.81, its hex string: AC 18 0 51, - * so mac address will look like: 18:00:51:xx:xx:yy + * mgt ip is: 172.24.0.81, its hex string: AC 18 00 51, + * so mac address will look like: fa:00:51:xx:xx:yy * xx:xx are random. yy is device ID */ int mgtIpL = (int)NetworkUtils.ipv4StringToLong(mgtIp); String mgtIpStr = Integer.toHexString(mgtIpL); @@ -158,7 +158,7 @@ public static String generateMacWithDeviceIdIp(short deviceId) { mgtIpStr = compensate + mgtIpStr; } - StringBuilder sb = new StringBuilder(mgtIpStr.substring(2, 4)).append(":"); + StringBuilder sb = new StringBuilder("fa").append(":"); sb.append(mgtIpStr, 4, 6).append(":"); sb.append(mgtIpStr, 6, 8).append(":"); From b0f8057d5af9967c1a3d4b53b140804d8250303c Mon Sep 17 00:00:00 2001 From: AlanJager Date: Wed, 12 Nov 2025 18:55:09 +0800 Subject: [PATCH 02/48] [sdk]: Update sdk Resolves: ZSTAC-79795 Change-Id: I6e78716665646a786277656f7379787a6e62756f --- .../java/org/zstack/sdk/GenerateModelMetadataAction.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/src/main/java/org/zstack/sdk/GenerateModelMetadataAction.java b/sdk/src/main/java/org/zstack/sdk/GenerateModelMetadataAction.java index 9d52805be3..435e738b09 100644 --- a/sdk/src/main/java/org/zstack/sdk/GenerateModelMetadataAction.java +++ b/sdk/src/main/java/org/zstack/sdk/GenerateModelMetadataAction.java @@ -12,7 +12,7 @@ public class GenerateModelMetadataAction extends AbstractAction { public static class Result { public ErrorCode error; - public org.zstack.sdk.DeployModelServiceResult value; + public org.zstack.sdk.GenerateModelMetadataResult value; public Result throwExceptionIfError() { if (error != null) { @@ -63,8 +63,8 @@ private Result makeResult(ApiResult res) { return ret; } - org.zstack.sdk.DeployModelServiceResult value = res.getResult(org.zstack.sdk.DeployModelServiceResult.class); - ret.value = value == null ? new org.zstack.sdk.DeployModelServiceResult() : value; + org.zstack.sdk.GenerateModelMetadataResult value = res.getResult(org.zstack.sdk.GenerateModelMetadataResult.class); + ret.value = value == null ? new org.zstack.sdk.GenerateModelMetadataResult() : value; return ret; } From cbf8971616f77204be9a6ad1d9f29e0c790ae30e Mon Sep 17 00:00:00 2001 From: "shixin.ruan" Date: Tue, 18 Nov 2025 19:27:12 +0800 Subject: [PATCH 03/48] [conf]: recover UsedIpVO DBImpact Resolves: ZSTAC-77608 Change-Id: I6c71707372797770667069646563746568636162 --- conf/db/upgrade/V5.4.6__schema.sql | 57 ++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 conf/db/upgrade/V5.4.6__schema.sql diff --git a/conf/db/upgrade/V5.4.6__schema.sql b/conf/db/upgrade/V5.4.6__schema.sql new file mode 100644 index 0000000000..138893de85 --- /dev/null +++ b/conf/db/upgrade/V5.4.6__schema.sql @@ -0,0 +1,57 @@ +-- Fix UsedIpVO gateway and netmask from empty strings +DROP PROCEDURE IF EXISTS fixUsedIpGatewayAndNetmask; + +DELIMITER $$ + +CREATE PROCEDURE fixUsedIpGatewayAndNetmask() +BEGIN + DECLARE done INT DEFAULT FALSE; + DECLARE v_usedIpUuid VARCHAR(32); + DECLARE v_ipRangeUuid VARCHAR(32); + DECLARE v_gateway VARCHAR(64); + DECLARE v_netmask VARCHAR(64); + + -- Cursor for UsedIpVO records with empty gateway or netmask + DECLARE cur CURSOR FOR + SELECT uuid, ipRangeUuid + FROM UsedIpVO + WHERE (gateway = '' OR netmask = '' OR gateway IS NULL OR netmask IS NULL) + AND ipRangeUuid IS NOT NULL; + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; + + OPEN cur; + + read_loop: LOOP + FETCH cur INTO v_usedIpUuid, v_ipRangeUuid; + + IF done THEN + LEAVE read_loop; + END IF; + + -- Get gateway and netmask from IpRangeVO + SELECT gateway, netmask + INTO v_gateway, v_netmask + FROM IpRangeVO + WHERE uuid = v_ipRangeUuid; + + -- Update UsedIpVO with correct gateway and netmask + IF v_gateway IS NOT NULL AND v_netmask IS NOT NULL THEN + UPDATE UsedIpVO + SET gateway = v_gateway, netmask = v_netmask + WHERE uuid = v_usedIpUuid; + END IF; + + END LOOP; + + CLOSE cur; + +END$$ + +DELIMITER ; + +-- Execute the procedure +CALL fixUsedIpGatewayAndNetmask(); + +-- Drop the procedure after use +DROP PROCEDURE IF EXISTS fixUsedIpGatewayAndNetmask; From f6a093c3f2d5f7e325a55c719a191727fc70c8f0 Mon Sep 17 00:00:00 2001 From: "shixin.ruan" Date: Wed, 19 Nov 2025 14:59:12 +0800 Subject: [PATCH 04/48] [applianceVm]: refactor applianVm cascade Resolves: ZSTAC-79667 Change-Id: I78726c6d697577776873706c6c6f6e63636a7264 --- conf/springConfigXml/vyos.xml | 1 + .../ApplianceVmCascadeExtension.java | 79 ++++++++++++++++--- .../zstack/appliancevm/ApplianceVmFacade.java | 2 + .../appliancevm/ApplianceVmFacadeImpl.java | 20 ++++- .../ApvmCascadeFilterExtensionPoint.java | 21 ++++- .../VirtualRouterManagerImpl.java | 13 ++- .../virtualrouter/vyos/VyosVmFactory.java | 39 ++++++++- 7 files changed, 153 insertions(+), 22 deletions(-) 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/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..9a415a48bf 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,7 @@ 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 String OWNER = String.format("ApplianceVm.%s", Platform.getManagementServerId()); @@ -224,6 +222,18 @@ 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())); + + } } private void deployAnsible() { @@ -627,4 +637,8 @@ public void detachVirtualRouterFromHaGroup(String vmUuid, String haGroupUuid) { ext.detachVirtualRouterFromHaGroup(vmUuid, haGroupUuid); } } + + public ApvmCascadeFilterExtensionPoint getApvmCascadeFilterExtensionPoint(ApplianceVmType type) { + return apvmCascadeFilterExtensionPointMap.get(type); + } } 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/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterManagerImpl.java b/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterManagerImpl.java index 6d47951e25..ca14cc7899 100755 --- a/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterManagerImpl.java +++ b/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterManagerImpl.java @@ -2033,7 +2033,7 @@ protected List scripts() { }.execute(); } - private List applianceVmsToBeDeleted(List applianceVmVOS, List deletedUuids) { + public List applianceVmsToBeDeleted(List applianceVmVOS, List deletedUuids) { List vos = new ArrayList<>(); for (ApplianceVmVO vo : applianceVmVOS) { VirtualRouterVmVO vo_dbf = dbf.findByUuid(vo.getUuid(), VirtualRouterVmVO.class); @@ -2057,7 +2057,7 @@ private List applianceVmsToBeDeleted(List applianc return vos; } - List applianceVmsAdditionalPublicNic(List applianceVmVOS, List parentIssuerUuids) { + public List applianceVmsAdditionalPublicNic(List applianceVmVOS, List parentIssuerUuids) { List toDeleteNics = new ArrayList<>(); for (ApplianceVmVO vo : applianceVmVOS) { VirtualRouterVmVO vr_dbf = dbf.findByUuid(vo.getUuid(), VirtualRouterVmVO.class); @@ -2132,7 +2132,7 @@ public void done(ErrorCodeList errorCodeList) { }); } - List applianceVmsToDeleteNicByIpRanges(List applianceVmVOS, List iprUuids) { + public List applianceVmsToDeleteNicByIpRanges(List applianceVmVOS, List iprUuids) { List toDeleteNics = new ArrayList<>(); for (ApplianceVmVO vo : applianceVmVOS) { for (VmNicVO nic : vo.getVmNics()) { @@ -2159,7 +2159,7 @@ List applianceVmsToDeleteNicByIpRanges(List applianceVmV return toDeleteNics; } - private List applianceVmsToBeDeletedByIpRanges(List applianceVmVOS, List iprUuids) { + public List applianceVmsToBeDeletedByIpRanges(List applianceVmVOS, List iprUuids) { List toDeleted = new ArrayList<>(); List l3Uuids = Q.New(IpRangeVO.class).in(IpRangeVO_.uuid, iprUuids).select(IpRangeVO_.l3NetworkUuid).listValues(); for (ApplianceVmVO vos : applianceVmVOS) { @@ -2215,6 +2215,11 @@ public List filterApplianceVmCascade(List applianc } } + @Override + public ApplianceVmType getApplianceVmType() { + return ApplianceVmType.valueOf(VirtualRouterConstant.VIRTUAL_ROUTER_VM_TYPE); + } + private void reconenctVirtualRouter(String vrUUid, boolean statusChange) { ReconnectVirtualRouterVmMsg msg = new ReconnectVirtualRouterVmMsg(); msg.setVirtualRouterVmUuid(vrUUid); diff --git a/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/vyos/VyosVmFactory.java b/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/vyos/VyosVmFactory.java index 17d62cc88b..69aa5b0155 100644 --- a/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/vyos/VyosVmFactory.java +++ b/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/vyos/VyosVmFactory.java @@ -2,13 +2,21 @@ import org.springframework.beans.factory.annotation.Autowired; import org.zstack.appliancevm.ApplianceVmType; +import org.zstack.appliancevm.ApplianceVmVO; +import org.zstack.appliancevm.ApvmCascadeFilterExtensionPoint; +import org.zstack.core.cascade.CascadeAction; import org.zstack.core.db.DatabaseFacade; +import org.zstack.header.network.l3.IpRangeVO; +import org.zstack.header.network.l3.L3NetworkVO; +import org.zstack.header.network.l3.UsedIpInventory; import org.zstack.header.network.service.NetworkServiceType; +import org.zstack.header.vm.VmNicInventory; import org.zstack.network.service.lb.LoadBalancerConstants; import org.zstack.network.service.vip.VipGetUsedPortRangeExtensionPoint; import org.zstack.network.service.vip.VipVO; import org.zstack.network.service.virtualrouter.VirtualRouterGlobalConfig; import org.zstack.network.service.virtualrouter.VirtualRouterGlobalProperty; +import org.zstack.network.service.virtualrouter.VirtualRouterManagerImpl; import org.zstack.utils.RangeSet; import org.zstack.utils.Utils; import org.zstack.utils.VipUseForList; @@ -20,12 +28,14 @@ /** * Created by weiwang on 19/09/2017 */ -public class VyosVmFactory extends VyosVmBaseFactory implements VipGetUsedPortRangeExtensionPoint { +public class VyosVmFactory extends VyosVmBaseFactory implements VipGetUsedPortRangeExtensionPoint, ApvmCascadeFilterExtensionPoint { private static final CLogger logger = Utils.getLogger(VyosVmFactory.class); public static ApplianceVmType applianceVmType = new ApplianceVmType(VyosConstants.VYOS_VM_TYPE); @Autowired private DatabaseFacade dbf; + @Autowired + private VirtualRouterManagerImpl vrMgr; @Override public ApplianceVmType getApplianceVmType() { @@ -60,4 +70,31 @@ public RangeSet getVipUsePortRange(String vipUuid, String protocol, VipUseForLis return portRangeList; } + + @Override + public List filterApplianceVmCascade(List applianceVmVOS, CascadeAction action, + String parentIssuer, + List parentIssuerUuids, + List toDeleteNics, + List toDeleteIps) { + logger.debug(String.format("filter appliance vm type %s with parentIssuer [type: %s, uuids: %s]", + VyosConstants.VYOS_VM_TYPE, parentIssuer, parentIssuerUuids)); + + if (parentIssuer.equals(L3NetworkVO.class.getSimpleName())) { + List vos = vrMgr.applianceVmsToBeDeleted(applianceVmVOS, parentIssuerUuids); + + applianceVmVOS.removeAll(vos); + toDeleteNics.addAll(vrMgr.applianceVmsAdditionalPublicNic(applianceVmVOS, parentIssuerUuids)); + + return vos; + } else if (parentIssuer.equals(IpRangeVO.class.getSimpleName())) { + List vos = vrMgr.applianceVmsToBeDeletedByIpRanges(applianceVmVOS, parentIssuerUuids); + applianceVmVOS.removeAll(vos); + toDeleteNics.addAll(VmNicInventory.valueOf(vrMgr.applianceVmsToDeleteNicByIpRanges(applianceVmVOS, parentIssuerUuids))); + + return vos; + } else { + return applianceVmVOS; + } + } } From b2f4bffc2cc98043f9ab3c8968a9820f6255c04e Mon Sep 17 00:00:00 2001 From: lianghy Date: Thu, 20 Nov 2025 17:48:31 +0800 Subject: [PATCH 05/48] [conf]: bump version to 5.4.6 DBImpact Resolves: ZSTAC-80020 Change-Id: I68666f6f7074636c6d7478796e73676d6c727863 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b8ac796c95..8577c9efcf 100755 --- a/VERSION +++ b/VERSION @@ -1,3 +1,3 @@ MAJOR=5 MINOR=4 -UPDATE=2 +UPDATE=6 From 7f38521d77c5a033c798bf6e4707fa32fe86ed3e Mon Sep 17 00:00:00 2001 From: AlanJager Date: Fri, 21 Nov 2025 17:21:39 +0800 Subject: [PATCH 06/48] [sdk]: Update sdk Resolves: ZSTAC-74156 Change-Id: I78646174636d676d627467786c7266756f746270 --- .../main/java/org/zstack/sdk/MdevDeviceSpecInventory.java | 8 ++++++++ .../main/java/org/zstack/sdk/PciDeviceSpecInventory.java | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/sdk/src/main/java/org/zstack/sdk/MdevDeviceSpecInventory.java b/sdk/src/main/java/org/zstack/sdk/MdevDeviceSpecInventory.java index 0360c59dbd..c3b2fc5b0e 100644 --- a/sdk/src/main/java/org/zstack/sdk/MdevDeviceSpecInventory.java +++ b/sdk/src/main/java/org/zstack/sdk/MdevDeviceSpecInventory.java @@ -77,4 +77,12 @@ public java.sql.Timestamp getLastOpDate() { return this.lastOpDate; } + public java.lang.Integer maxAvailableDevicesPerHost; + public void setMaxAvailableDevicesPerHost(java.lang.Integer maxAvailableDevicesPerHost) { + this.maxAvailableDevicesPerHost = maxAvailableDevicesPerHost; + } + public java.lang.Integer getMaxAvailableDevicesPerHost() { + return this.maxAvailableDevicesPerHost; + } + } diff --git a/sdk/src/main/java/org/zstack/sdk/PciDeviceSpecInventory.java b/sdk/src/main/java/org/zstack/sdk/PciDeviceSpecInventory.java index 99b34405fe..6bead4ce0d 100644 --- a/sdk/src/main/java/org/zstack/sdk/PciDeviceSpecInventory.java +++ b/sdk/src/main/java/org/zstack/sdk/PciDeviceSpecInventory.java @@ -157,4 +157,12 @@ public java.sql.Timestamp getLastOpDate() { return this.lastOpDate; } + public java.lang.Integer maxAvailableDevicesPerHost; + public void setMaxAvailableDevicesPerHost(java.lang.Integer maxAvailableDevicesPerHost) { + this.maxAvailableDevicesPerHost = maxAvailableDevicesPerHost; + } + public java.lang.Integer getMaxAvailableDevicesPerHost() { + return this.maxAvailableDevicesPerHost; + } + } From ed4dca59b0dfd1da18afc72be9fd6593b1de3e15 Mon Sep 17 00:00:00 2001 From: "xinhao.huang" Date: Fri, 21 Nov 2025 17:29:42 +0800 Subject: [PATCH 07/48] [conf]: update model service's framework in sql schema DBImpact Resolves: ZSTAC-79819 Change-Id: I656a74706867656168667775716869766e736d64 --- conf/db/upgrade/V5.4.6__schema.sql | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/conf/db/upgrade/V5.4.6__schema.sql b/conf/db/upgrade/V5.4.6__schema.sql index 138893de85..01d1d006e9 100644 --- a/conf/db/upgrade/V5.4.6__schema.sql +++ b/conf/db/upgrade/V5.4.6__schema.sql @@ -55,3 +55,41 @@ CALL fixUsedIpGatewayAndNetmask(); -- Drop the procedure after use DROP PROCEDURE IF EXISTS fixUsedIpGatewayAndNetmask; + + +-- Update ModelServiceVO framework values +DROP PROCEDURE IF EXISTS updateModelServiceFramework; + +DELIMITER $$ + +CREATE PROCEDURE updateModelServiceFramework() +BEGIN + DECLARE v_table_exists INT DEFAULT 0; + + -- Check if ModelServiceVO table and framework column exist + SELECT COUNT(*) INTO v_table_exists + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'ModelServiceVO' + AND COLUMN_NAME = 'framework'; + + IF v_table_exists > 0 THEN + -- Update llama.cpp to LlamaCpp + UPDATE ModelServiceVO + SET framework = 'LlamaCpp' + WHERE framework = 'llama.cpp'; + + -- Update sentence_transformers to SentenceTransformers + UPDATE ModelServiceVO + SET framework = 'SentenceTransformers' + WHERE framework = 'sentence_transformers'; + END IF; +END$$ + +DELIMITER ; + +-- Execute the procedure +CALL updateModelServiceFramework(); + +-- Drop the procedure after use +DROP PROCEDURE IF EXISTS updateModelServiceFramework; From e8785c0af31aec2b164b9525fec7c28cf1c66d0f Mon Sep 17 00:00:00 2001 From: AlanJager Date: Tue, 25 Nov 2025 10:43:19 +0800 Subject: [PATCH 08/48] [conf]: Upgrade xtts and sdxl-turbo's architecture type DBImpact Resolves: ZSTAC-79822 Change-Id: I757a69696276717870766863617778737165746a --- conf/db/upgrade/V5.4.6__schema.sql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conf/db/upgrade/V5.4.6__schema.sql b/conf/db/upgrade/V5.4.6__schema.sql index 01d1d006e9..d5d23d63c2 100644 --- a/conf/db/upgrade/V5.4.6__schema.sql +++ b/conf/db/upgrade/V5.4.6__schema.sql @@ -93,3 +93,6 @@ CALL updateModelServiceFramework(); -- Drop the procedure after use DROP PROCEDURE IF EXISTS updateModelServiceFramework; + +UPDATE ModelVO SET architectureType = 'xtts-v2' WHERE uuid = '39280569b4e0490fb581f6ab98e76400'; +UPDATE ModelVO SET architectureType = 'sdxl-turbo' WHERE uuid = '6a720c01935f4f9ea09f81bde722ee42'; From c682625ece536b3f624920e561081a31c3ac2e8d Mon Sep 17 00:00:00 2001 From: AlanJager Date: Tue, 25 Nov 2025 16:21:41 +0800 Subject: [PATCH 09/48] [sdk]: Update sdk Resolves: ZSTAC-78793 Change-Id: I66636873787076786973697a72766c6c75746873 --- .../org/zstack/sdk/AddModelServiceAction.java | 6 ++++++ .../org/zstack/sdk/CloneModelServiceAction.java | 6 ++++++ .../org/zstack/sdk/ModelServiceInventory.java | 16 ++++++++++++++++ .../org/zstack/sdk/UpdateModelServiceAction.java | 6 ++++++ 4 files changed, 34 insertions(+) diff --git a/sdk/src/main/java/org/zstack/sdk/AddModelServiceAction.java b/sdk/src/main/java/org/zstack/sdk/AddModelServiceAction.java index 01d2193ea6..3062782ee5 100644 --- a/sdk/src/main/java/org/zstack/sdk/AddModelServiceAction.java +++ b/sdk/src/main/java/org/zstack/sdk/AddModelServiceAction.java @@ -55,6 +55,12 @@ public Result throwExceptionIfError() { @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String startCommand; + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String containerCommand; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String containerArgs; + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String pythonVersion; diff --git a/sdk/src/main/java/org/zstack/sdk/CloneModelServiceAction.java b/sdk/src/main/java/org/zstack/sdk/CloneModelServiceAction.java index 37bad5494f..d8a876b518 100644 --- a/sdk/src/main/java/org/zstack/sdk/CloneModelServiceAction.java +++ b/sdk/src/main/java/org/zstack/sdk/CloneModelServiceAction.java @@ -49,6 +49,12 @@ public Result throwExceptionIfError() { @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String startCommand; + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String containerCommand; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String containerArgs; + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String pythonVersion; diff --git a/sdk/src/main/java/org/zstack/sdk/ModelServiceInventory.java b/sdk/src/main/java/org/zstack/sdk/ModelServiceInventory.java index a588313c06..3b0d649572 100644 --- a/sdk/src/main/java/org/zstack/sdk/ModelServiceInventory.java +++ b/sdk/src/main/java/org/zstack/sdk/ModelServiceInventory.java @@ -148,6 +148,22 @@ public java.lang.String getStartCommand() { return this.startCommand; } + public java.lang.String containerCommand; + public void setContainerCommand(java.lang.String containerCommand) { + this.containerCommand = containerCommand; + } + public java.lang.String getContainerCommand() { + return this.containerCommand; + } + + public java.lang.String containerArgs; + public void setContainerArgs(java.lang.String containerArgs) { + this.containerArgs = containerArgs; + } + public java.lang.String getContainerArgs() { + return this.containerArgs; + } + public boolean supportDistributed; public void setSupportDistributed(boolean supportDistributed) { this.supportDistributed = supportDistributed; diff --git a/sdk/src/main/java/org/zstack/sdk/UpdateModelServiceAction.java b/sdk/src/main/java/org/zstack/sdk/UpdateModelServiceAction.java index cc8d685257..131e4e3b9f 100644 --- a/sdk/src/main/java/org/zstack/sdk/UpdateModelServiceAction.java +++ b/sdk/src/main/java/org/zstack/sdk/UpdateModelServiceAction.java @@ -49,6 +49,12 @@ public Result throwExceptionIfError() { @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String startCommand; + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String containerCommand; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String containerArgs; + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String pythonVersion; From a9e47e9c1d4f3da2db5fbb1f0723b4f8743c18f8 Mon Sep 17 00:00:00 2001 From: AlanJager Date: Tue, 25 Nov 2025 17:36:53 +0800 Subject: [PATCH 10/48] [conf]: Fix update schema DBImpact Resolves: ZSTAC-78793 Change-Id: I65786775617a6b746276756f636c79616b7a7475 --- conf/db/upgrade/V5.4.6__schema.sql | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/conf/db/upgrade/V5.4.6__schema.sql b/conf/db/upgrade/V5.4.6__schema.sql index d5d23d63c2..2343c34c7c 100644 --- a/conf/db/upgrade/V5.4.6__schema.sql +++ b/conf/db/upgrade/V5.4.6__schema.sql @@ -96,3 +96,7 @@ DROP PROCEDURE IF EXISTS updateModelServiceFramework; UPDATE ModelVO SET architectureType = 'xtts-v2' WHERE uuid = '39280569b4e0490fb581f6ab98e76400'; UPDATE ModelVO SET architectureType = 'sdxl-turbo' WHERE uuid = '6a720c01935f4f9ea09f81bde722ee42'; + +CALL ADD_COLUMN('ModelServiceVO', 'containerArgs', 'TEXT', 1, NULL); +CALL ADD_COLUMN('ModelServiceVO', 'containerCommand', 'TEXT', 1, NULL); + From f3cf7294da6c57677095dfb6f9d4aaeed9035e1d Mon Sep 17 00:00:00 2001 From: "yaohua.wu" Date: Tue, 25 Nov 2025 17:53:30 +0800 Subject: [PATCH 11/48] [zbs]: reload if addon info null Resolves: ZSTAC-80049 Change-Id: I726a616d6569716c78756f7562666f6d6767657a --- .../main/java/org/zstack/storage/zbs/ZbsStorageController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java index dd1861e58f..3d7a0b6745 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java @@ -553,7 +553,7 @@ public StorageCapabilities reportCapabilities() { @Override public String allocateSpace(AllocateSpaceSpec aspec) { - if (config == null) { + if (config == null || addonInfo == null) { reloadDbInfo(); } From 48ecbf2bd2588d6d02d34adcb44212f8596ea5a4 Mon Sep 17 00:00:00 2001 From: "yaohua.wu" Date: Tue, 25 Nov 2025 21:33:02 +0800 Subject: [PATCH 12/48] [testlib]: update libcbd on deploying client Resolves: ZSTAC-79057 Change-Id: I6471766d6d786871777977736e7073726e64776a --- .../kvm/ExternalPrimaryStorageKvmFactory.java | 7 +- .../storage/zbs/ZbsStorageController.java | 119 ++++++++++++++---- .../testlib/ExternalPrimaryStorageSpec.groovy | 7 ++ 3 files changed, 110 insertions(+), 23 deletions(-) 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/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java index 3d7a0b6745..01d67f7dee 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java @@ -9,10 +9,12 @@ import org.zstack.cbd.kvm.CbdVolumeTo; import org.zstack.compute.host.HostGlobalConfig; import org.zstack.core.CoreGlobalProperty; +import org.zstack.core.ansible.AnsibleGlobalProperty; import org.zstack.core.asyncbatch.While; import org.zstack.core.cloudbus.CloudBus; import org.zstack.core.cloudbus.CloudBusCallBack; import org.zstack.core.db.DatabaseFacade; +import org.zstack.core.db.Q; import org.zstack.core.db.SQL; import org.zstack.core.workflow.FlowChainBuilder; import org.zstack.core.workflow.ShareFlow; @@ -99,6 +101,7 @@ public class ZbsStorageController implements PrimaryStorageControllerSvc, Primar public static final String ROLLBACK_SNAPSHOT_PATH = "/zbs/primarystorage/snapshot/rollback"; public static final String CHECK_HOST_STORAGE_CONNECTION_PATH = "/zbs/primarystorage/check/host/connection"; public static final String GET_VOLUME_CLIENTS_PATH = "/zbs/primarystorage/volume/clients"; + public static final String UPDATE_HOST_DEPENDENCY_PATH = "/zbs/primarystorage/host/updatedependency"; private static final StorageCapabilities capabilities = new StorageCapabilities(); @@ -187,28 +190,92 @@ public List getActiveVolumesLocation(HostInventory h) { @Override public void deployClient(HostInventory h, Completion comp) { - KVMHostVO host = org.zstack.core.db.Q.New(KVMHostVO.class).eq(KVMHostVO_.uuid, h.getUuid()).find(); - if (host == null) { - comp.fail(operr("cannot found kvm host[uuid:%s], unable to deploy client", h.getUuid())); - return; - } - - DeployClientCmd cmd = new DeployClientCmd(); - cmd.setIp(h.getManagementIp()); - cmd.setPort(host.getPort()); - cmd.setUsername(host.getUsername()); - cmd.setPassword(host.getPassword()); - httpCall(DEPLOY_CLIENT_PATH, cmd, DeployClientRsp.class, new ReturnValueCompletion(comp) { + FlowChain chain = FlowChainBuilder.newShareFlowChain(); + chain.setName(String.format("deploy-zbs-client-on-host-%s", h.getUuid())); + chain.then(new ShareFlow() { @Override - public void success(DeployClientRsp returnValue) { - comp.success(); - } + public void setup() { + flow(new NoRollbackFlow() { + String __name__ = "deploy-client"; - @Override - public void fail(ErrorCode errorCode) { - comp.fail(errorCode); + @Override + public void run(FlowTrigger trigger, Map data) { + KVMHostVO host = Q.New(KVMHostVO.class).eq(KVMHostVO_.uuid, h.getUuid()).find(); + if (host == null) { + trigger.fail(operr("cannot found kvm host[uuid:%s], unable to deploy client", h.getUuid())); + return; + } + + DeployClientCmd cmd = new DeployClientCmd(); + cmd.setIp(h.getManagementIp()); + cmd.setPort(host.getPort()); + cmd.setUsername(host.getUsername()); + cmd.setPassword(host.getPassword()); + httpCall(DEPLOY_CLIENT_PATH, cmd, DeployClientRsp.class, new ReturnValueCompletion(trigger) { + @Override + public void success(DeployClientRsp returnValue) { + trigger.next(); + } + + @Override + public void fail(ErrorCode errorCode) { + trigger.fail(errorCode); + } + }); + } + }); + + flow(new NoRollbackFlow() { + String __name__ = "update-host-client-dependency"; + + @Override + public void run(FlowTrigger trigger, Map data) { + UpdateHostDependencyCmd cmd = new UpdateHostDependencyCmd(); + cmd.updatePackages = "libcbd"; + cmd.zstackRepo = AnsibleGlobalProperty.ZSTACK_REPO; + + KVMHostAsyncHttpCallMsg msg = new KVMHostAsyncHttpCallMsg(); + msg.setCommand(cmd); + msg.setHostUuid(h.getUuid()); + msg.setPath(UPDATE_HOST_DEPENDENCY_PATH); + msg.setNoStatusCheck(true); + bus.makeTargetServiceIdByResourceUuid(msg, HostConstant.SERVICE_ID, msg.getHostUuid()); + bus.send(msg, new CloudBusCallBack(trigger) { + @Override + public void run(MessageReply reply) { + if (!reply.isSuccess()) { + trigger.fail(reply.getError()); + return; + } + + KVMHostAsyncHttpCallReply hreply = reply.castReply(); + UpdateHostDependencyRsp rsp = hreply.toResponse(UpdateHostDependencyRsp.class); + if (!rsp.isSuccess()) { + trigger.fail(operr(rsp.getError())); + return; + } + + trigger.next(); + } + }); + } + }); + + done(new FlowDoneHandler(comp) { + @Override + public void handle(Map data) { + comp.success(); + } + }); + + error(new FlowErrorHandler(comp) { + @Override + public void handle(ErrorCode errCode, Map data) { + comp.fail(errCode); + } + }); } - }); + }).start(); } @Override @@ -357,7 +424,7 @@ public void fail(ErrorCode errorCode) { flow(new NoRollbackFlow() { String __name__ = "deploy-client"; - List refs = org.zstack.core.db.Q.New(PrimaryStorageClusterRefVO.class) + List refs = Q.New(PrimaryStorageClusterRefVO.class) .eq(PrimaryStorageClusterRefVO_.primaryStorageUuid, self.getUuid()) .list(); @@ -372,12 +439,12 @@ public void run(FlowTrigger trigger, Map data) { .map(PrimaryStorageClusterRefVO::getClusterUuid) .collect(Collectors.toList()); - List hosts = org.zstack.core.db.Q.New(HostVO.class) + List hosts = Q.New(HostVO.class) .in(HostAO_.clusterUuid, clusterUuids) .list(); new While<>(hosts).each((h, comp) -> { - KVMHostVO host = org.zstack.core.db.Q.New(KVMHostVO.class).eq(KVMHostVO_.uuid, h.getUuid()).find(); + KVMHostVO host = Q.New(KVMHostVO.class).eq(KVMHostVO_.uuid, h.getUuid()).find(); if (host == null) { comp.addError(operr("cannot found kvm host[uuid:%s], unable to deploy client", h.getUuid())); comp.allDone(); @@ -1897,6 +1964,14 @@ public void setPath(String path) { public static class CheckHostStorageConnectionRsp extends AgentResponse { } + public static class UpdateHostDependencyCmd extends AgentCommand { + public String updatePackages; + public String zstackRepo; + } + + public static class UpdateHostDependencyRsp extends AgentResponse { + } + public static class AgentResponse extends ZbsMdsBase.AgentResponse { } diff --git a/testlib/src/main/java/org/zstack/testlib/ExternalPrimaryStorageSpec.groovy b/testlib/src/main/java/org/zstack/testlib/ExternalPrimaryStorageSpec.groovy index 356a9641f1..19dedb00cc 100644 --- a/testlib/src/main/java/org/zstack/testlib/ExternalPrimaryStorageSpec.groovy +++ b/testlib/src/main/java/org/zstack/testlib/ExternalPrimaryStorageSpec.groovy @@ -71,6 +71,13 @@ class ExternalPrimaryStorageSpec extends PrimaryStorageSpec { return rsp } + simulator(ZbsStorageController.UPDATE_HOST_DEPENDENCY_PATH) { HttpEntity e, EnvSpec spec -> + def rsp = new ZbsStorageController.UpdateHostDependencyRsp() + rsp.success = true + + return rsp + } + simulator(ZbsStorageController.GET_FACTS_PATH) { HttpEntity e, EnvSpec spec -> ZbsStorageController.GetFactsCmd cmd = JSONObjectUtil.toObject(e.body, ZbsStorageController.GetFactsCmd.class) ExternalPrimaryStorageSpec zspec = spec.specByUuid(cmd.uuid) From 48ec0ecb5da210b99bf6ab4c8bc5a761a2975e60 Mon Sep 17 00:00:00 2001 From: AlanJager Date: Tue, 25 Nov 2025 18:13:16 +0800 Subject: [PATCH 13/48] [sdk]: Update sdk Resolves: ZSTAC-80119 Change-Id: I6966616b68627679756b6a6e79686f6972716b67 --- .../sdk/UpdateModelServiceInstanceGroupAction.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sdk/src/main/java/org/zstack/sdk/UpdateModelServiceInstanceGroupAction.java b/sdk/src/main/java/org/zstack/sdk/UpdateModelServiceInstanceGroupAction.java index 0862c561bf..18e3b18309 100644 --- a/sdk/src/main/java/org/zstack/sdk/UpdateModelServiceInstanceGroupAction.java +++ b/sdk/src/main/java/org/zstack/sdk/UpdateModelServiceInstanceGroupAction.java @@ -40,6 +40,15 @@ public Result throwExceptionIfError() { @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.util.Map startupParameters; + @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String serviceLivez; + + @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String serviceReadyz; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.Integer serviceBootupTime; + @Param(required = false) public java.util.List systemTags; From ae91ababe7af489c6b713e9ee4b341783cca3385 Mon Sep 17 00:00:00 2001 From: AlanJager Date: Sat, 29 Nov 2025 13:22:47 +0800 Subject: [PATCH 14/48] [sdk]: Update sdk Resolves: ZSTAC-80119 Change-Id: I73726b787377706261676f6874726f6e61696f62 --- .../sdk/DeployAppDevelopmentServiceAction.java | 6 ++++++ .../zstack/sdk/DeployModelEvalServiceAction.java | 6 ++++++ .../org/zstack/sdk/DeployModelServiceAction.java | 6 ++++++ ...MatchModelServiceTemplateWithModelAction.java | 6 ++++++ .../main/java/org/zstack/sdk/ModelService.java | 16 ++++++++++++++++ 5 files changed, 40 insertions(+) diff --git a/sdk/src/main/java/org/zstack/sdk/DeployAppDevelopmentServiceAction.java b/sdk/src/main/java/org/zstack/sdk/DeployAppDevelopmentServiceAction.java index 536310c17d..2ab7e2b846 100644 --- a/sdk/src/main/java/org/zstack/sdk/DeployAppDevelopmentServiceAction.java +++ b/sdk/src/main/java/org/zstack/sdk/DeployAppDevelopmentServiceAction.java @@ -79,6 +79,12 @@ public Result throwExceptionIfError() { @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.Integer serviceBootUptime; + @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String serviceLivez; + + @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String serviceReadyz; + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String rootDiskOfferingUuid; diff --git a/sdk/src/main/java/org/zstack/sdk/DeployModelEvalServiceAction.java b/sdk/src/main/java/org/zstack/sdk/DeployModelEvalServiceAction.java index dd3c2933a1..bf4c6abc18 100644 --- a/sdk/src/main/java/org/zstack/sdk/DeployModelEvalServiceAction.java +++ b/sdk/src/main/java/org/zstack/sdk/DeployModelEvalServiceAction.java @@ -130,6 +130,12 @@ public Result throwExceptionIfError() { @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.Integer serviceBootUptime; + @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String serviceLivez; + + @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String serviceReadyz; + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String rootDiskOfferingUuid; diff --git a/sdk/src/main/java/org/zstack/sdk/DeployModelServiceAction.java b/sdk/src/main/java/org/zstack/sdk/DeployModelServiceAction.java index 9c73bee8da..61ee415881 100644 --- a/sdk/src/main/java/org/zstack/sdk/DeployModelServiceAction.java +++ b/sdk/src/main/java/org/zstack/sdk/DeployModelServiceAction.java @@ -79,6 +79,12 @@ public Result throwExceptionIfError() { @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.Integer serviceBootUptime; + @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String serviceLivez; + + @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String serviceReadyz; + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String rootDiskOfferingUuid; diff --git a/sdk/src/main/java/org/zstack/sdk/MatchModelServiceTemplateWithModelAction.java b/sdk/src/main/java/org/zstack/sdk/MatchModelServiceTemplateWithModelAction.java index 7d6d97cb2c..be243bba4d 100644 --- a/sdk/src/main/java/org/zstack/sdk/MatchModelServiceTemplateWithModelAction.java +++ b/sdk/src/main/java/org/zstack/sdk/MatchModelServiceTemplateWithModelAction.java @@ -88,6 +88,12 @@ public Result throwExceptionIfError() { @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.Integer serviceBootUptime; + @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String serviceLivez; + + @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String serviceReadyz; + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String rootDiskOfferingUuid; diff --git a/sdk/src/main/java/org/zstack/sdk/ModelService.java b/sdk/src/main/java/org/zstack/sdk/ModelService.java index 60c82ea684..cc765e6749 100644 --- a/sdk/src/main/java/org/zstack/sdk/ModelService.java +++ b/sdk/src/main/java/org/zstack/sdk/ModelService.java @@ -172,6 +172,22 @@ public java.lang.Integer getServiceBootUptime() { return this.serviceBootUptime; } + public java.lang.String serviceLivez; + public void setServiceLivez(java.lang.String serviceLivez) { + this.serviceLivez = serviceLivez; + } + public java.lang.String getServiceLivez() { + return this.serviceLivez; + } + + public java.lang.String serviceReadyz; + public void setServiceReadyz(java.lang.String serviceReadyz) { + this.serviceReadyz = serviceReadyz; + } + public java.lang.String getServiceReadyz() { + return this.serviceReadyz; + } + public java.lang.String rootDiskOfferingUuid; public void setRootDiskOfferingUuid(java.lang.String rootDiskOfferingUuid) { this.rootDiskOfferingUuid = rootDiskOfferingUuid; From c25cfa17c8c6d200345ef90b6f591530982e9bfb Mon Sep 17 00:00:00 2001 From: "haoyu.ding" Date: Mon, 1 Dec 2025 21:39:03 +0800 Subject: [PATCH 15/48] [ceph]: change default password Resolves: ZSTAC-79936 Change-Id: I65657166766872677463796e796d6f6f78746964 --- conf/globalConfig/ceph.xml | 2 +- .../test/integration/storage/ceph/CephOperationCase.groovy | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/test/src/test/groovy/org/zstack/test/integration/storage/ceph/CephOperationCase.groovy b/test/src/test/groovy/org/zstack/test/integration/storage/ceph/CephOperationCase.groovy index eb6ddc8296..b131d74024 100644 --- a/test/src/test/groovy/org/zstack/test/integration/storage/ceph/CephOperationCase.groovy +++ b/test/src/test/groovy/org/zstack/test/integration/storage/ceph/CephOperationCase.groovy @@ -263,7 +263,7 @@ class CephOperationCase extends SubCase { .select(GlobalConfigVO_.value) .eq(GlobalConfigVO_.name, "sds.admin.password") .eq(GlobalConfigVO_.category, "ceph") - .findValue() == "password" + .findValue() == "Admin@123" updateGlobalConfig { category = CephGlobalConfig.CATEGORY From cce827da4c006530f6741afe9c71395026fd213f Mon Sep 17 00:00:00 2001 From: AlanJager Date: Tue, 2 Dec 2025 13:52:27 +0800 Subject: [PATCH 16/48] [conf]: Add isolated field to gpu and gpu spec DBImpact Resolves: ZSTAC-79981 Change-Id: I706a65776377706f73766f62786e667472677a6c --- conf/db/upgrade/V5.4.6__schema.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/db/upgrade/V5.4.6__schema.sql b/conf/db/upgrade/V5.4.6__schema.sql index 2343c34c7c..1905c878f6 100644 --- a/conf/db/upgrade/V5.4.6__schema.sql +++ b/conf/db/upgrade/V5.4.6__schema.sql @@ -100,3 +100,5 @@ UPDATE ModelVO SET architectureType = 'sdxl-turbo' WHERE uuid = '6a720c01935f4f9 CALL ADD_COLUMN('ModelServiceVO', 'containerArgs', 'TEXT', 1, NULL); CALL ADD_COLUMN('ModelServiceVO', 'containerCommand', 'TEXT', 1, NULL); +CALL ADD_COLUMN('GpuDeviceVO', 'isolated', 'TINYINT(1)', 1, NULL); +CALL ADD_COLUMN('GpuDeviceSpecVO', 'isolated', 'TINYINT(1)', 1, NULL); From 7f5c5cfa43589de62cb346635636f756dcb372f5 Mon Sep 17 00:00:00 2001 From: AlanJager Date: Tue, 2 Dec 2025 16:49:32 +0800 Subject: [PATCH 17/48] [sdk]: Update sdk Resolves: ZSTAC-79981 Change-Id: I766568646477627a766c6570617871786a776675 --- .../org/zstack/sdk/GpuDeviceSpecInventory.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sdk/src/main/java/org/zstack/sdk/GpuDeviceSpecInventory.java b/sdk/src/main/java/org/zstack/sdk/GpuDeviceSpecInventory.java index 24d0532f3c..e043f206e5 100644 --- a/sdk/src/main/java/org/zstack/sdk/GpuDeviceSpecInventory.java +++ b/sdk/src/main/java/org/zstack/sdk/GpuDeviceSpecInventory.java @@ -12,4 +12,20 @@ public java.lang.Long getMemory() { return this.memory; } + public java.lang.String gpuType; + public void setGpuType(java.lang.String gpuType) { + this.gpuType = gpuType; + } + public java.lang.String getGpuType() { + return this.gpuType; + } + + public java.lang.Boolean isolated; + public void setIsolated(java.lang.Boolean isolated) { + this.isolated = isolated; + } + public java.lang.Boolean getIsolated() { + return this.isolated; + } + } From fa231786854cf49e31c7a67eeb9d4c0e242e96d1 Mon Sep 17 00:00:00 2001 From: AlanJager Date: Wed, 3 Dec 2025 14:50:38 +0800 Subject: [PATCH 18/48] [sdk]: Fix sdk and upgrade gpuVendor field Resolves: ZSTAC-80203 Change-Id: I73736d736c7775677273766572787462756d7a71 --- conf/db/upgrade/V5.4.6__schema.sql | 6 ++++++ sdk/src/main/java/org/zstack/sdk/GpuVendor.java | 10 +++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/conf/db/upgrade/V5.4.6__schema.sql b/conf/db/upgrade/V5.4.6__schema.sql index 1905c878f6..fd9e2c31f4 100644 --- a/conf/db/upgrade/V5.4.6__schema.sql +++ b/conf/db/upgrade/V5.4.6__schema.sql @@ -100,5 +100,11 @@ UPDATE ModelVO SET architectureType = 'sdxl-turbo' WHERE uuid = '6a720c01935f4f9 CALL ADD_COLUMN('ModelServiceVO', 'containerArgs', 'TEXT', 1, NULL); CALL ADD_COLUMN('ModelServiceVO', 'containerCommand', 'TEXT', 1, NULL); +-- Upgrade gpuVendor field in ModelServiceGpuVendorVO +Update ModelServiceGpuVendorVO set gpuVendor = 'Huawei' where gpuVendor = 'HUAWEI'; +Update ModelServiceGpuVendorVO set gpuVendor = 'Haiguang' where gpuVendor = 'HAIGUANG'; +Update ModelServiceGpuVendorVO set gpuVendor = 'TianShu' where gpuVendor = 'TIANSHU'; +Update ModelServiceGpuVendorVO set gpuVendor = 'Intel' where gpuVendor = 'INTEL'; + CALL ADD_COLUMN('GpuDeviceVO', 'isolated', 'TINYINT(1)', 1, NULL); CALL ADD_COLUMN('GpuDeviceSpecVO', 'isolated', 'TINYINT(1)', 1, NULL); diff --git a/sdk/src/main/java/org/zstack/sdk/GpuVendor.java b/sdk/src/main/java/org/zstack/sdk/GpuVendor.java index ef07274374..d5f4842085 100644 --- a/sdk/src/main/java/org/zstack/sdk/GpuVendor.java +++ b/sdk/src/main/java/org/zstack/sdk/GpuVendor.java @@ -1,11 +1,11 @@ package org.zstack.sdk; public enum GpuVendor { - INTEL, + Intel, AMD, NVIDIA, - HAIGUANG, - HUAWEI, - TIANSHU, - OTHER, + Haiguang, + Huawei, + TianShu, + Other, } From 18692ef672cf7bfdf84888b91606b865c856998e Mon Sep 17 00:00:00 2001 From: AlanJager Date: Wed, 3 Dec 2025 14:57:50 +0800 Subject: [PATCH 19/48] [conf]: Fix model services whose cpu arch missed in db DBImpact Resolves: ZSTAC-80334 Change-Id: I6d7470667a6b666a617575707474626a626a7a68 --- conf/db/upgrade/V5.4.6__schema.sql | 100 +++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/conf/db/upgrade/V5.4.6__schema.sql b/conf/db/upgrade/V5.4.6__schema.sql index 1905c878f6..77c3a4675d 100644 --- a/conf/db/upgrade/V5.4.6__schema.sql +++ b/conf/db/upgrade/V5.4.6__schema.sql @@ -102,3 +102,103 @@ CALL ADD_COLUMN('ModelServiceVO', 'containerCommand', 'TEXT', 1, NULL); CALL ADD_COLUMN('GpuDeviceVO', 'isolated', 'TINYINT(1)', 1, NULL); CALL ADD_COLUMN('GpuDeviceSpecVO', 'isolated', 'TINYINT(1)', 1, NULL); + +DELIMITER $$ + +DROP PROCEDURE IF EXISTS fix_missing_architecture_records$$ + +CREATE PROCEDURE fix_missing_architecture_records() +BEGIN + DECLARE done INT DEFAULT FALSE; + DECLARE v_model_service_uuid VARCHAR(32); + DECLARE v_architecture VARCHAR(32); + DECLARE v_exists INT; + + -- Cursor to find all model services that have templates but missing architecture records + DECLARE service_cursor CURSOR FOR + SELECT DISTINCT mst.modelServiceUuid, mst.cpuArchitecture + FROM ModelServiceTemplateVO mst + WHERE NOT EXISTS ( + SELECT 1 + FROM ModelServiceCpuArchitectureVO msca + WHERE msca.modelServiceUuid = mst.modelServiceUuid + AND msca.architecture = mst.cpuArchitecture + ) + ORDER BY mst.modelServiceUuid, mst.cpuArchitecture; + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; + + -- Start transaction + START TRANSACTION; + + -- Create a temporary table to store statistics + CREATE TEMPORARY TABLE IF NOT EXISTS fix_stats ( + total_services INT DEFAULT 0, + total_records_added INT DEFAULT 0 + ); + + INSERT INTO fix_stats VALUES (0, 0); + + -- Open cursor and process each missing architecture record + OPEN service_cursor; + + read_loop: LOOP + FETCH service_cursor INTO v_model_service_uuid, v_architecture; + + IF done THEN + LEAVE read_loop; + END IF; + + -- Double check if the record doesn't exist (to avoid duplicates) + SELECT COUNT(*) INTO v_exists + FROM ModelServiceCpuArchitectureVO + WHERE modelServiceUuid = v_model_service_uuid + AND architecture = v_architecture; + + IF v_exists = 0 THEN + -- Insert the missing architecture record + INSERT INTO ModelServiceCpuArchitectureVO (modelServiceUuid, architecture, lastOpDate, createDate) + VALUES ( + v_model_service_uuid, + v_architecture, + CURRENT_TIMESTAMP(3), + CURRENT_TIMESTAMP(3) + ); + + -- Update statistics + UPDATE fix_stats SET total_records_added = total_records_added + 1; + + -- Log the fix + SELECT CONCAT('Fixed: Added architecture record [', v_architecture, '] for model service [', v_model_service_uuid, ']') AS log_message; + END IF; + + END LOOP; + + CLOSE service_cursor; + + -- Count total affected services + UPDATE fix_stats SET total_services = ( + SELECT COUNT(DISTINCT modelServiceUuid) + FROM ModelServiceCpuArchitectureVO + WHERE createDate >= (SELECT MIN(createDate) FROM (SELECT createDate FROM ModelServiceCpuArchitectureVO ORDER BY createDate DESC LIMIT 1000) AS recent) + ); + + -- Display summary + SELECT + total_records_added AS 'Total Architecture Records Added', + (SELECT COUNT(DISTINCT modelServiceUuid) FROM ModelServiceTemplateVO) AS 'Total Model Services with Templates', + (SELECT COUNT(DISTINCT modelServiceUuid) FROM ModelServiceCpuArchitectureVO) AS 'Total Model Services with Architecture Records' + FROM fix_stats; + + -- Cleanup + DROP TEMPORARY TABLE IF EXISTS fix_stats; + + -- Commit transaction + COMMIT; + + SELECT 'Fix completed successfully!' AS status; +END$$ + +DELIMITER ; + +CALL fix_missing_architecture_records(); From 1372396968f48d9e2bf70ce9964edc5866737d1b Mon Sep 17 00:00:00 2001 From: AlanJager Date: Thu, 4 Dec 2025 15:32:47 +0800 Subject: [PATCH 20/48] [sdk]: Update sdk and add new fields Resolves: ZSTAC-78057 Change-Id: I67617a667567756a7578706a6c78646e6267756d --- conf/db/upgrade/V5.4.6__schema.sql | 4 ++++ .../main/java/org/zstack/sdk/AddModelAction.java | 6 ++++++ .../main/java/org/zstack/sdk/ModelInventory.java | 16 ++++++++++++++++ .../java/org/zstack/sdk/UpdateModelAction.java | 6 ++++++ 4 files changed, 32 insertions(+) diff --git a/conf/db/upgrade/V5.4.6__schema.sql b/conf/db/upgrade/V5.4.6__schema.sql index 9ee1050de7..b7280a5ac3 100644 --- a/conf/db/upgrade/V5.4.6__schema.sql +++ b/conf/db/upgrade/V5.4.6__schema.sql @@ -208,3 +208,7 @@ END$$ DELIMITER ; CALL fix_missing_architecture_records(); + +-- Add new gpu constraint fields +CALL ADD_COLUMN('ModelVO', 'recommendedGpuNum', 'VARCHAR(256)', 1, NULL); +CALL ADD_COLUMN('ModelVO', 'gpuConstraintDescription', 'VARCHAR(512)', 1, NULL); diff --git a/sdk/src/main/java/org/zstack/sdk/AddModelAction.java b/sdk/src/main/java/org/zstack/sdk/AddModelAction.java index 2dc39539fb..a43fcee825 100644 --- a/sdk/src/main/java/org/zstack/sdk/AddModelAction.java +++ b/sdk/src/main/java/org/zstack/sdk/AddModelAction.java @@ -61,6 +61,12 @@ public Result throwExceptionIfError() { @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.util.List modelServiceUuids; + @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String recommendedGpuNum; + + @Param(required = false, maxLength = 512, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String gpuConstraintDescription; + @Param(required = false) public java.lang.String resourceUuid; diff --git a/sdk/src/main/java/org/zstack/sdk/ModelInventory.java b/sdk/src/main/java/org/zstack/sdk/ModelInventory.java index a2ff03462f..ec46d527ee 100644 --- a/sdk/src/main/java/org/zstack/sdk/ModelInventory.java +++ b/sdk/src/main/java/org/zstack/sdk/ModelInventory.java @@ -116,6 +116,22 @@ public java.lang.Long getMinGpuMemory() { return this.minGpuMemory; } + public java.util.List recommendedGpuNum; + public void setRecommendedGpuNum(java.util.List recommendedGpuNum) { + this.recommendedGpuNum = recommendedGpuNum; + } + public java.util.List getRecommendedGpuNum() { + return this.recommendedGpuNum; + } + + public java.lang.String gpuConstraintDescription; + public void setGpuConstraintDescription(java.lang.String gpuConstraintDescription) { + this.gpuConstraintDescription = gpuConstraintDescription; + } + public java.lang.String getGpuConstraintDescription() { + return this.gpuConstraintDescription; + } + public java.lang.String versionSemver; public void setVersionSemver(java.lang.String versionSemver) { this.versionSemver = versionSemver; diff --git a/sdk/src/main/java/org/zstack/sdk/UpdateModelAction.java b/sdk/src/main/java/org/zstack/sdk/UpdateModelAction.java index 057e11a49a..1d440e5787 100644 --- a/sdk/src/main/java/org/zstack/sdk/UpdateModelAction.java +++ b/sdk/src/main/java/org/zstack/sdk/UpdateModelAction.java @@ -46,6 +46,12 @@ public Result throwExceptionIfError() { @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.util.List modelClassifications; + @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String recommendedGpuNum; + + @Param(required = false, maxLength = 512, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String gpuConstraintDescription; + @Param(required = false) public java.util.List systemTags; From 9741abc12d31168e987130dde608338f249269be Mon Sep 17 00:00:00 2001 From: AlanJager Date: Thu, 4 Dec 2025 18:22:29 +0800 Subject: [PATCH 21/48] [compute]: Export public method for static ip case Resolves: ZSTAC-80381 Change-Id: I7673656d7769756d706b736467797868666f7a69 --- .../org/zstack/compute/vm/StaticIpOperator.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/compute/src/main/java/org/zstack/compute/vm/StaticIpOperator.java b/compute/src/main/java/org/zstack/compute/vm/StaticIpOperator.java index 183b095154..0fe152196f 100755 --- a/compute/src/main/java/org/zstack/compute/vm/StaticIpOperator.java +++ b/compute/src/main/java/org/zstack/compute/vm/StaticIpOperator.java @@ -318,8 +318,7 @@ public void validateSystemTagInCreateMessage(APICreateMessage msg) { validateSystemTagInApiMessage(msg); } - public void validateSystemTagInApiMessage(APIMessage msg) { - Map staticIps = getNicNetworkInfoBySystemTag(msg.getSystemTags()); + public List fillUpStaticIpInfoToVmNics(Map staticIps) { List newSystags = new ArrayList<>(); for (Map.Entry e : staticIps.entrySet()) { String l3Uuid = e.getKey(); @@ -350,7 +349,7 @@ public void validateSystemTagInApiMessage(APIMessage msg) { )); } else if (!nicIp.ipv4Netmask.equals(ipRangeVO.getNetmask())) { throw new ApiMessageInterceptionException(operr("netmask error, expect: %s, got: %s", - ipRangeVO.getNetmask(), nicIp.ipv4Netmask)); + ipRangeVO.getNetmask(), nicIp.ipv4Netmask)); } if (StringUtils.isEmpty(nicIp.ipv4Gateway)) { @@ -397,10 +396,16 @@ public void validateSystemTagInApiMessage(APIMessage msg) { } } } + } - if (!newSystags.isEmpty()) { - msg.getSystemTags().addAll(newSystags); - } + return newSystags; + } + + public void validateSystemTagInApiMessage(APIMessage msg) { + Map staticIps = getNicNetworkInfoBySystemTag(msg.getSystemTags()); + List newSystags = fillUpStaticIpInfoToVmNics(staticIps); + if (!newSystags.isEmpty()) { + msg.getSystemTags().addAll(newSystags); } } From 2048e5bf807ff7aa2563952479b9351e94f4bc31 Mon Sep 17 00:00:00 2001 From: AlanJager Date: Thu, 4 Dec 2025 18:56:55 +0800 Subject: [PATCH 22/48] [conf]: Fix missing records in ModelServiceGpuVendorVO DBImpact Resolves: ZSTAC-80203 Change-Id: I6473736b7a716b77796b6b796467716e7062627a --- conf/db/upgrade/V5.4.6__schema.sql | 113 +++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/conf/db/upgrade/V5.4.6__schema.sql b/conf/db/upgrade/V5.4.6__schema.sql index b7280a5ac3..d9fae10108 100644 --- a/conf/db/upgrade/V5.4.6__schema.sql +++ b/conf/db/upgrade/V5.4.6__schema.sql @@ -212,3 +212,116 @@ CALL fix_missing_architecture_records(); -- Add new gpu constraint fields CALL ADD_COLUMN('ModelVO', 'recommendedGpuNum', 'VARCHAR(256)', 1, NULL); CALL ADD_COLUMN('ModelVO', 'gpuConstraintDescription', 'VARCHAR(512)', 1, NULL); + +DELIMITER $$ + +CREATE PROCEDURE update_system_model_service_templates() +BEGIN + DECLARE done INT DEFAULT FALSE; + DECLARE model_name VARCHAR(255); + DECLARE gpu_vendor_name VARCHAR(32); + DECLARE py_version VARCHAR(255); + DECLARE cuda_version VARCHAR(255); + DECLARE cann_version VARCHAR(255); + DECLARE fw_version VARCHAR(255); + DECLARE service_uuid VARCHAR(32); + + DECLARE templates_cursor CURSOR FOR + SELECT name, vendor, pythonVersion, cudaVersion, cannVersion, frameworkVersion FROM system_models_templates_to_update; + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; + + CREATE TEMPORARY TABLE IF NOT EXISTS system_models_templates_to_update ( + name VARCHAR(255), + vendor VARCHAR(32), + pythonVersion VARCHAR(255), + cudaVersion VARCHAR(255), + cannVersion VARCHAR(255), + frameworkVersion VARCHAR(255) + ); + + INSERT INTO system_models_templates_to_update (name, vendor, pythonVersion, cudaVersion, cannVersion, frameworkVersion) VALUES + ('vLLM-0.7.2', 'NVIDIA', '3.10', '12.5', NULL, '0.7.2'), + ('vLLM-0.8.5', 'NVIDIA', '3.10', '12.5', NULL, '0.8.5'), + ('vLLM-0.9.2', 'NVIDIA', '3.10', '12.5', NULL, '0.9.2'), + ('vLLM-0.11.0', 'NVIDIA', '3.10', '12.5', NULL, '0.11.0'), + ('SGLang-0.4.9.post1', 'NVIDIA', '3.10', '12.5', NULL, '0.4.9.post1'), + ('SGLang-0.5.2', 'NVIDIA', '3.10', '12.5', NULL, '0.5.2'), + ('SGLang-0.5.4', 'NVIDIA', '3.10', '12.5', NULL, '0.5.4'), + ('Transformers-4.48.3', 'NVIDIA', '3.10', '12.5', NULL, '4.48.3'), + ('Transformers-4.57.1', 'NVIDIA', '3.10', '12.5', NULL, '4.57.1'), + ('Transformers-4.56.2', 'NVIDIA', '3.10', '12.5', NULL, '4.56.2'), + ('sentence_transformers-3.1.1', 'NVIDIA', '3.10', '12.5', NULL, '3.1.1'), + ('Diffusers-0.30.0', 'NVIDIA', '3.10', '12.5', NULL, '0.30.0'), + ('Diffusers-0.35.1', 'NVIDIA', '3.10', '12.5', NULL, '0.35.1'), + ('MindIE-2.0.RC1-910B', 'Huawei', '3.9', NULL, '8.0', '2.0.RC1'), + ('MindIE-2.1.RC1-910B', 'Huawei', '3.9', NULL, '8.0', '2.1.RC1'), + ('MindIE-2.1.RC2-910B', 'Huawei', '3.9', NULL, '8.0', '2.1.RC2'), + ('MindIE-1.0.0-310P', 'Huawei', '3.9', NULL, '7.0', '1.0.0'), + ('vLLM-Ascend-0.11.0.rc0', 'Huawei', '3.9', NULL, '8.0', '0.11.0.rc0'), + ('vLLM-0.5.0-HYGON-Z100L', 'Haiguang', '3.10', NULL, NULL, '0.5.0'), + ('vLLM-0.8.5-HYGON-K100-AI', 'Haiguang', '3.10', NULL, NULL, '0.8.5'), + ('vLLM-0.9.2-HYGON-K100-AI', 'Haiguang', '3.10', NULL, NULL, '0.9.2'), + ('vLLM-0.7.2-HYGON-K100-AI', 'Haiguang', '3.10', NULL, NULL, '0.7.2'), + ('MinerU2.5-2509', 'NVIDIA', '3.10', '12.5', NULL, '2.5'); + + OPEN templates_cursor; + update_template_loop: LOOP + FETCH templates_cursor INTO model_name, gpu_vendor_name, py_version, cuda_version, cann_version, fw_version; + IF done THEN + LEAVE update_template_loop; + END IF; + + SELECT COUNT(*) INTO @cnt FROM `zstack`.`ModelServiceVO` WHERE name = model_name AND system = 1; + IF @cnt > 0 THEN + SELECT uuid INTO service_uuid FROM `zstack`.`ModelServiceVO` WHERE name = model_name AND system = 1 LIMIT 1; + ELSE + SET service_uuid = NULL; + END IF; + + IF service_uuid IS NOT NULL THEN + SELECT COUNT(*) INTO @tmpl_cnt FROM `zstack`.`ModelServiceTemplateVO` WHERE `modelServiceUuid` = service_uuid; + IF @tmpl_cnt > 0 THEN + UPDATE `zstack`.`ModelServiceTemplateVO` SET + `pythonVersionSemver` = py_version, + `cudaVersion` = cuda_version, + `cannVersion` = cann_version, + `frameworkVersionSemver` = fw_version, + `gpuVendor` = gpu_vendor_name + WHERE `modelServiceUuid` = service_uuid; + SELECT CONCAT('INFO: Updated ModelServiceTemplateVO for service_uuid=', service_uuid, ', updated_rows=', ROW_COUNT()) AS msg; + ELSE + INSERT INTO `zstack`.`ModelServiceTemplateVO` (`uuid`, `modelServiceUuid`, `pythonVersionSemver`, `cudaVersion`, `cannVersion`, `frameworkVersionSemver`, `gpuVendor`) + VALUES (REPLACE(UUID(),'-',''), service_uuid, py_version, cuda_version, cann_version, fw_version, gpu_vendor_name); + SELECT CONCAT('INFO: Inserted ModelServiceTemplateVO for service_uuid=', service_uuid, ', inserted_rows=', ROW_COUNT()) AS msg; + END IF; + + -- Ensure ModelServiceGpuVendorVO record exists with the corresponding gpuVendor for this modelServiceUuid + SELECT COUNT(*) INTO @gv_cnt FROM `zstack`.`ModelServiceGpuVendorVO` + WHERE `modelServiceUuid` = service_uuid AND `gpuVendor` = gpu_vendor_name; + IF @gv_cnt = 0 THEN + INSERT INTO `zstack`.`ModelServiceGpuVendorVO` (`modelServiceUuid`, `gpuVendor`) + VALUES (service_uuid, gpu_vendor_name); + SELECT CONCAT('INFO: Inserted ModelServiceGpuVendorVO for service_uuid=', service_uuid, ', gpuVendor=', gpu_vendor_name) AS msg; + ELSE + SELECT CONCAT('INFO: ModelServiceGpuVendorVO exists for service_uuid=', service_uuid, ', gpuVendor=', gpu_vendor_name) AS msg; + END IF; + ELSE + SELECT CONCAT('WARN: Service not found for model=', model_name, ', skipping template and gpuVendor update.') AS msg; + END IF; + + SET service_uuid = NULL; + END LOOP; + CLOSE templates_cursor; + + DROP TEMPORARY TABLE IF EXISTS system_models_templates_to_update; +END $$ +DELIMITER ; + +CALL update_system_model_service_templates(); +DROP PROCEDURE IF EXISTS update_system_model_service_templates; + +Update ModelServiceTemplateVO set gpuVendor = 'Huawei' where gpuVendor = 'HUAWEI'; +Update ModelServiceTemplateVO set gpuVendor = 'Haiguang' where gpuVendor = 'HAIGUANG'; +Update ModelServiceTemplateVO set gpuVendor = 'TianShu' where gpuVendor = 'TIANSHU'; +Update ModelServiceTemplateVO set gpuVendor = 'Intel' where gpuVendor = 'INTEL'; From 1d32a1ecda76bc787805aac8ec7564d0569a5ff7 Mon Sep 17 00:00:00 2001 From: J M Date: Mon, 3 Nov 2025 19:31:17 +0800 Subject: [PATCH 23/48] [storage]: use specify msg get volume path 1. add snapshot placement capability to external storage 2. ext ps controller cannot use extension point, move it to exp ps. 3. retain the ask meaning of AskSnapshotCapabilityMsg. Resolves: ZSTAC-79582 ZSTAC-79481 Change-Id: I7a7074707079616b696f7375757577666c79756b --- .../ExternalPrimaryStorage.xml | 8 +- conf/springConfigXml/zbs.xml | 1 - ...ningVolumePathFromInternalSnapshotMsg.java | 27 +++++++ ...ngVolumePathFromInternalSnapshotReply.java | 22 ++++++ .../primary/VolumeSnapshotCapability.java | 28 +++++-- .../ceph/primary/CephPrimaryStorageBase.java | 23 +++++- .../zstack/expon/ExponStorageController.java | 3 +- .../primary/ExternalStorageFencerType.java | 1 + .../primary/local/LocalStorageBase.java | 1 + .../primary/nfs/NfsPrimaryStorage.java | 1 + .../primary/smp/SMPPrimaryStorageBase.java | 1 + .../xinfini/XInfiniStorageController.java | 3 +- .../storage/zbs/ZbsStorageController.java | 3 +- .../zstack/storage/zbs/ZbsStorageFactory.java | 42 +--------- .../primary/SimulatorPrimaryStorage.java | 1 + .../addon/primary/ExternalPrimaryStorage.java | 34 +++++++- ...ChangeVolumeProcessingMethodExtension.java | 31 -------- .../ExternalPrimaryStorageFactory.java | 77 ++++++++++++++++++- .../storage/primary/PrimaryStorageBase.java | 7 ++ 19 files changed, 221 insertions(+), 93 deletions(-) create mode 100644 header/src/main/java/org/zstack/header/storage/primary/GetOwningVolumePathFromInternalSnapshotMsg.java create mode 100644 header/src/main/java/org/zstack/header/storage/primary/GetOwningVolumePathFromInternalSnapshotReply.java delete mode 100644 storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageChangeVolumeProcessingMethodExtension.java diff --git a/conf/springConfigXml/ExternalPrimaryStorage.xml b/conf/springConfigXml/ExternalPrimaryStorage.xml index f0b5f60289..55450dca7b 100644 --- a/conf/springConfigXml/ExternalPrimaryStorage.xml +++ b/conf/springConfigXml/ExternalPrimaryStorage.xml @@ -29,6 +29,8 @@ + + @@ -52,10 +54,4 @@ - - - - - - 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/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/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/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..6579e94139 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 @@ -3320,7 +3320,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 +4723,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 +5173,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() { @@ -6078,6 +6079,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 +6155,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/expon/src/main/java/org/zstack/expon/ExponStorageController.java b/plugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java index ca72e1a08b..2a3762f98f 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); 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..7c0e17cd17 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,6 +8,7 @@ * @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()); 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/NfsPrimaryStorage.java b/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java index 11e888024f..1a1f39a18c 100755 --- a/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java +++ b/plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java @@ -1336,6 +1336,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/sharedMountPointPrimaryStorage/src/main/java/org/zstack/storage/primary/smp/SMPPrimaryStorageBase.java b/plugin/sharedMountPointPrimaryStorage/src/main/java/org/zstack/storage/primary/smp/SMPPrimaryStorageBase.java index a554238854..38aeef95cc 100755 --- a/plugin/sharedMountPointPrimaryStorage/src/main/java/org/zstack/storage/primary/smp/SMPPrimaryStorageBase.java +++ b/plugin/sharedMountPointPrimaryStorage/src/main/java/org/zstack/storage/primary/smp/SMPPrimaryStorageBase.java @@ -396,6 +396,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/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java b/plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java index a43a9eaa6c..267d55f403 100644 --- a/plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java +++ b/plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java @@ -97,9 +97,10 @@ private String getVhostSocketDir() { VolumeSnapshotCapability scap = new VolumeSnapshotCapability(); scap.setSupport(true); scap.setArrangementType(VolumeSnapshotCapability.VolumeSnapshotArrangementType.INDIVIDUAL); + scap.setPlacementType(VolumeSnapshotCapability.VolumeSnapshotPlacementType.INTERNAL); scap.setSupportCreateOnHypervisor(false); scap.setSupportLazyDelete(false); - scap.setVolumePathFromInnerSnapshotRegex("^[^@]+"); + scap.setVolumePathFromInternalSnapshotRegex("^[^@]+"); capabilities.setSnapshotCapability(scap); capabilities.setSupportCloneFromVolume(false); capabilities.setSupportStorageQos(false); diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java index 01d67f7dee..4b725d7d95 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java @@ -109,9 +109,10 @@ public class ZbsStorageController implements PrimaryStorageControllerSvc, Primar VolumeSnapshotCapability scap = new VolumeSnapshotCapability(); scap.setSupport(true); scap.setArrangementType(VolumeSnapshotCapability.VolumeSnapshotArrangementType.INDIVIDUAL); + scap.setPlacementType(VolumeSnapshotCapability.VolumeSnapshotPlacementType.INTERNAL); scap.setSupportCreateOnHypervisor(false); scap.setSupportLazyDelete(false); - scap.setVolumePathFromInnerSnapshotRegex("^[^@]+"); + scap.setVolumePathFromInternalSnapshotRegex("^[^@]+"); capabilities.setSnapshotCapability(scap); capabilities.setSupportShareableVolume(true); capabilities.setSupportCloneFromVolume(false); diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageFactory.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageFactory.java index 43c95e77e7..df9fb479a2 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageFactory.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageFactory.java @@ -34,15 +34,10 @@ * @author Xingwei Yu * @date 2024/3/21 11:56 */ -public class ZbsStorageFactory implements ExternalPrimaryStorageSvcBuilder, BackupStorageSelector, VolumeSnapshotAfterDeleteExtensionPoint { +public class ZbsStorageFactory implements ExternalPrimaryStorageSvcBuilder, BackupStorageSelector { private static CLogger logger = Utils.getLogger(ZbsStorageFactory.class); public static final ExternalStorageFencerType fencerType = new ExternalStorageFencerType(ZbsConstants.IDENTITY, VolumeProtocol.CBD.toString()); - @Autowired - private CloudBus bus; - @Autowired - private StorageTrash trash; - private List preferBackupStorageTypes; @Override @@ -73,39 +68,4 @@ public List getPreferBackupStorageTypes() { public String getIdentity() { return ZbsConstants.IDENTITY; } - - @Override - public void volumeSnapshotAfterDeleteExtensionPoint(VolumeSnapshotInventory snapshot, NoErrorCompletion completion) { - completion.done(); - } - - private boolean isCbdProtocol(String volumeUuid) { - return Q.New(VolumeVO.class).eq(VolumeVO_.protocol, VolumeProtocol.CBD.toString()).eq(VolumeVO_.uuid, volumeUuid).isExists(); - } - - @Override - public void volumeSnapshotAfterCleanUpExtensionPoint(String volumeUuid, List snapshots) { - if (CollectionUtils.isEmpty(snapshots) || !isCbdProtocol(volumeUuid)) { - return; - } - - Set volumeInstallPaths = snapshots.stream().map(s -> getVolumeFromSnapshotPath(s.getPrimaryStorageInstallPath())) - .collect(Collectors.toSet()); - if (volumeInstallPaths.isEmpty()) { - return; - } - - volumeInstallPaths.forEach(volumeInstallPath -> { - String details = trash.makeSureInstallPathNotUsed(volumeInstallPath, VolumeVO.class.getSimpleName()); - - if (StringUtils.isBlank(details)) { - logger.debug(String.format("delete volume[InstallPath:%s] after cleaning up snapshots", volumeInstallPath)); - DeleteVolumeBitsOnPrimaryStorageMsg msg = new DeleteVolumeBitsOnPrimaryStorageMsg(); - msg.setPrimaryStorageUuid(snapshots.get(0).getPrimaryStorageUuid()); - msg.setInstallPath(volumeInstallPath); - bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, snapshots.get(0).getPrimaryStorageUuid()); - bus.send(msg); - } - }); - } } diff --git a/simulator/simulatorImpl/src/main/java/org/zstack/simulator/storage/primary/SimulatorPrimaryStorage.java b/simulator/simulatorImpl/src/main/java/org/zstack/simulator/storage/primary/SimulatorPrimaryStorage.java index a4c639c9bd..45cf8612a3 100755 --- a/simulator/simulatorImpl/src/main/java/org/zstack/simulator/storage/primary/SimulatorPrimaryStorage.java +++ b/simulator/simulatorImpl/src/main/java/org/zstack/simulator/storage/primary/SimulatorPrimaryStorage.java @@ -155,6 +155,7 @@ protected void handle(AskVolumeSnapshotCapabilityMsg msg) { AskVolumeSnapshotCapabilityReply reply = new AskVolumeSnapshotCapabilityReply(); VolumeSnapshotCapability capability = new VolumeSnapshotCapability(); capability.setArrangementType(VolumeSnapshotArrangementType.CHAIN); + capability.setPlacementType(VolumeSnapshotCapability.VolumeSnapshotPlacementType.EXTERNAL); capability.setSupport(true); reply.setCapability(capability); bus.reply(msg, reply); diff --git a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java index 05bea4ba5f..79332acdc8 100644 --- a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java +++ b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java @@ -55,6 +55,8 @@ import org.zstack.utils.logging.CLogger; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; import static org.zstack.core.Platform.operr; @@ -1866,12 +1868,18 @@ public void fail(ErrorCode errorCode) { }); flow(new NoRollbackFlow() { - // TODO: hardcode for expon final String __name__ = "delete-origin-root-volume-which-has-no-snapshot"; + @Override + public boolean skip(Map data) { + return controller.reportCapabilities().getSnapshotCapability() + .getPlacementType() != VolumeSnapshotCapability.VolumeSnapshotPlacementType.INTERNAL; + } + @Override public void run(FlowTrigger trigger, Map data) { boolean hasSnapshot = Q.New(VolumeSnapshotVO.class) + .eq(VolumeSnapshotVO_.volumeUuid, msg.getVolume().getUuid()) .like(VolumeSnapshotVO_.primaryStorageInstallPath, String.format("%s%%", msg.getVolume().getInstallPath())) .isExists(); if (!hasSnapshot) { @@ -1920,6 +1928,30 @@ protected void handle(AskInstallPathForNewSnapshotMsg msg) { bus.reply(msg, reply); } + @Override + protected void handle(GetOwningVolumePathFromInternalSnapshotMsg msg) { + GetOwningVolumePathFromInternalSnapshotReply reply = new GetOwningVolumePathFromInternalSnapshotReply(); + if (msg.getSnapshotPaths() != null) { + VolumeSnapshotCapability scap = controller.reportCapabilities().getSnapshotCapability(); + if (scap.getPlacementType() == VolumeSnapshotCapability.VolumeSnapshotPlacementType.INTERNAL) { + Pattern pattern = Pattern.compile(scap.getVolumePathFromInternalSnapshotRegex()); + for (String snapshotPath : msg.getSnapshotPaths()) { + Matcher matcher = pattern.matcher(snapshotPath); + if (matcher.find()) { + String volumePath = matcher.group(); + reply.putOwningVolumePath(snapshotPath, volumePath); + } else { + reply.setError(operr("cannot find owning volume path from internal snapshot path[%s], " + + "because the regex[%s] does not match the snapshot path", snapshotPath, scap.getVolumePathFromInternalSnapshotRegex())); + break; + } + } + } + } + + bus.reply(msg, reply); + } + @Override protected void handle(GetPrimaryStorageResourceLocationMsg msg) { bus.reply(msg, new GetPrimaryStorageResourceLocationReply()); diff --git a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageChangeVolumeProcessingMethodExtension.java b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageChangeVolumeProcessingMethodExtension.java deleted file mode 100644 index 09dbccb01b..0000000000 --- a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageChangeVolumeProcessingMethodExtension.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.zstack.storage.addon.primary; - -import org.zstack.core.db.Q; -import org.zstack.header.storage.primary.PrimaryStorageConstant; -import org.zstack.header.storage.primary.PrimaryStorageVO; -import org.zstack.header.storage.primary.PrimaryStorageVO_; -import org.zstack.header.storage.snapshot.VolumeSnapshotVO; -import org.zstack.header.storage.snapshot.VolumeSnapshotVO_; -import org.zstack.header.volume.VolumeDeletionPolicyManager; -import org.zstack.header.volume.VolumeInventory; -import org.zstack.storage.volume.ChangeVolumeProcessingMethodExtensionPoint; - -/** - * @author Xingwei Yu - * @date 2024/10/23 16:07 - */ -public class ExternalPrimaryStorageChangeVolumeProcessingMethodExtension implements ChangeVolumeProcessingMethodExtensionPoint { - @Override - public VolumeDeletionPolicyManager.VolumeDeletionPolicy getTransientVolumeDeletionPolicy(VolumeInventory transientVolume) { - String psType = Q.New(PrimaryStorageVO.class).eq(PrimaryStorageVO_.uuid, transientVolume.getPrimaryStorageUuid()).select(PrimaryStorageVO_.type).findValue(); - if (!psType.equals(PrimaryStorageConstant.EXTERNAL_PRIMARY_STORAGE_TYPE)) { - return null; - } - boolean hasSnapshots = Q.New(VolumeSnapshotVO.class).eq(VolumeSnapshotVO_.primaryStorageUuid, transientVolume.getPrimaryStorageUuid()) - .like(VolumeSnapshotVO_.primaryStorageInstallPath, String.format("%s@%%", transientVolume.getInstallPath())).isExists(); - if (!hasSnapshots) { - return VolumeDeletionPolicyManager.VolumeDeletionPolicy.Direct; - } - return VolumeDeletionPolicyManager.VolumeDeletionPolicy.DBOnly; - } -} diff --git a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageFactory.java b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageFactory.java index 6b21ab8325..a8e00d3a0a 100644 --- a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageFactory.java +++ b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageFactory.java @@ -1,5 +1,6 @@ package org.zstack.storage.addon.primary; +import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.zstack.core.Platform; import org.zstack.core.asyncbatch.While; @@ -11,6 +12,7 @@ import org.zstack.core.db.DatabaseFacade; import org.zstack.core.db.Q; import org.zstack.core.singleflight.MultiNodeSingleFlightImpl; +import org.zstack.core.trash.StorageTrash; import org.zstack.core.workflow.FlowChainBuilder; import org.zstack.header.Component; import org.zstack.header.apimediator.ApiMessageInterceptionException; @@ -38,17 +40,21 @@ import org.zstack.header.vm.*; import org.zstack.header.vm.cdrom.VmCdRomVO; import org.zstack.header.vm.cdrom.VmCdRomVO_; +import org.zstack.header.volume.VolumeDeletionPolicyManager; import org.zstack.header.volume.VolumeInventory; import org.zstack.header.volume.VolumeVO; import org.zstack.header.volume.block.BlockVolumeVO; import org.zstack.storage.addon.backup.ExternalBackupStorageFactory; import org.zstack.storage.primary.PrimaryStorageFeatureAllocatorExtensionPoint; import org.zstack.storage.snapshot.MarkRootVolumeAsSnapshotExtension; +import org.zstack.storage.volume.ChangeVolumeProcessingMethodExtensionPoint; import org.zstack.utils.CollectionUtils; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; import static org.zstack.core.Platform.argerr; @@ -58,7 +64,8 @@ public class ExternalPrimaryStorageFactory implements PrimaryStorageFactory, Com PreVmInstantiateResourceExtensionPoint, VmReleaseResourceExtensionPoint, VmAttachVolumeExtensionPoint, VmDetachVolumeExtensionPoint, BeforeTakeLiveSnapshotsOnVolumes, CreateTemplateFromVolumeSnapshotExtensionPoint, MarkRootVolumeAsSnapshotExtension, VmInstanceMigrateExtensionPoint, - ManagementNodeChangeListener, PrimaryStorageFeatureAllocatorExtensionPoint, HostResizeVolumeExtensionPoint { + ManagementNodeChangeListener, PrimaryStorageFeatureAllocatorExtensionPoint, HostResizeVolumeExtensionPoint, + VolumeSnapshotAfterDeleteExtensionPoint, ChangeVolumeProcessingMethodExtensionPoint { private static final CLogger logger = Utils.getLogger(ExternalBackupStorageFactory.class); public static PrimaryStorageType type = new PrimaryStorageType(PrimaryStorageConstant.EXTERNAL_PRIMARY_STORAGE_TYPE); @@ -81,6 +88,8 @@ public class ExternalPrimaryStorageFactory implements PrimaryStorageFactory, Com protected CloudBus bus; @Autowired protected EventFacade evtf; + @Autowired + protected StorageTrash trash; static { type.setSupportHeartbeatFile(true); @@ -1001,4 +1010,70 @@ public HostResizeVolumeStruct beforeKvmHostResizeVolume(HostResizeVolumeStruct s struct.setSize(controller.alignSize(struct.getSize())); return struct; } + + @Override + public void volumeSnapshotAfterDeleteExtensionPoint(VolumeSnapshotInventory snapshot, NoErrorCompletion completion) { + completion.done(); + } + + + @Override + public void volumeSnapshotAfterCleanUpExtensionPoint(String volumeUuid, List snapshots) { + if (CollectionUtils.isEmpty(snapshots)) { + return; + } + + String psUuid = snapshots.get(0).getPrimaryStorageUuid(); + PrimaryStorageControllerSvc controller = controllers.get(psUuid); + if (controller == null) { + return; + } + + VolumeSnapshotCapability snapCap = controller.reportCapabilities().getSnapshotCapability(); + if (snapCap.getPlacementType() != VolumeSnapshotCapability.VolumeSnapshotPlacementType.INTERNAL) { + return; + } + + Pattern pattern = Pattern.compile(snapCap.getVolumePathFromInternalSnapshotRegex()); + Set volumeInstallPaths = snapshots.stream().map(s -> { + Matcher matcher = pattern.matcher(s.getPrimaryStorageInstallPath()); + if (matcher.find()) { + return matcher.group(); + } else { + logger.warn(String.format("cannot find volume install path from internal snapshot install path[%s] " + + "by regex[%s], skip deleting volume bits on primary storage", s.getPrimaryStorageInstallPath(), + snapCap.getVolumePathFromInternalSnapshotRegex())); + return null; + } + }).filter(Objects::nonNull).collect(Collectors.toSet()); + + volumeInstallPaths.forEach(volumeInstallPath -> { + String details = trash.makeSureInstallPathNotUsed(volumeInstallPath, VolumeVO.class.getSimpleName()); + + if (StringUtils.isBlank(details)) { + logger.debug(String.format("delete volume[InstallPath:%s] after cleaning up snapshots", volumeInstallPath)); + DeleteVolumeBitsOnPrimaryStorageMsg msg = new DeleteVolumeBitsOnPrimaryStorageMsg(); + msg.setPrimaryStorageUuid(snapshots.get(0).getPrimaryStorageUuid()); + msg.setInstallPath(volumeInstallPath); + bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, snapshots.get(0).getPrimaryStorageUuid()); + bus.send(msg); + } + }); + } + + @Override + public VolumeDeletionPolicyManager.VolumeDeletionPolicy getTransientVolumeDeletionPolicy(VolumeInventory transientVolume) { + PrimaryStorageControllerSvc controllerSvc = controllers.get(transientVolume.getPrimaryStorageUuid()); + if (controllerSvc == null || controllerSvc.reportCapabilities().getSnapshotCapability() + .getPlacementType() != VolumeSnapshotCapability.VolumeSnapshotPlacementType.INTERNAL) { + return null; + } + + boolean hasSnapshots = Q.New(VolumeSnapshotVO.class).eq(VolumeSnapshotVO_.primaryStorageUuid, transientVolume.getPrimaryStorageUuid()) + .like(VolumeSnapshotVO_.primaryStorageInstallPath, String.format("%s@%%", transientVolume.getInstallPath())).isExists(); + if (!hasSnapshots) { + return VolumeDeletionPolicyManager.VolumeDeletionPolicy.Direct; + } + return VolumeDeletionPolicyManager.VolumeDeletionPolicy.DBOnly; + } } diff --git a/storage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.java b/storage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.java index 6f9515a1e4..a5011877ba 100755 --- a/storage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.java +++ b/storage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.java @@ -413,6 +413,8 @@ protected void handleLocalMessage(Message msg) { handle((DeleteVolumeChainOnPrimaryStorageMsg) msg); } else if (msg instanceof CleanUpStorageTrashOnPrimaryStorageMsg) { handle((CleanUpStorageTrashOnPrimaryStorageMsg)msg); + } else if (msg instanceof GetOwningVolumePathFromInternalSnapshotMsg) { + handle((GetOwningVolumePathFromInternalSnapshotMsg) msg); } else { bus.dealWithUnknownMessage(msg); } @@ -1763,6 +1765,11 @@ protected void handle(UnlinkBitsOnPrimaryStorageMsg msg) { bus.reply(msg, reply); }; + protected void handle(GetOwningVolumePathFromInternalSnapshotMsg msg) { + GetOwningVolumePathFromInternalSnapshotReply reply = new GetOwningVolumePathFromInternalSnapshotReply(); + bus.reply(msg, reply); + } + // don't attach any cluster public boolean isUnmounted() { long count = Q.New(PrimaryStorageClusterRefVO.class) From e0cb873e60526e4b98e54b732485b46874157060 Mon Sep 17 00:00:00 2001 From: AlanJager Date: Fri, 5 Dec 2025 15:28:19 +0800 Subject: [PATCH 24/48] [conf]: Upgrade GpuDeviceVO add gpuStatus DBImpact Resolves: ZSTAC-79761 Change-Id: I7662666569656f6c736d736667747679726a666c --- conf/db/upgrade/V5.4.6__schema.sql | 4 ++++ sdk/src/main/java/org/zstack/sdk/GpuDeviceInventory.java | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/conf/db/upgrade/V5.4.6__schema.sql b/conf/db/upgrade/V5.4.6__schema.sql index d9fae10108..c268fff057 100644 --- a/conf/db/upgrade/V5.4.6__schema.sql +++ b/conf/db/upgrade/V5.4.6__schema.sql @@ -325,3 +325,7 @@ Update ModelServiceTemplateVO set gpuVendor = 'Huawei' where gpuVendor = 'HUAWEI Update ModelServiceTemplateVO set gpuVendor = 'Haiguang' where gpuVendor = 'HAIGUANG'; Update ModelServiceTemplateVO set gpuVendor = 'TianShu' where gpuVendor = 'TIANSHU'; Update ModelServiceTemplateVO set gpuVendor = 'Intel' where gpuVendor = 'INTEL'; + +CALL ADD_COLUMN('GpuDeviceVO', 'gpuStatus', 'varchar(16)', 1, NULL); + +UPDATE `zstack`.`GpuDeviceVO` SET `gpuStatus`='nominal' WHERE `gpuStatus` IS NULL; diff --git a/sdk/src/main/java/org/zstack/sdk/GpuDeviceInventory.java b/sdk/src/main/java/org/zstack/sdk/GpuDeviceInventory.java index c45b9f27ba..587c9cbeae 100644 --- a/sdk/src/main/java/org/zstack/sdk/GpuDeviceInventory.java +++ b/sdk/src/main/java/org/zstack/sdk/GpuDeviceInventory.java @@ -44,6 +44,14 @@ public java.lang.String getGpuType() { return this.gpuType; } + public java.lang.String gpuStatus; + public void setGpuStatus(java.lang.String gpuStatus) { + this.gpuStatus = gpuStatus; + } + public java.lang.String getGpuStatus() { + return this.gpuStatus; + } + public GpuAllocateStatus allocateStatus; public void setAllocateStatus(GpuAllocateStatus allocateStatus) { this.allocateStatus = allocateStatus; From 1d5b821e8ee832d3c39d5aa8e8cdae560240026f Mon Sep 17 00:00:00 2001 From: "xinhao.huang" Date: Fri, 5 Dec 2025 18:37:17 +0800 Subject: [PATCH 25/48] [conf]: update ModelServiceInstanceGroupVO schema - add column supportMetrics for ModelServiceInstanceGroupVO DBImpact Resolves: ZSTAC-80375 Change-Id: I6862697569686b7a6b6e787673696e71736f6169 --- conf/db/upgrade/V5.4.6__schema.sql | 22 +++++++++++++++++++ .../ModelServiceInstanceGroupInventory.java | 8 +++++++ 2 files changed, 30 insertions(+) diff --git a/conf/db/upgrade/V5.4.6__schema.sql b/conf/db/upgrade/V5.4.6__schema.sql index c268fff057..9030590e1d 100644 --- a/conf/db/upgrade/V5.4.6__schema.sql +++ b/conf/db/upgrade/V5.4.6__schema.sql @@ -329,3 +329,25 @@ Update ModelServiceTemplateVO set gpuVendor = 'Intel' where gpuVendor = 'INTEL'; CALL ADD_COLUMN('GpuDeviceVO', 'gpuStatus', 'varchar(16)', 1, NULL); UPDATE `zstack`.`GpuDeviceVO` SET `gpuStatus`='nominal' WHERE `gpuStatus` IS NULL; + +-- Add supportMetrics column to ModelServiceInstanceGroupVO +DROP PROCEDURE IF EXISTS addModelServiceInstanceGroupSupportMetricsColumn; +DELIMITER $$ +CREATE PROCEDURE addModelServiceInstanceGroupSupportMetricsColumn() +BEGIN + DECLARE columnExists BOOLEAN DEFAULT FALSE; + + SELECT COUNT(*) INTO columnExists + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_NAME = 'ModelServiceInstanceGroupVO' + AND COLUMN_NAME = 'supportMetrics' + AND TABLE_SCHEMA = 'zstack'; + + IF columnExists = FALSE THEN + ALTER TABLE `zstack`.`ModelServiceInstanceGroupVO` ADD COLUMN `supportMetrics` TEXT DEFAULT NULL; + END IF; +END $$ +DELIMITER ; + +CALL addModelServiceInstanceGroupSupportMetricsColumn(); +DROP PROCEDURE IF EXISTS addModelServiceInstanceGroupSupportMetricsColumn; diff --git a/sdk/src/main/java/org/zstack/sdk/ModelServiceInstanceGroupInventory.java b/sdk/src/main/java/org/zstack/sdk/ModelServiceInstanceGroupInventory.java index 8720f3ff25..25ad17e970 100644 --- a/sdk/src/main/java/org/zstack/sdk/ModelServiceInstanceGroupInventory.java +++ b/sdk/src/main/java/org/zstack/sdk/ModelServiceInstanceGroupInventory.java @@ -108,4 +108,12 @@ public java.lang.String getYaml() { return this.yaml; } + public java.util.List supportMetrics; + public void setSupportMetrics(java.util.List supportMetrics) { + this.supportMetrics = supportMetrics; + } + public java.util.List getSupportMetrics() { + return this.supportMetrics; + } + } From 55a16d3f1213c348a8c2005f0cdc8a4b97b78102 Mon Sep 17 00:00:00 2001 From: AlanJager Date: Mon, 8 Dec 2025 10:12:24 +0800 Subject: [PATCH 26/48] [conf]: Fix gpu work status upgrade sql Fix status from lowercase to uppercase, to avoid Enum.valueOf failure DBImpact Resolves: ZSTAC-80451 Change-Id: I67646d73796f7076626d6a616664746c76757979 --- conf/db/upgrade/V5.4.6__schema.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/db/upgrade/V5.4.6__schema.sql b/conf/db/upgrade/V5.4.6__schema.sql index 9030590e1d..c487fde82d 100644 --- a/conf/db/upgrade/V5.4.6__schema.sql +++ b/conf/db/upgrade/V5.4.6__schema.sql @@ -328,7 +328,7 @@ Update ModelServiceTemplateVO set gpuVendor = 'Intel' where gpuVendor = 'INTEL'; CALL ADD_COLUMN('GpuDeviceVO', 'gpuStatus', 'varchar(16)', 1, NULL); -UPDATE `zstack`.`GpuDeviceVO` SET `gpuStatus`='nominal' WHERE `gpuStatus` IS NULL; +UPDATE `zstack`.`GpuDeviceVO` SET `gpuStatus`='NOMINAL' WHERE `gpuStatus` IS NULL; -- Add supportMetrics column to ModelServiceInstanceGroupVO DROP PROCEDURE IF EXISTS addModelServiceInstanceGroupSupportMetricsColumn; From 7ad8dac200b79b96e2b7bd08458d099485610cab Mon Sep 17 00:00:00 2001 From: AlanJager Date: Mon, 8 Dec 2025 10:55:19 +0800 Subject: [PATCH 27/48] [sdk]: Update sdk Resolves: ZSTAC-80172 Change-Id: I7774626b796a6b626a626b78656d6f69656a7274 --- .../org/zstack/sdk/DeleteModelEvaluationTasksResult.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sdk/src/main/java/org/zstack/sdk/DeleteModelEvaluationTasksResult.java b/sdk/src/main/java/org/zstack/sdk/DeleteModelEvaluationTasksResult.java index 5d1619bb4e..9da05d4467 100644 --- a/sdk/src/main/java/org/zstack/sdk/DeleteModelEvaluationTasksResult.java +++ b/sdk/src/main/java/org/zstack/sdk/DeleteModelEvaluationTasksResult.java @@ -3,5 +3,12 @@ public class DeleteModelEvaluationTasksResult { + public java.util.List results; + public void setResults(java.util.List results) { + this.results = results; + } + public java.util.List getResults() { + return this.results; + } } From 6c8be0f7949af8c96a02ba01c13f446a2ddd9570 Mon Sep 17 00:00:00 2001 From: lianghy Date: Thu, 20 Nov 2025 18:01:34 +0800 Subject: [PATCH 28/48] [iam2-ldap]: support two-factor authentication for AD/LDAP accounts Resolves: ZSTAC-73108 Change-Id: I646373108a7923767067706e7a6e667a796f686d --- .../org/zstack/sdk/GetTwoFactorAuthenticationSecretAction.java | 2 +- .../zstack/sdk/ResetTwoFactorAuthenticationSecretAction.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/src/main/java/org/zstack/sdk/GetTwoFactorAuthenticationSecretAction.java b/sdk/src/main/java/org/zstack/sdk/GetTwoFactorAuthenticationSecretAction.java index 7968d3fe2b..6023de4803 100644 --- a/sdk/src/main/java/org/zstack/sdk/GetTwoFactorAuthenticationSecretAction.java +++ b/sdk/src/main/java/org/zstack/sdk/GetTwoFactorAuthenticationSecretAction.java @@ -31,7 +31,7 @@ public Result throwExceptionIfError() { @Param(required = true, nonempty = true, nullElements = false, emptyString = true, noTrim = false) public java.lang.String password; - @Param(required = true, validValues = {"account","iam2"}, nonempty = true, nullElements = false, emptyString = true, noTrim = false) + @Param(required = true, validValues = {"account","iam2","iam2-ldap"}, nonempty = true, nullElements = false, emptyString = true, noTrim = false) public java.lang.String type; @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) diff --git a/sdk/src/main/java/org/zstack/sdk/ResetTwoFactorAuthenticationSecretAction.java b/sdk/src/main/java/org/zstack/sdk/ResetTwoFactorAuthenticationSecretAction.java index ce0a61a40a..f3633f18b7 100644 --- a/sdk/src/main/java/org/zstack/sdk/ResetTwoFactorAuthenticationSecretAction.java +++ b/sdk/src/main/java/org/zstack/sdk/ResetTwoFactorAuthenticationSecretAction.java @@ -31,7 +31,7 @@ public Result throwExceptionIfError() { @Param(required = true, nonempty = true, nullElements = false, emptyString = true, noTrim = false) public java.lang.String password; - @Param(required = true, validValues = {"account","iam2"}, nonempty = true, nullElements = false, emptyString = true, noTrim = false) + @Param(required = true, validValues = {"account","iam2","iam2-ldap"}, nonempty = true, nullElements = false, emptyString = true, noTrim = false) public java.lang.String type; @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) From 845671dfdc7133ced74a0db38754fa8906fea1ed Mon Sep 17 00:00:00 2001 From: "boce.wang" Date: Wed, 5 Nov 2025 15:37:01 +0800 Subject: [PATCH 29/48] [applianceVm]: support sriov bond - ApplianceVm support vf nic bond in vm Resolves: ZSTAC-79984 Change-Id: I6868776c48bfce58c0324b2397c5197eab1af751 --- .../allocator/HostAllocatorManagerImpl.java | 14 ++-- .../compute/allocator/HostSortorChain.java | 6 +- conf/db/upgrade/V5.5.0__schema.sql | 2 + .../appliancevm/ApplianceVmFacadeImpl.java | 20 +++++- ...ApplianceVmNicBootstrapExtensionPoint.java | 7 ++ .../zstack/appliancevm/ApplianceVmNicTO.java | 9 +++ .../java/org/zstack/kvm/KVMAgentCommands.java | 9 +++ .../main/java/org/zstack/kvm/KVMConstant.java | 1 + .../service/virtualrouter/VirtualRouter.java | 18 +++++ .../virtualrouter/VirtualRouterCommands.java | 9 +++ .../VirtualRouterManagerImpl.java | 68 ++++++++++++++++--- .../lb/VirtualRouterLoadBalancerBackend.java | 17 ++++- sdk/src/main/java/org/zstack/sdk/NicTO.java | 8 +++ .../java/org/zstack/sdk/VmVfNicInventory.java | 8 +++ 14 files changed, 177 insertions(+), 19 deletions(-) create mode 100644 conf/db/upgrade/V5.5.0__schema.sql create mode 100644 plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmNicBootstrapExtensionPoint.java diff --git a/compute/src/main/java/org/zstack/compute/allocator/HostAllocatorManagerImpl.java b/compute/src/main/java/org/zstack/compute/allocator/HostAllocatorManagerImpl.java index 814cf91b83..c1eb12ba20 100755 --- a/compute/src/main/java/org/zstack/compute/allocator/HostAllocatorManagerImpl.java +++ b/compute/src/main/java/org/zstack/compute/allocator/HostAllocatorManagerImpl.java @@ -530,12 +530,14 @@ public void fail(ErrorCode errorCode) { @Override public void rollback(FlowRollback trigger, Map data) { - ReturnHostCapacityMsg rmsg = new ReturnHostCapacityMsg(); - rmsg.setHostUuid(reply.getHost().getUuid()); - rmsg.setMemoryCapacity(spec.getMemoryCapacity()); - rmsg.setCpuCapacity(spec.getCpuCapacity()); - bus.makeTargetServiceIdByResourceUuid(rmsg, HostAllocatorConstant.SERVICE_ID, rmsg.getHostUuid()); - bus.send(rmsg); + if (reply.getHost() != null) { + ReturnHostCapacityMsg rmsg = new ReturnHostCapacityMsg(); + rmsg.setHostUuid(reply.getHost().getUuid()); + rmsg.setMemoryCapacity(spec.getMemoryCapacity()); + rmsg.setCpuCapacity(spec.getCpuCapacity()); + bus.makeTargetServiceIdByResourceUuid(rmsg, HostAllocatorConstant.SERVICE_ID, rmsg.getHostUuid()); + bus.send(rmsg); + } trigger.rollback(); } }).then(new NoRollbackFlow() { diff --git a/compute/src/main/java/org/zstack/compute/allocator/HostSortorChain.java b/compute/src/main/java/org/zstack/compute/allocator/HostSortorChain.java index a96ac0db75..cbffe13761 100644 --- a/compute/src/main/java/org/zstack/compute/allocator/HostSortorChain.java +++ b/compute/src/main/java/org/zstack/compute/allocator/HostSortorChain.java @@ -195,7 +195,11 @@ public void fail(ErrorCode errorCode) { @Override public void done(ErrorCodeList errorCodeList) { if (selectedHost.get() == null) { - completion.fail(errorCodeList); + if (!errorCodeList.getCauses().isEmpty()) { + completion.fail(errorCodeList.getCauses().get(0)); + } else { + completion.fail(operr("failed to reserve host capacity for all candidate hosts")); + } return; } completion.success(selectedHost.get()); diff --git a/conf/db/upgrade/V5.5.0__schema.sql b/conf/db/upgrade/V5.5.0__schema.sql new file mode 100644 index 0000000000..802f0170ea --- /dev/null +++ b/conf/db/upgrade/V5.5.0__schema.sql @@ -0,0 +1,2 @@ +CALL ADD_COLUMN('VmVfNicVO', 'secondaryPciDeviceUuid', 'VARCHAR(32)', 1, NULL); +ALTER TABLE `zstack`.`VmVfNicVO` ADD CONSTRAINT `fkVmVfNicVOSecondaryPciDeviceVO` FOREIGN KEY (`secondaryPciDeviceUuid`) REFERENCES `zstack`.`PciDeviceVO` (`uuid`) ON DELETE SET NULL; \ No newline at end of file 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 9a415a48bf..871479f13a 100755 --- a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmFacadeImpl.java +++ b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmFacadeImpl.java @@ -86,6 +86,7 @@ public class ApplianceVmFacadeImpl extends AbstractService implements ApplianceV 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()); @@ -222,7 +223,7 @@ 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); @@ -234,6 +235,11 @@ private void populateExtensions() { 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() { @@ -347,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; @@ -386,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"); @@ -424,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); @@ -440,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 ++; @@ -637,7 +653,7 @@ public void detachVirtualRouterFromHaGroup(String vmUuid, String haGroupUuid) { ext.detachVirtualRouterFromHaGroup(vmUuid, haGroupUuid); } } - + public ApvmCascadeFilterExtensionPoint getApvmCascadeFilterExtensionPoint(ApplianceVmType type) { return apvmCascadeFilterExtensionPointMap.get(type); } 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/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java b/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java index 91e5d885bd..3b2eebb15e 100755 --- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java +++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java @@ -1208,6 +1208,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 +1316,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; } 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..283fa68af5 100755 --- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMConstant.java +++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMConstant.java @@ -65,6 +65,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"; diff --git a/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouter.java b/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouter.java index 85287633e0..32a4448b68 100755 --- a/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouter.java +++ b/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouter.java @@ -945,6 +945,22 @@ public void attachNetworkService(String vrUuid, String networkServiceType, Strin public void detachNetworkService(String vrUuid, String networkServiceType, String l3NetworkUuid){ } + private void fillNicBondMode(VmNicInventory nicInventory, VirtualRouterCommands.NicInfo info) { + info.setBondMode("none"); + + List exts = pluginRgty.getExtensionList(ApplianceVmNicBootstrapExtensionPoint.class); + if (exts == null || exts.isEmpty()) { + return; + } + + ApplianceVmNicTO nicTO = new ApplianceVmNicTO(); + nicTO.setBondMode("none"); + for (ApplianceVmNicBootstrapExtensionPoint ext : exts) { + ext.fillNicBootstrapInfo(nicInventory, nicTO); + } + info.setBondMode(nicTO.getBondMode()); + } + public class virtualRouterAfterAttachNicFlow extends NoRollbackFlow { @Override public void run(FlowTrigger trigger, Map data) { @@ -987,6 +1003,7 @@ public void run(FlowTrigger trigger, Map data) { } info.setMtu(new MtuGetter().getMtu(l3NetworkVO.getUuid())); info.setState(nicInventory.getState()); + fillNicBondMode(nicInventory, info); cmd.setNics(Arrays.asList(info)); VirtualRouterAsyncHttpCallMsg cmsg = new VirtualRouterAsyncHttpCallMsg(); @@ -1314,6 +1331,7 @@ public void run(FlowTrigger trigger, Map data) { info.setGateway(nicInventory.getGateway()); info.setMac(nicInventory.getMac()); info.setNetmask(nicInventory.getNetmask()); + fillNicBondMode(nicInventory, info); cmd.setNics(Arrays.asList(info)); VirtualRouterAsyncHttpCallMsg cmsg = new VirtualRouterAsyncHttpCallMsg(); diff --git a/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterCommands.java b/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterCommands.java index 3d9f963605..6b167a0b89 100755 --- a/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterCommands.java +++ b/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterCommands.java @@ -196,6 +196,7 @@ public static class NicInfo { private String gateway6; private String addressMode; private String state; + private String bondMode; public String getIp() { return ip; @@ -315,6 +316,14 @@ public String getState() { public void setState(String state) { this.state = state; } + + public String getBondMode() { + return bondMode; + } + + public void setBondMode(String bondMode) { + this.bondMode = bondMode; + } } public static class ConfigureNicCmd extends AgentCommand { diff --git a/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterManagerImpl.java b/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterManagerImpl.java index ca14cc7899..e5880b3f83 100755 --- a/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterManagerImpl.java +++ b/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouterManagerImpl.java @@ -2718,19 +2718,69 @@ public void run(MessageReply reply) { } private List findVipsOnVirtualRouter(List vfNics, String vrUuid) { - List vipUuids = SQL.New("select vip.uuid from VipVO vip, VipPeerL3NetworkRefVO ref " + - "where ref.vipUuid = vip.uuid " + - "and (ref.l3NetworkUuid in (:l3NetworkUuids) " + - "or vip.l3NetworkUuid in (:l3NetworkUuids))") - .param("l3NetworkUuids", vfNics.stream().map(VmNicInventory::getL3NetworkUuid).collect(Collectors.toList())) - .list(); + List l3Uuids = vfNics.stream().map(VmNicInventory::getL3NetworkUuid).collect(Collectors.toList()); + List l3Networks = Q.New(L3NetworkVO.class).in(L3NetworkVO_.uuid, l3Uuids).list(); + + /* separate private l3 and public/system l3 by category */ + List guestL3Uuids = l3Networks.stream() + .filter(l3 -> L3NetworkCategory.Private.equals(l3.getCategory())) + .map(L3NetworkVO::getUuid) + .collect(Collectors.toList()); + /* public and system l3 are both treated as public l3, because they are shared resources among VRs */ + List publicL3Uuids = l3Networks.stream() + .filter(l3 -> L3NetworkCategory.Public.equals(l3.getCategory()) || + L3NetworkCategory.System.equals(l3.getCategory())) + .map(L3NetworkVO::getUuid) + .collect(Collectors.toList()); + + Set vipUuids = new HashSet<>(); + + /* for guest vf nics, find vips bindingto these l3 networks as peerL3 */ + if (!guestL3Uuids.isEmpty()) { + List guestVipUuids = SQL.New("select vip.uuid from VipVO vip, VipPeerL3NetworkRefVO ref " + + "where ref.vipUuid = vip.uuid " + + "and ref.l3NetworkUuid in (:l3NetworkUuids)") + .param("l3NetworkUuids", guestL3Uuids) + .list(); + vipUuids.addAll(guestVipUuids); + } + + /* for public vf nics, find vips bindingto this vr and bindingto these l3 networks as public l3 */ + if (!publicL3Uuids.isEmpty()) { + List publicVipUuids = SQL.New("select vip.uuid from VipVO vip, VirtualRouterVipVO ref " + + "where ref.uuid = vip.uuid " + + "and ref.virtualRouterVmUuid = :vrUuid " + + "and vip.l3NetworkUuid in (:l3NetworkUuids)") + .param("vrUuid", vrUuid) + .param("l3NetworkUuids", publicL3Uuids) + .list(); + vipUuids.addAll(publicVipUuids); + + String haUuid = haBackend.getVirtualRouterHaUuid(vrUuid); + if (haUuid != null) { + List haVipUuids = SQL.New("select vip.uuid from VipVO vip, VpcHaGroupNetworkServiceRefVO ref " + + "where ref.networkServiceUuid = vip.uuid " + + "and ref.vpcHaRouterUuid = :haUuid " + + "and ref.networkServiceName = :vipType " + + "and vip.l3NetworkUuid in (:l3NetworkUuids)") + .param("haUuid", haUuid) + .param("vipType", VipVO.class.getSimpleName()) + .param("l3NetworkUuids", publicL3Uuids) + .list(); + vipUuids.addAll(haVipUuids); + } + } + + if (vipUuids.isEmpty()) { + return new ArrayList<>(); + } - vipUuids = getVirtualRouterVips(vrUuid, vipUuids); - if (vipUuids == null || vipUuids.isEmpty()) { + List filteredVipUuids = getVirtualRouterVips(vrUuid, new ArrayList<>(vipUuids)); + if (filteredVipUuids == null || filteredVipUuids.isEmpty()) { return new ArrayList<>(); } - List vips = Q.New(VipVO.class).in(VipVO_.uuid, vipUuids).list(); + List vips = Q.New(VipVO.class).in(VipVO_.uuid, filteredVipUuids).list(); VirtualRouterVmInventory vr = VirtualRouterVmInventory.valueOf((VirtualRouterVmVO) Q.New(VirtualRouterVmVO.class).eq(VirtualRouterVmVO_.uuid, vrUuid).find()); diff --git a/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/lb/VirtualRouterLoadBalancerBackend.java b/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/lb/VirtualRouterLoadBalancerBackend.java index c08db61161..3ee3d33449 100755 --- a/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/lb/VirtualRouterLoadBalancerBackend.java +++ b/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/lb/VirtualRouterLoadBalancerBackend.java @@ -953,6 +953,16 @@ public int compare(LoadBalancerServerGroupServerIpInventory r1, LoadBalancerServ } } if (addIp) { + // Check if VR has a NIC connected to this L3 network + if (vr != null) { + boolean vrHasL3Network = vr.getVmNics().stream() + .anyMatch(vrNic -> usedIpInventory.getL3NetworkUuid().equals(vrNic.getL3NetworkUuid())); + if (!vrHasL3Network) { + logger.warn(String.format("VR[uuid:%s] has no NIC connected to L3Network[uuid:%s], " + + "skip backend server IP[%s]", vr.getUuid(), usedIpInventory.getL3NetworkUuid(), usedIpInventory.getIp())); + continue; + } + } ips.add(usedIpInventory.getIp()); params.add(String.format("balancerWeight::%s::%s", usedIpInventory.getIp(), nicRef.getWeight())); backendServers.add(new LbTO.BackendServer(usedIpInventory.getIp(), nicRef.getWeight())); @@ -2572,7 +2582,12 @@ private List getLoadBalancersByL3Networks(String l3Uuid, boo LoadBalancerStruct struct = new LoadBalancerStruct(); LoadBalancerVO lb = dbf.findByUuid(e.getKey(), LoadBalancerVO.class); struct.setLb(LoadBalancerInventory.valueOf(lb)); - struct.setVip(VipInventory.valueOf(dbf.findByUuid(lb.getVipUuid(), VipVO.class))); + if (lb.getVipUuid() != null) { + struct.setVip(VipInventory.valueOf(dbf.findByUuid(lb.getVipUuid(), VipVO.class))); + } + if (lb.getIpv6VipUuid() != null) { + struct.setIpv6Vip(VipInventory.valueOf(dbf.findByUuid(lb.getIpv6VipUuid(), VipVO.class))); + } struct.setListenerServerGroupMap(new HashMap<>()); List serverGroupUuids = new ArrayList<>(); diff --git a/sdk/src/main/java/org/zstack/sdk/NicTO.java b/sdk/src/main/java/org/zstack/sdk/NicTO.java index 2dc95ea852..6eecb1466a 100644 --- a/sdk/src/main/java/org/zstack/sdk/NicTO.java +++ b/sdk/src/main/java/org/zstack/sdk/NicTO.java @@ -149,6 +149,14 @@ public java.lang.String getPciDeviceAddress() { return this.pciDeviceAddress; } + public java.util.List extraPciDeviceAddresses; + public void setExtraPciDeviceAddresses(java.util.List extraPciDeviceAddresses) { + this.extraPciDeviceAddresses = extraPciDeviceAddresses; + } + public java.util.List getExtraPciDeviceAddresses() { + return this.extraPciDeviceAddresses; + } + public java.lang.String ipForTf; public void setIpForTf(java.lang.String ipForTf) { this.ipForTf = ipForTf; diff --git a/sdk/src/main/java/org/zstack/sdk/VmVfNicInventory.java b/sdk/src/main/java/org/zstack/sdk/VmVfNicInventory.java index 1a25f664e0..e008576b36 100644 --- a/sdk/src/main/java/org/zstack/sdk/VmVfNicInventory.java +++ b/sdk/src/main/java/org/zstack/sdk/VmVfNicInventory.java @@ -20,4 +20,12 @@ public java.lang.String getHaState() { return this.haState; } + public java.lang.String secondaryPciDeviceUuid; + public void setSecondaryPciDeviceUuid(java.lang.String secondaryPciDeviceUuid) { + this.secondaryPciDeviceUuid = secondaryPciDeviceUuid; + } + public java.lang.String getSecondaryPciDeviceUuid() { + return this.secondaryPciDeviceUuid; + } + } From 50df70c4f06d1af4ef79f33885bc3ed9454893b2 Mon Sep 17 00:00:00 2001 From: "haoyu.ding" Date: Mon, 15 Dec 2025 19:34:50 +0800 Subject: [PATCH 30/48] [vm]: Modifying the vnc password does not require a restart APIImpact Resolves: ZSTAC-73270 Change-Id: I68727271736c6d687374776a64686a717a6f6d68 --- .../zstack/compute/vm/AbstractVmInstance.java | 1 + .../compute/vm/VmInstanceApiInterceptor.java | 21 ++++ .../org/zstack/compute/vm/VmInstanceBase.java | 111 ++++++++++++++++++ conf/serviceConfig/vmInstance.xml | 3 + .../vm/APIUpdateConsolePasswordEvent.java | 38 ++++++ ...UpdateConsolePasswordEventDoc_zh_cn.groovy | 32 +++++ .../vm/APIUpdateConsolePasswordMsg.java | 55 +++++++++ ...PIUpdateConsolePasswordMsgDoc_zh_cn.groovy | 67 +++++++++++ ...pdateVmConsolePasswordOnHypervisorMsg.java | 37 ++++++ ...ateVmConsolePasswordOnHypervisorReply.java | 6 + .../java/org/zstack/kvm/KVMAgentCommands.java | 11 ++ .../main/java/org/zstack/kvm/KVMConstant.java | 1 + .../src/main/java/org/zstack/kvm/KVMHost.java | 67 +++++++++++ .../sdk/UpdateConsolePasswordAction.java | 104 ++++++++++++++++ .../sdk/UpdateConsolePasswordResult.java | 14 +++ .../java/org/zstack/testlib/ApiHelper.groovy | 27 +++++ 16 files changed, 595 insertions(+) create mode 100644 header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordEvent.java create mode 100644 header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordEventDoc_zh_cn.groovy create mode 100644 header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordMsg.java create mode 100644 header/src/main/java/org/zstack/header/vm/APIUpdateConsolePasswordMsgDoc_zh_cn.groovy create mode 100644 header/src/main/java/org/zstack/header/vm/UpdateVmConsolePasswordOnHypervisorMsg.java create mode 100644 header/src/main/java/org/zstack/header/vm/UpdateVmConsolePasswordOnHypervisorReply.java create mode 100644 sdk/src/main/java/org/zstack/sdk/UpdateConsolePasswordAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/UpdateConsolePasswordResult.java diff --git a/compute/src/main/java/org/zstack/compute/vm/AbstractVmInstance.java b/compute/src/main/java/org/zstack/compute/vm/AbstractVmInstance.java index 100bdb2bc8..51c5ed925e 100755 --- a/compute/src/main/java/org/zstack/compute/vm/AbstractVmInstance.java +++ b/compute/src/main/java/org/zstack/compute/vm/AbstractVmInstance.java @@ -65,6 +65,7 @@ public abstract class AbstractVmInstance implements VmInstance { AttachIsoToVmInstanceMsg.class.getName(), APIDetachIsoFromVmInstanceMsg.class.getName(), APIGetVmConsoleAddressMsg.class.getName(), + APIUpdateConsolePasswordMsg.class.getName(), APIDeleteVmStaticIpMsg.class.getName(), APIPauseVmInstanceMsg.class.getName(), CreateTemplateFromRootVolumeSnapShotVmMsg.class.getName(), diff --git a/compute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.java b/compute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.java index fe1f33f104..e598163a5a 100755 --- a/compute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.java +++ b/compute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.java @@ -9,6 +9,8 @@ import org.zstack.compute.VmNicUtils; import org.zstack.core.cloudbus.CloudBus; import org.zstack.core.componentloader.PluginRegistry; +import org.zstack.core.config.GlobalConfigVO; +import org.zstack.core.config.GlobalConfigVO_; import org.zstack.core.db.*; import org.zstack.core.db.SimpleQuery.Op; import org.zstack.header.apimediator.ApiMessageInterceptionException; @@ -137,6 +139,8 @@ else if (msg instanceof APIAttachVmNicToVmMsg) { validate((APIUpdateVmInstanceMsg) msg); } else if (msg instanceof APISetVmConsolePasswordMsg) { validate((APISetVmConsolePasswordMsg) msg); + } else if (msg instanceof APIUpdateConsolePasswordMsg) { + validate((APIUpdateConsolePasswordMsg) msg); } else if (msg instanceof APIChangeInstanceOfferingMsg) { validate((APIChangeInstanceOfferingMsg) msg); } else if (msg instanceof APIMigrateVmMsg) { @@ -1533,6 +1537,23 @@ private void validate(APISetVmConsolePasswordMsg msg) { } } + private void validate(APIUpdateConsolePasswordMsg msg) { + VmInstanceVO vm = dbf.findByUuid(msg.getUuid(), VmInstanceVO.class); + if (vm.getState() != VmInstanceState.Running) { + throw new ApiMessageInterceptionException(operr( + "Cannot update console password for VM[uuid:%s] because it is not in 'Running' state. Current state is '%s'.", + vm.getUuid(), vm.getState() + )); + } + boolean hasPassword = VmSystemTags.CONSOLE_PASSWORD.hasTag(vm.getUuid()); + if (!hasPassword) { + throw new ApiMessageInterceptionException(operr( + "Cannot update the console password for VM[uuid:%s] because no console password is currently set. ", + vm.getUuid() + )); + } + } + private void validate(APIAttachL3NetworkToVmNicMsg msg) { throw new ApiMessageInterceptionException(argerr("can not call this api because it's Deprecated")); } diff --git a/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java b/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java index ed98aef34e..1c4834f937 100755 --- a/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java +++ b/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java @@ -3277,6 +3277,8 @@ protected void handleApiMessage(APIMessage msg) { handle((APISetVmBootVolumeMsg) msg); } else if (msg instanceof APISetVmConsolePasswordMsg) { handle((APISetVmConsolePasswordMsg) msg); + } else if (msg instanceof APIUpdateConsolePasswordMsg) { + handle((APIUpdateConsolePasswordMsg) msg); } else if (msg instanceof APISetVmSoundTypeMsg) { handle((APISetVmSoundTypeMsg) msg); } else if (msg instanceof APISetVmQxlMemoryMsg) { @@ -4197,6 +4199,115 @@ public void handle(Map data) { }).start(); } + private void handle(APIUpdateConsolePasswordMsg msg) { + thdf.chainSubmit(new ChainTask(msg) { + @Override + public String getSyncSignature() { + return syncThreadName; + } + + @Override + public String getName() { + return String.format("update-and-apply-console-password-for-vm-%s", msg.getVmInstanceUuid()); + } + + @Override + public void run(SyncTaskChain chain) { + final APIUpdateConsolePasswordEvent evt = new APIUpdateConsolePasswordEvent(msg.getId()); + + refreshVO(); + + ErrorCode error = validateOperationByState(msg, self.getState(), SysErrors.OPERATION_ERROR); + if (error != null) { + throw new OperationFailureException(error); + } + + if (self.getHostUuid() == null) { + throw new OperationFailureException(operr( + "cannot update console password of vm[uuid:%s], the vm is not running on any host", + self.getUuid() + )); + } + + + FlowChain fchain = FlowChainBuilder.newSimpleFlowChain(); + fchain.setName(getName()); + + fchain.then(new Flow() { + String __name__ = "persist-new-console-password-in-db"; + private String oldPassword; + + @Override + public void run(FlowTrigger trigger, Map data) { + oldPassword = Optional.ofNullable(VmSystemTags.CONSOLE_PASSWORD.getTag(self.getUuid())) + .map(tag -> VmSystemTags.CONSOLE_PASSWORD.getTokenByTag(tag, VmSystemTags.CONSOLE_PASSWORD_TOKEN)) + .orElse(null); + + SystemTagCreator creator = VmSystemTags.CONSOLE_PASSWORD.newSystemTagCreator(self.getUuid()); + creator.setTagByTokens(map(e(VmSystemTags.CONSOLE_PASSWORD_TOKEN, msg.getPassword()))); + creator.recreate = true; + creator.create(); + trigger.next(); + } + + @Override + public void rollback(FlowRollback trigger, Map data) { + if (oldPassword == null) { + VmSystemTags.CONSOLE_PASSWORD.delete(self.getUuid()); + } else { + SystemTagCreator creator = VmSystemTags.CONSOLE_PASSWORD.newSystemTagCreator(self.getUuid()); + creator.setTagByTokens(map(e(VmSystemTags.CONSOLE_PASSWORD_TOKEN, oldPassword))); + creator.recreate = true; + creator.create(); + } + trigger.rollback(); + } + }); + + fchain.then(new NoRollbackFlow() { + String __name__ = "apply-new-console-password-on-hypervisor"; + + @Override + public void run(FlowTrigger trigger, Map data) { + UpdateVmConsolePasswordOnHypervisorMsg umsg = new UpdateVmConsolePasswordOnHypervisorMsg(); + umsg.setVmInstanceUuid(self.getUuid()); + umsg.setHostUuid(self.getHostUuid()); + umsg.setPassword(msg.getPassword()); + + bus.makeTargetServiceIdByResourceUuid(umsg, HostConstant.SERVICE_ID, self.getHostUuid()); + + bus.send(umsg, new CloudBusCallBack(trigger) { + @Override + public void run(MessageReply reply) { + if (!reply.isSuccess()) { + trigger.fail(reply.getError()); + } else { + trigger.next(); + } + } + }); + } + }); + + fchain.done(new FlowDoneHandler(msg) { + @Override + public void handle(Map data) { + evt.setInventory(getSelfInventory()); + bus.publish(evt); + chain.next(); + } + }).error(new FlowErrorHandler(msg) { + @Override + public void handle(ErrorCode errCode, Map data) { + evt.setError(errCode); + bus.publish(evt); + chain.next(); + } + }).start(); + } + }); + } + private void handle(APISetVmSoundTypeMsg msg) { APISetVmSoundTypeEvent evt = new APISetVmSoundTypeEvent(msg.getId()); SystemTagCreator creator = VmSystemTags.SOUND_TYPE.newSystemTagCreator(self.getUuid()); 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/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/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java b/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java index 91e5d885bd..401059f60f 100755 --- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java +++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java @@ -992,6 +992,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; 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..21cac14968 100755 --- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMConstant.java +++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMConstant.java @@ -121,6 +121,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/KVMHost.java b/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java index ab8c29640f..122eeeeb32 100755 --- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java +++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java @@ -704,6 +704,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); } @@ -6893,4 +6895,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/sdk/src/main/java/org/zstack/sdk/UpdateConsolePasswordAction.java b/sdk/src/main/java/org/zstack/sdk/UpdateConsolePasswordAction.java new file mode 100644 index 0000000000..c3398dbbe0 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/UpdateConsolePasswordAction.java @@ -0,0 +1,104 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class UpdateConsolePasswordAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.UpdateConsolePasswordResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String uuid; + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String password; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.UpdateConsolePasswordResult value = res.getResult(org.zstack.sdk.UpdateConsolePasswordResult.class); + ret.value = value == null ? new org.zstack.sdk.UpdateConsolePasswordResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "PUT"; + info.path = "/vm-instances/{uuid}/actions"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "updateConsolePassword"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/UpdateConsolePasswordResult.java b/sdk/src/main/java/org/zstack/sdk/UpdateConsolePasswordResult.java new file mode 100644 index 0000000000..1462e8ae7d --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/UpdateConsolePasswordResult.java @@ -0,0 +1,14 @@ +package org.zstack.sdk; + +import org.zstack.sdk.VmInstanceInventory; + +public class UpdateConsolePasswordResult { + public VmInstanceInventory inventory; + public void setInventory(VmInstanceInventory inventory) { + this.inventory = inventory; + } + public VmInstanceInventory getInventory() { + return this.inventory; + } + +} diff --git a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy index 34cf02a9ff..1fb130443c 100644 --- a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy +++ b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy @@ -43035,6 +43035,33 @@ abstract class ApiHelper { } + def updateConsolePassword(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UpdateConsolePasswordAction.class) Closure c) { + def a = new org.zstack.sdk.UpdateConsolePasswordAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def updateConsoleProxyAgent(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UpdateConsoleProxyAgentAction.class) Closure c) { def a = new org.zstack.sdk.UpdateConsoleProxyAgentAction() a.sessionId = Test.currentEnvSpec?.session?.uuid From 6b6c758104e456abd7703ff19537dac486adee67 Mon Sep 17 00:00:00 2001 From: "shan.wu" Date: Mon, 13 Oct 2025 11:16:19 +0800 Subject: [PATCH 31/48] [storage-migration]: storage migration supports specifying volume provision strategy. storage migration supports specifying volume provision strategy. Resolves/Related: ZSTAC-77942 Change-Id: I767861677267636b677578636267746c62777479 --- plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java | 9 ++------- .../org/zstack/sdk/PrimaryStorageMigrateVmAction.java | 3 +++ .../zstack/sdk/PrimaryStorageMigrateVolumeAction.java | 3 +++ 3 files changed, 8 insertions(+), 7 deletions(-) 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..38086488ff 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); } } diff --git a/sdk/src/main/java/org/zstack/sdk/PrimaryStorageMigrateVmAction.java b/sdk/src/main/java/org/zstack/sdk/PrimaryStorageMigrateVmAction.java index 60e8edc102..49641300f2 100644 --- a/sdk/src/main/java/org/zstack/sdk/PrimaryStorageMigrateVmAction.java +++ b/sdk/src/main/java/org/zstack/sdk/PrimaryStorageMigrateVmAction.java @@ -52,6 +52,9 @@ public Result throwExceptionIfError() { @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public long bandwidth = 0L; + @Param(required = false, validValues = {"Specified","FollowVolume","FollowDestPrimaryStorage"}, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String volumeProvisioningStrategy = "FollowDestPrimaryStorage"; + @Param(required = false) public java.util.List systemTags; diff --git a/sdk/src/main/java/org/zstack/sdk/PrimaryStorageMigrateVolumeAction.java b/sdk/src/main/java/org/zstack/sdk/PrimaryStorageMigrateVolumeAction.java index ed88a0bd61..7ed53f5ebc 100644 --- a/sdk/src/main/java/org/zstack/sdk/PrimaryStorageMigrateVolumeAction.java +++ b/sdk/src/main/java/org/zstack/sdk/PrimaryStorageMigrateVolumeAction.java @@ -31,6 +31,9 @@ public Result throwExceptionIfError() { @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String dstPrimaryStorageUuid; + @Param(required = false, validValues = {"Specified","FollowVolume","FollowDestPrimaryStorage"}, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String volumeProvisioningStrategy = "FollowDestPrimaryStorage"; + @Param(required = false) public java.util.List systemTags; From 4baa9811223ccb62c099fa9b53d7f92e30eb6f35 Mon Sep 17 00:00:00 2001 From: shenjin Date: Tue, 16 Dec 2025 20:19:45 +0800 Subject: [PATCH 32/48] [conf]: add dependent devices support for PCI device group Add `dependentDevices` field to `PciDeviceVO` to store related device dependencies. Rename `getRelatedPciDeviceUuids` method to include dependent devices. Resolves: ZSTAC-79394 Change-Id: I6664697077636b7a77697261747a626f74706b71 (cherry picked from commit 6f679187a4e9e493cd12cc7b86ef4c7ac6deeae8) --- conf/db/upgrade/V5.5.0__schema.sql | 4 +++- sdk/src/main/java/org/zstack/sdk/PciDeviceInventory.java | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/conf/db/upgrade/V5.5.0__schema.sql b/conf/db/upgrade/V5.5.0__schema.sql index 802f0170ea..f6f376c572 100644 --- a/conf/db/upgrade/V5.5.0__schema.sql +++ b/conf/db/upgrade/V5.5.0__schema.sql @@ -1,2 +1,4 @@ CALL ADD_COLUMN('VmVfNicVO', 'secondaryPciDeviceUuid', 'VARCHAR(32)', 1, NULL); -ALTER TABLE `zstack`.`VmVfNicVO` ADD CONSTRAINT `fkVmVfNicVOSecondaryPciDeviceVO` FOREIGN KEY (`secondaryPciDeviceUuid`) REFERENCES `zstack`.`PciDeviceVO` (`uuid`) ON DELETE SET NULL; \ No newline at end of file +ALTER TABLE `zstack`.`VmVfNicVO` ADD CONSTRAINT `fkVmVfNicVOSecondaryPciDeviceVO` FOREIGN KEY (`secondaryPciDeviceUuid`) REFERENCES `zstack`.`PciDeviceVO` (`uuid`) ON DELETE SET NULL; + +CALL ADD_COLUMN('PciDeviceVO', 'dependentDevices', 'varchar(255)', 1, NULL); diff --git a/sdk/src/main/java/org/zstack/sdk/PciDeviceInventory.java b/sdk/src/main/java/org/zstack/sdk/PciDeviceInventory.java index 7dec375572..06e7e5885c 100644 --- a/sdk/src/main/java/org/zstack/sdk/PciDeviceInventory.java +++ b/sdk/src/main/java/org/zstack/sdk/PciDeviceInventory.java @@ -185,6 +185,14 @@ public java.lang.String getRev() { return this.rev; } + public java.lang.String dependentDevices; + public void setDependentDevices(java.lang.String dependentDevices) { + this.dependentDevices = dependentDevices; + } + public java.lang.String getDependentDevices() { + return this.dependentDevices; + } + public java.sql.Timestamp createDate; public void setCreateDate(java.sql.Timestamp createDate) { this.createDate = createDate; From e4da6d5a47b5bb8c80c1c5829fdeb147f825c9cf Mon Sep 17 00:00:00 2001 From: shenjin Date: Sun, 30 Nov 2025 12:24:47 +0800 Subject: [PATCH 33/48] [sdk]: support kunlunxin GPU support kunlunxin GPU, add GPU_Communication_Controller Resolves: ZSTAC-79110 Change-Id: I6277786e6e6973637566746c737364637676626a --- sdk/src/main/java/org/zstack/sdk/MdevDeviceType.java | 1 + sdk/src/main/java/org/zstack/sdk/PciDeviceType.java | 1 + 2 files changed, 2 insertions(+) diff --git a/sdk/src/main/java/org/zstack/sdk/MdevDeviceType.java b/sdk/src/main/java/org/zstack/sdk/MdevDeviceType.java index a2ff1befcc..cb58e93b76 100644 --- a/sdk/src/main/java/org/zstack/sdk/MdevDeviceType.java +++ b/sdk/src/main/java/org/zstack/sdk/MdevDeviceType.java @@ -6,4 +6,5 @@ public enum MdevDeviceType { GPU_Processing_Accelerators, GPU_Co_Processor, GPU_3D_Controller, + GPU_Communication_Controller, } diff --git a/sdk/src/main/java/org/zstack/sdk/PciDeviceType.java b/sdk/src/main/java/org/zstack/sdk/PciDeviceType.java index 2d6cc7a4ba..a81359354f 100644 --- a/sdk/src/main/java/org/zstack/sdk/PciDeviceType.java +++ b/sdk/src/main/java/org/zstack/sdk/PciDeviceType.java @@ -8,6 +8,7 @@ public enum PciDeviceType { GPU_3D_Controller, GPU_Processing_Accelerators, GPU_Co_Processor, + GPU_Communication_Controller, Ethernet_Controller, Audio_Controller, USB_Controller, From 1afe6f2d87cdf90811997079c71686c0dd8a6f88 Mon Sep 17 00:00:00 2001 From: "yaohua.wu" Date: Tue, 18 Nov 2025 18:24:38 +0800 Subject: [PATCH 34/48] [sdk]: support designating ps for slb instance Resolves: ZSTAC-79222 Change-Id: I726a716d61706e716c74656c727779637a6b6b64 --- .../main/java/org/zstack/sdk/CreateSlbInstanceAction.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sdk/src/main/java/org/zstack/sdk/CreateSlbInstanceAction.java b/sdk/src/main/java/org/zstack/sdk/CreateSlbInstanceAction.java index 7019e2c999..4be292428e 100644 --- a/sdk/src/main/java/org/zstack/sdk/CreateSlbInstanceAction.java +++ b/sdk/src/main/java/org/zstack/sdk/CreateSlbInstanceAction.java @@ -43,6 +43,12 @@ public Result throwExceptionIfError() { @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String hostUuid; + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String primaryStorageUuidForRootVolume; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.util.List rootVolumeSystemTags; + @Param(required = false) public java.lang.String resourceUuid; From 05817d1785321ab743ae866b678d55fa0d3a16c6 Mon Sep 17 00:00:00 2001 From: "shan.wu" Date: Tue, 16 Dec 2025 17:45:43 +0800 Subject: [PATCH 35/48] [vhost]:fix start vm failed 1.When the cluster where the vm is located has attached vhost primary storage, regardless of whether vhost volume is currently attached for vm, we will enable hugepage memory and set the memory access mode to shared. 2.Check hugepage and shared memory before attaching vhost volume to vm online. Resolves/Related: ZSTAC-80546 Change-Id: I74716b65706f6f717a6d626a62757265796c7875 --- .../org/zstack/compute/vm/VmGlobalConfig.java | 4 ++ .../zstack/vhost/kvm/KvmVhostNodeServer.java | 30 +++++++- .../expon/ExponPrimaryStorageCase.groovy | 69 ++++++++++++++++++- 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/compute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.java b/compute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.java index bd79900c13..b9b5cfa3ef 100755 --- a/compute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.java +++ b/compute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.java @@ -133,4 +133,8 @@ public class VmGlobalConfig { @GlobalConfigValidation(validValues = {"None", "AuthenticAMD"}) @BindResourceConfig(value = {VmInstanceVO.class}) public static GlobalConfig VM_CPUID_VENDOR = new GlobalConfig(CATEGORY, "vm.cpuid.vendor"); + + @GlobalConfigValidation(validValues = {"true", "false", "auto"}) + @GlobalConfigDef(defaultValue = "false", type = String.class, description = "generate config required for vhost primary storage") + public static GlobalConfig GENERATE_CONFIG_VHOST_REQUIRED = new GlobalConfig(CATEGORY, "generate.config.vhost.required"); } diff --git a/plugin/vhost/src/main/java/org/zstack/vhost/kvm/KvmVhostNodeServer.java b/plugin/vhost/src/main/java/org/zstack/vhost/kvm/KvmVhostNodeServer.java index 5b9cf5623e..fe4dd595e2 100644 --- a/plugin/vhost/src/main/java/org/zstack/vhost/kvm/KvmVhostNodeServer.java +++ b/plugin/vhost/src/main/java/org/zstack/vhost/kvm/KvmVhostNodeServer.java @@ -1,8 +1,10 @@ package org.zstack.vhost.kvm; +import javax.persistence.TypedQuery; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; +import org.zstack.compute.vm.VmGlobalConfig; import org.zstack.core.componentloader.PluginRegistry; +import org.zstack.core.db.DatabaseFacade; import org.zstack.header.Component; import org.zstack.header.errorcode.ErrorCode; import org.zstack.header.errorcode.OperationFailureException; @@ -15,6 +17,7 @@ import org.zstack.header.volume.VolumeProtocol; import org.zstack.header.volume.VolumeProtocolCapability; import org.zstack.kvm.*; +import org.zstack.resourceconfig.ResourceConfigFacade; import org.zstack.storage.addon.primary.ExternalPrimaryStorageFactory; import java.util.ArrayList; @@ -27,6 +30,10 @@ public class KvmVhostNodeServer implements Component, KVMStartVmExtensionPoint, KVMConvertVolumeExtensionPoint, KVMDetachVolumeExtensionPoint, KVMAttachVolumeExtensionPoint { @Autowired private ExternalPrimaryStorageFactory extPsFactory; + @Autowired + private DatabaseFacade dbf; + @Autowired + private ResourceConfigFacade rcf; private PluginRegistry pluginRgty; @@ -39,6 +46,21 @@ public class KvmVhostNodeServer implements Component, KVMStartVmExtensionPoint, capability.setSupportReadonly(false); } + private boolean needSupportVhostPrimaryStorage(String clusterUuid) { + String generateVhostConfig = VmGlobalConfig.GENERATE_CONFIG_VHOST_REQUIRED.value(String.class); + if (!"auto".equals(generateVhostConfig)) { + return Boolean.parseBoolean(generateVhostConfig); + } + String sql = "select count(ref) from PrimaryStorageClusterRefVO ref, PrimaryStorageOutputProtocolRefVO protoRef" + + " where ref.primaryStorageUuid = protoRef.primaryStorageUuid" + + " and ref.clusterUuid = :clusterUuid" + + " and protoRef.outputProtocol = :outputProtocol"; + TypedQuery q = dbf.getEntityManager().createQuery(sql, Long.class); + q.setParameter("clusterUuid", clusterUuid); + q.setParameter("outputProtocol", VolumeProtocol.Vhost.name()); + Long count = q.getSingleResult(); + return count != null && count > 0; + } @Override public void beforeStartVmOnKvm(KVMHostInventory host, VmInstanceSpec spec, KVMAgentCommands.StartVmCmd cmd) { @@ -54,13 +76,15 @@ public void beforeStartVmOnKvm(KVMHostInventory host, VmInstanceSpec spec, KVMAg } } - cmd.setDataVolumes(dtos); if (VolumeProtocol.Vhost.name().equals(spec.getDestRootVolume().getProtocol()) || - spec.getDestDataVolumes().stream().anyMatch(v -> VolumeProtocol.Vhost.name().equals(v.getProtocol()))) { + spec.getDestDataVolumes().stream().anyMatch(v -> VolumeProtocol.Vhost.name().equals(v.getProtocol())) || + needSupportVhostPrimaryStorage(host.getClusterUuid())) { cmd.setUseHugePage(true); cmd.setMemAccess("shared"); } + cmd.setDataVolumes(dtos); + // vhostuser disk not support readonly mode, so no iso. } diff --git a/test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/expon/ExponPrimaryStorageCase.groovy b/test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/expon/ExponPrimaryStorageCase.groovy index 192d189b81..0f1e52b24c 100644 --- a/test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/expon/ExponPrimaryStorageCase.groovy +++ b/test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/expon/ExponPrimaryStorageCase.groovy @@ -1,6 +1,8 @@ package org.zstack.test.integration.storage.primary.addon.expon import org.springframework.http.HttpEntity +import org.zstack.compute.cluster.ClusterGlobalConfig +import org.zstack.compute.vm.VmGlobalConfig import org.zstack.core.Platform import org.zstack.core.cloudbus.CloudBus import org.zstack.core.db.Q @@ -49,6 +51,7 @@ import org.zstack.utils.data.SizeUnit import org.zstack.utils.gson.JSONObjectUtil import static java.util.Arrays.asList +import static java.util.UUID.randomUUID import static org.zstack.expon.ExponIscsiHelper.iscsiExportTargetName import static org.zstack.expon.ExponNameHelper.getVolIdFromPath @@ -204,7 +207,7 @@ class ExponPrimaryStorageCase extends SubCase { reconnectPrimaryStorage { uuid = ps.uuid } - + testCreateVmWhenSpecifiedSblk() testDeletePs() } } @@ -713,6 +716,70 @@ class ExponPrimaryStorageCase extends SubCase { } } + void testCreateVmWhenSpecifiedSblk() { + def sblk = addSharedBlockGroupPrimaryStorage { + name = "sblk" + diskUuids = [randomUUID() as String] + zoneUuid = cluster.getZoneUuid() + } as PrimaryStorageInventory + + attachPrimaryStorageToCluster { + primaryStorageUuid = sblk.uuid + clusterUuid = cluster.getUuid() + } + + env.afterSimulator(KVMConstant.KVM_START_VM_PATH) { rsp, HttpEntity e -> + def cmd = JSONObjectUtil.toObject(e.body, KVMAgentCommands.StartVmCmd.class) + assert cmd.useHugePage + assert cmd.memAccess == "shared" + return rsp + } + + VmGlobalConfig.GENERATE_CONFIG_VHOST_REQUIRED.updateValue("auto") + + def vm1 = createVmInstance { + name = "vm" + instanceOfferingUuid = instanceOffering.uuid + rootDiskOfferingUuid = diskOffering.uuid + imageUuid = image.uuid + l3NetworkUuids = [l3.uuid] + primaryStorageUuidForRootVolume = sblk.uuid + } as VmInstanceInventory + + VmGlobalConfig.GENERATE_CONFIG_VHOST_REQUIRED.updateValue("true") + + def vm2 = createVmInstance { + name = "vm" + instanceOfferingUuid = instanceOffering.uuid + rootDiskOfferingUuid = diskOffering.uuid + imageUuid = image.uuid + l3NetworkUuids = [l3.uuid] + primaryStorageUuidForRootVolume = sblk.uuid + } as VmInstanceInventory + + detachPrimaryStorageFromCluster { + primaryStorageUuid = sblk.uuid + clusterUuid = cluster.getUuid() + } + + deletePrimaryStorage { + uuid = sblk.uuid + } + + VmGlobalConfig.GENERATE_CONFIG_VHOST_REQUIRED.updateValue("false") + def vm3 = createVmInstance { + name = "vm" + instanceOfferingUuid = instanceOffering.uuid + rootDiskOfferingUuid = diskOffering.uuid + imageUuid = image.uuid + l3NetworkUuids = [l3.uuid] + } as VmInstanceInventory + + deleteVm(vm1.uuid) + deleteVm(vm2.uuid) + deleteVm(vm3.uuid) + } + void testDeletePs() { assert MultiNodeSingleFlightImpl.getExecutor(ps.uuid) != null From 94456471e16508f7d6646b09b3006d5bd9aa3392 Mon Sep 17 00:00:00 2001 From: "yaohua.wu" Date: Tue, 18 Nov 2025 18:24:38 +0800 Subject: [PATCH 36/48] [sdk]: support designating ps for slb instance Resolves: ZSTAC-79222 Change-Id: I726a716d61706e716c74656c727779637a6b6b64 --- .../main/java/org/zstack/sdk/CreateSlbInstanceAction.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sdk/src/main/java/org/zstack/sdk/CreateSlbInstanceAction.java b/sdk/src/main/java/org/zstack/sdk/CreateSlbInstanceAction.java index 7019e2c999..4be292428e 100644 --- a/sdk/src/main/java/org/zstack/sdk/CreateSlbInstanceAction.java +++ b/sdk/src/main/java/org/zstack/sdk/CreateSlbInstanceAction.java @@ -43,6 +43,12 @@ public Result throwExceptionIfError() { @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String hostUuid; + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String primaryStorageUuidForRootVolume; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.util.List rootVolumeSystemTags; + @Param(required = false) public java.lang.String resourceUuid; From a56d7a6a515a6e9f6846e68762a3a0bde2c99784 Mon Sep 17 00:00:00 2001 From: J M Date: Fri, 14 Nov 2025 18:04:11 +0800 Subject: [PATCH 37/48] [storage]: external storage support multi pools add systemTag to pass required url. add ExternalPrimaryStorageSpaceVO to record pool capacity. reject no mds or no pools config DBImpact Resolves: ZSTAC-67556 Change-Id: I6f64687a75697362786d6c737473776e6d746663 --- conf/db/upgrade/V5.5.0__schema.sql | 63 +++ conf/persistence.xml | 1 + .../ExternalPrimaryStorage.xml | 8 + conf/springConfigXml/cbd.xml | 4 + .../header/message/NeedReplyMessage.java | 5 + .../header/storage/addon/StorageCapacity.java | 40 ++ .../ExternalPrimaryStorageSpaceInventory.java | 133 +++++ .../ExternalPrimaryStorageSpaceVO.java | 140 ++++++ .../ExternalPrimaryStorageSpaceVO_.java | 19 + .../primary/PrimaryStorageControllerSvc.java | 6 +- .../addon/primary/StorageCapabilities.java | 20 +- .../AllocatePrimaryStorageSpaceMsg.java | 4 + .../primary/PSCapacityExtensionPoint.java | 21 +- .../org/zstack/header/vm/VmInstanceSpec.java | 8 + .../src/main/java/org/zstack/cbd/Config.java | 28 -- .../org/zstack/cbd/kvm/KvmCbdNodeServer.java | 105 +++- .../ceph/primary/CephPrimaryStorageBase.java | 9 +- .../primary/CephPrimaryStorageFactory.java | 6 +- .../zstack/expon/ExponStorageController.java | 24 +- .../ExternalPrimaryStorageAllocator.java | 128 +++++ .../local/LocalStorageAllocatorFactory.java | 3 +- .../nfs/NfsDownloadImageToCacheJob.java | 2 +- .../zstack/vhost/kvm/KvmVhostNodeServer.java | 4 +- .../xinfini/XInfiniStorageController.java | 28 +- .../org/zstack/storage/zbs}/AddonInfo.java | 4 +- .../org/zstack/storage/zbs}/ClusterInfo.java | 2 +- .../java/org/zstack/storage/zbs/Config.java | 61 +++ .../zstack/storage/zbs}/LogicalPoolInfo.java | 2 +- .../org/zstack/storage/zbs/ZbsConstants.java | 3 +- .../org/zstack/storage/zbs/ZbsHelper.java | 31 +- .../org/zstack/storage/zbs/ZbsMdsBase.java | 1 - .../storage/zbs/ZbsPrimaryStorageMdsBase.java | 1 - .../storage/zbs/ZbsStorageController.java | 471 +++++++----------- .../BlockExternalPrimaryStorageBackend.java | 4 + .../BlockExternalPrimaryStorageFactory.java | 6 +- .../addon/primary/ExternalPrimaryStorage.java | 53 +- .../ExternalPrimaryStorageFactory.java | 99 +++- ...rnalPrimaryStorageSpaceCapacityHelper.java | 285 +++++++++++ .../ExternalPrimaryStorageSpaceHelper.java | 56 +++ .../ExternalPrimaryStorageSystemTags.java | 13 + .../storage/primary/ImageCacheUtil.java | 10 +- .../storage/primary/PrimaryStorageBase.java | 1 + .../primary/PrimaryStorageManagerImpl.java | 5 +- .../storage/snapshot/VolumeSnapshotBase.java | 2 + .../snapshot/VolumeSnapshotTreeBase.java | 18 +- .../org/zstack/storage/volume/VolumeBase.java | 2 + .../addon/zbs/ZbsPrimaryStorageCase.groovy | 105 +++- .../testlib/ExternalPrimaryStorageSpec.groovy | 25 +- 48 files changed, 1669 insertions(+), 400 deletions(-) create mode 100644 header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageSpaceInventory.java create mode 100644 header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageSpaceVO.java create mode 100644 header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageSpaceVO_.java delete mode 100644 plugin/cbd/src/main/java/org/zstack/cbd/Config.java create mode 100644 plugin/externalStorage/src/main/java/org/zstack/externalStorage/primary/ExternalPrimaryStorageAllocator.java rename plugin/{cbd/src/main/java/org/zstack/cbd => zbs/src/main/java/org/zstack/storage/zbs}/AddonInfo.java (93%) rename plugin/{cbd/src/main/java/org/zstack/cbd => zbs/src/main/java/org/zstack/storage/zbs}/ClusterInfo.java (92%) create mode 100644 plugin/zbs/src/main/java/org/zstack/storage/zbs/Config.java rename plugin/{cbd/src/main/java/org/zstack/cbd => zbs/src/main/java/org/zstack/storage/zbs}/LogicalPoolInfo.java (99%) create mode 100644 storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageSpaceCapacityHelper.java create mode 100644 storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageSpaceHelper.java create mode 100644 storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageSystemTags.java diff --git a/conf/db/upgrade/V5.5.0__schema.sql b/conf/db/upgrade/V5.5.0__schema.sql index f6f376c572..5d1587afdc 100644 --- a/conf/db/upgrade/V5.5.0__schema.sql +++ b/conf/db/upgrade/V5.5.0__schema.sql @@ -2,3 +2,66 @@ CALL ADD_COLUMN('VmVfNicVO', 'secondaryPciDeviceUuid', 'VARCHAR(32)', 1, NULL); ALTER TABLE `zstack`.`VmVfNicVO` ADD CONSTRAINT `fkVmVfNicVOSecondaryPciDeviceVO` FOREIGN KEY (`secondaryPciDeviceUuid`) REFERENCES `zstack`.`PciDeviceVO` (`uuid`) ON DELETE SET NULL; CALL ADD_COLUMN('PciDeviceVO', 'dependentDevices', 'varchar(255)', 1, NULL); + +CREATE TABLE IF NOT EXISTS `zstack`.`ExternalPrimaryStorageSpaceVO` +( + uuid VARCHAR(32) NOT NULL, + primaryStorageUuid VARCHAR(32), + locationUrl VARCHAR(255), + type VARCHAR(255), + name VARCHAR(255), + availableCapacity BIGINT, + totalCapacity BIGINT, + availablePhysicalCapacity BIGINT, + totalPhysicalCapacity BIGINT, + `lastOpDate` TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `createDate` TIMESTAMP, + PRIMARY KEY (`uuid`), + CONSTRAINT `fkExternalPrimaryStorageSpaceVOPrimaryStorageEO` FOREIGN KEY (`primaryStorageUuid`) REFERENCES `zstack`.`PrimaryStorageEO` (`uuid`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + +DROP PROCEDURE IF EXISTS UpdateVolumeInstallPathForZbs; + +DELIMITER $$ +CREATE PROCEDURE UpdateVolumeInstallPathForZbs() +BEGIN + DECLARE done INT DEFAULT FALSE; + DECLARE psUuid VARCHAR(32); + DECLARE cur CURSOR FOR + SELECT uuid FROM `zstack`.`ExternalPrimaryStorageVO` WHERE identity = 'zbs'; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; + + OPEN cur; + read_loop: LOOP + FETCH cur INTO psUuid; + IF done THEN + LEAVE read_loop; + END IF; + + UPDATE `zstack`.`VolumeEO` + SET installPath = CONCAT('zbs://', SUBSTRING_INDEX(SUBSTRING(installPath, 5), '/', -2)) + WHERE primaryStorageUuid = psUuid + AND installPath LIKE 'cbd:%/%/%'; + + UPDATE `zstack`.`VolumeSnapshotEO` + SET primaryStorageInstallPath = CONCAT('zbs://', SUBSTRING_INDEX(SUBSTRING(primaryStorageInstallPath, 5), '/', -2)) + WHERE primaryStorageUuid = psUuid + AND primaryStorageInstallPath LIKE 'cbd:%/%/%'; + + UPDATE `zstack`.`ImageCacheVO` + SET installUrl = CONCAT('zbs://', SUBSTRING_INDEX(SUBSTRING(installUrl, 5), '/', -2)) + WHERE primaryStorageUuid = psUuid + AND installUrl LIKE 'cbd:%/%/%'; + + UPDATE `zstack`.`ImageCacheShadowVO` + SET installUrl = CONCAT('zbs://', SUBSTRING_INDEX(SUBSTRING(installUrl, 5), '/', -2)) + WHERE primaryStorageUuid = psUuid + AND installUrl LIKE 'cbd:%/%/%'; + END LOOP; + CLOSE cur; +END $$ + +DELIMITER ; + +CALL UpdateVolumeInstallPathForZbs(); 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/springConfigXml/ExternalPrimaryStorage.xml b/conf/springConfigXml/ExternalPrimaryStorage.xml index 55450dca7b..60c3ed6115 100644 --- a/conf/springConfigXml/ExternalPrimaryStorage.xml +++ b/conf/springConfigXml/ExternalPrimaryStorage.xml @@ -25,6 +25,7 @@ + @@ -46,6 +47,13 @@ + + + + + + + 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/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/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/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/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/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/vm/VmInstanceSpec.java b/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java index 96da4293fa..c182acd19c 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; @@ -788,6 +789,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/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/KvmCbdNodeServer.java b/plugin/cbd/src/main/java/org/zstack/cbd/kvm/KvmCbdNodeServer.java index 006d726054..8c3e60e68f 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 @@ -15,34 +15,36 @@ import org.zstack.header.core.ReturnValueCompletion; import org.zstack.header.core.workflow.*; import org.zstack.header.errorcode.ErrorCode; +import org.zstack.header.errorcode.OperationFailureException; import org.zstack.header.host.HostConstant; 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 static org.zstack.core.Platform.argerr; import static org.zstack.core.Platform.operr; /** * @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 @@ -220,4 +222,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 6579e94139..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); @@ -5438,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(); } 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 2a3762f98f..2528ddeb27 100644 --- a/plugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java +++ b/plugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java @@ -885,6 +885,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(); @@ -1310,8 +1330,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/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/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 completion) { NfsPrimaryStorageBackend bkd = nfsFactory.getHypervisorBackend(nfsMgr.findHypervisorTypeByImageFormatAndPrimaryStorageUuid(image.getInventory().getFormat(), primaryStorage.getUuid())); - bkd.checkIsBitsExisting(primaryStorage, ImageCacheUtil.getImageCachePath(cvo.toInventory()), new ReturnValueCompletion(completion) { + bkd.checkIsBitsExisting(primaryStorage, ImageCacheUtil.getImageCachePath(cvo.getInstallUrl()), new ReturnValueCompletion(completion) { @Override public void success(Boolean returnValue) { if (returnValue) { diff --git a/plugin/vhost/src/main/java/org/zstack/vhost/kvm/KvmVhostNodeServer.java b/plugin/vhost/src/main/java/org/zstack/vhost/kvm/KvmVhostNodeServer.java index 5b9cf5623e..c533f114ef 100644 --- a/plugin/vhost/src/main/java/org/zstack/vhost/kvm/KvmVhostNodeServer.java +++ b/plugin/vhost/src/main/java/org/zstack/vhost/kvm/KvmVhostNodeServer.java @@ -130,10 +130,10 @@ public void beforeDetachVolume(KVMHostInventory host, VmInstanceInventory vm, Vo } @Override - public void afterDetachVolume(KVMHostInventory host, VmInstanceInventory vm, VolumeInventory volume, KVMAgentCommands.DetachDataVolumeCmd cmd) { } + 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) { } + public void detachVolumeFailed(KVMHostInventory host, VmInstanceInventory vm, VolumeInventory volume, KVMAgentCommands.DetachDataVolumeCmd cmd, ErrorCode err) {} @Override public void beforeAttachVolume(KVMHostInventory host, VmInstanceInventory vm, VolumeInventory volume, KVMAgentCommands.AttachDataVolumeCmd cmd, Map data) { diff --git a/plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java b/plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java index 267d55f403..92224dc1e4 100644 --- a/plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java +++ b/plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java @@ -558,6 +558,30 @@ private void reloadDbInfo() { config = StringUtils.isEmpty(self.getConfig()) ? new XInfiniConfig() : JSONObjectUtil.toObject(self.getConfig(), XInfiniConfig.class); } + // TODO: add more not found handling when support multi pool + @Override + public void getCapacity(List requiredUrls, ReturnValueCompletion comp) { + Map pools = refreshPoolCapacity() + .stream() + .filter(it -> config.getPoolIds().contains(it.getId())) + .collect(Collectors.toMap(XInfiniAddonInfo.Pool::getId, it -> it)); + + long total = pools.values().stream().mapToLong(XInfiniAddonInfo.Pool::getTotalCapacity).sum(); + long avail = pools.values().stream().mapToLong(XInfiniAddonInfo.Pool::getAvailableCapacity).sum(); + StorageCapacity cap = new StorageCapacity(); + cap.setAvailableCapacity(avail); + cap.setTotalCapacity(total); + + for (String url : requiredUrls) { + int poolId = getPoolIdFromPath(url); + XInfiniAddonInfo.Pool pool = pools.get(poolId); + if (pool != null) { + cap.putCapacity(url, pool.getAvailableCapacity(), pool.getTotalCapacity()); + } + } + comp.success(cap); + } + @Override public void reportCapacity(ReturnValueCompletion comp) { reloadDbInfo(); @@ -1009,8 +1033,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/cbd/src/main/java/org/zstack/cbd/AddonInfo.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/AddonInfo.java similarity index 93% rename from plugin/cbd/src/main/java/org/zstack/cbd/AddonInfo.java rename to plugin/zbs/src/main/java/org/zstack/storage/zbs/AddonInfo.java index c08f5c37c6..d711cf7da4 100644 --- a/plugin/cbd/src/main/java/org/zstack/cbd/AddonInfo.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/AddonInfo.java @@ -1,4 +1,6 @@ -package org.zstack.cbd; +package org.zstack.storage.zbs; + +import org.zstack.cbd.MdsInfo; import java.util.ArrayList; import java.util.List; diff --git a/plugin/cbd/src/main/java/org/zstack/cbd/ClusterInfo.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ClusterInfo.java similarity index 92% rename from plugin/cbd/src/main/java/org/zstack/cbd/ClusterInfo.java rename to plugin/zbs/src/main/java/org/zstack/storage/zbs/ClusterInfo.java index 6907f7e7e0..2f0e21d950 100644 --- a/plugin/cbd/src/main/java/org/zstack/cbd/ClusterInfo.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ClusterInfo.java @@ -1,4 +1,4 @@ -package org.zstack.cbd; +package org.zstack.storage.zbs; /** * @author Xingwei Yu diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/Config.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/Config.java new file mode 100644 index 0000000000..ca7d1c2406 --- /dev/null +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/Config.java @@ -0,0 +1,61 @@ +package org.zstack.storage.zbs; + + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Xingwei Yu + * @date 2024/4/2 11:13 + */ +public class Config { + public static class Pool { + public String logicalName; + public String aliasName; + + public Pool(String logicalName, String aliasName) { + this.logicalName = logicalName; + this.aliasName = aliasName; + } + + public Pool() {} + } + + private List mdsUrls; + private List pools; + private String logicalPoolName; + private transient List poolNames; + + 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; + } + + public void setPools(List pools) { + this.pools = pools; + poolNames = getPoolNames(); + } + + public List getPools() { + return pools; + } + + public List getPoolNames() { + if (poolNames == null) { + poolNames = pools == null ? Collections.emptyList() : pools.stream().map(pool -> pool.logicalName).collect(Collectors.toList()); + } + return poolNames; + } +} diff --git a/plugin/cbd/src/main/java/org/zstack/cbd/LogicalPoolInfo.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/LogicalPoolInfo.java similarity index 99% rename from plugin/cbd/src/main/java/org/zstack/cbd/LogicalPoolInfo.java rename to plugin/zbs/src/main/java/org/zstack/storage/zbs/LogicalPoolInfo.java index 8725ca0aaa..bc3a1a1dfa 100644 --- a/plugin/cbd/src/main/java/org/zstack/cbd/LogicalPoolInfo.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/LogicalPoolInfo.java @@ -1,4 +1,4 @@ -package org.zstack.cbd; +package org.zstack.storage.zbs; /** * @author Xingwei Yu diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsConstants.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsConstants.java index 8f547cfeb2..9d69ca21b4 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsConstants.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsConstants.java @@ -13,8 +13,7 @@ public interface ZbsConstants { String ZBS_PS_ALLOW_PORTS = "7763"; String ZBS_HEARTBEAT_VOLUME_NAME = "zbs_zstack_heartbeat"; long ZBS_HEARTBEAT_VOLUME_SIZE_IN_GIGABYTE = 1; - String ZBS_CBD_LUN_PATH_FORMAT = "cbd:%s/%s/%s"; - String ZBS_CBD_PREFIX_SCHEME = "cbd://"; + String SCHEME_PREFIX = "zbs://"; Integer PRIMARY_STORAGE_MDS_MAXIMUM_PING_FAILURE = 3; String VOLUME_PHYSICAL_BLOCK_SIZE = "4096"; String MEGABYTE_SUPPORTED_VERSION = "1.6.1"; diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsHelper.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsHelper.java index 7af981c519..3484be39c2 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsHelper.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsHelper.java @@ -7,25 +7,40 @@ import org.zstack.utils.VersionComparator; import org.zstack.utils.data.SizeUnit; +import java.util.function.Function; + /** * @author Xingwei Yu * @date 2024/4/9 17:50 */ public class ZbsHelper { - public static void configUrl(String psUuid) { - String psUrl = ZbsConstants.ZBS_CBD_PREFIX_SCHEME + psUuid; - if (!psUrl.equals(Q.New(PrimaryStorageVO.class).select(PrimaryStorageVO_.url).eq(PrimaryStorageVO_.uuid, psUuid).findValue())) { - SQL.New(PrimaryStorageVO.class).set(PrimaryStorageVO_.url, psUrl).eq(PrimaryStorageVO_.uuid, psUuid).update(); - } + // cbdPath: cbd:physical_pool/logical_pool/volume_id + public static String convertCbdPathToZbsPath(String cbdPath) { + return cbdPath.replaceFirst(".+?/", "zbs://"); + } + + public static String convertZbsPathToCbdPath(String zbsPath, Function physicalPoolGetter) { + String logicalPool = getPoolFromVolumePath(zbsPath); + String physicalPool = physicalPoolGetter.apply(logicalPool); + return zbsPath.replaceFirst("zbs://", String.format("cbd:%s/", physicalPool)); } public static String buildHeartbeatVolumePath(String logicalPool) { - return String.format("cbd:%s_physical/%s/%s", logicalPool, logicalPool, ZbsConstants.ZBS_HEARTBEAT_VOLUME_NAME); + return String.format("zbs://%s/%s", logicalPool, ZbsConstants.ZBS_HEARTBEAT_VOLUME_NAME); } - public static String buildVolumePath(String physicalPool, String logicalPool, String volId) { + public static String buildPoolPath(String logicalPool) { + return String.format("zbs://%s", logicalPool); + } + + public static String buildVolumePath(String logicalPool, String volId) { String base = volId.replace("-", ""); - return String.format(ZbsConstants.ZBS_CBD_LUN_PATH_FORMAT, physicalPool, logicalPool, base); + return String.format("zbs://%s/%s", logicalPool, base); + } + + public static String getPoolFromVolumePath(String path) { + String[] parts = path.replace("zbs://", "").split("/"); + return parts[0]; } public static String getVolumeFromSnapshotPath(String path) { diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsMdsBase.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsMdsBase.java index 1d4f286233..80d3f96e7d 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsMdsBase.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsMdsBase.java @@ -3,7 +3,6 @@ import org.springframework.beans.factory.annotation.Autowire; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Configurable; -import org.zstack.cbd.ClusterInfo; import org.zstack.cbd.MdsInfo; import org.zstack.core.db.DatabaseFacade; import org.zstack.header.core.Completion; diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsPrimaryStorageMdsBase.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsPrimaryStorageMdsBase.java index 81309d4364..25bbcec820 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsPrimaryStorageMdsBase.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsPrimaryStorageMdsBase.java @@ -1,7 +1,6 @@ package org.zstack.storage.zbs; import org.springframework.beans.factory.annotation.Autowired; -import org.zstack.cbd.ClusterInfo; import org.zstack.cbd.MdsInfo; import org.zstack.cbd.MdsStatus; import org.zstack.compute.host.HostGlobalConfig; diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java index 4b725d7d95..b41d219a02 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java @@ -19,13 +19,13 @@ import org.zstack.core.workflow.FlowChainBuilder; import org.zstack.core.workflow.ShareFlow; import org.zstack.header.HasThreadContext; +import org.zstack.header.apimediator.ApiMessageInterceptionException; import org.zstack.header.core.*; import org.zstack.header.core.workflow.*; import org.zstack.header.errorcode.ErrorCode; import org.zstack.header.errorcode.ErrorCodeList; import org.zstack.header.errorcode.OperationFailureException; import org.zstack.header.errorcode.SysErrors; -import org.zstack.header.exception.CloudRuntimeException; import org.zstack.header.host.HostAO_; import org.zstack.header.host.HostConstant; import org.zstack.header.host.HostInventory; @@ -56,9 +56,14 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.Stream; +import static org.zstack.core.Platform.argerr; import static org.zstack.core.Platform.operr; import static org.zstack.storage.zbs.ZbsHelper.*; @@ -83,6 +88,8 @@ public class ZbsStorageController implements PrimaryStorageControllerSvc, Primar private AddonInfo addonInfo; private Config config; + private Map physicalPoolByLogicalPool = new ConcurrentHashMap<>(); + public static final String DEPLOY_CLIENT_PATH = "/zbs/primarystorage/client/deploy"; public static final String GET_CAPACITY_PATH = "/zbs/primarystorage/capacity"; public static final String GET_FACTS_PATH = "/zbs/primarystorage/facts"; @@ -116,8 +123,10 @@ public class ZbsStorageController implements PrimaryStorageControllerSvc, Primar capabilities.setSnapshotCapability(scap); capabilities.setSupportShareableVolume(true); capabilities.setSupportCloneFromVolume(false); + capabilities.setSupportCloneFromAnotherSpace(false); capabilities.setSupportStorageQos(false); capabilities.setSupportLiveExpandVolume(false); + capabilities.setSupportMultiSpace(true); capabilities.setSupportedImageFormats(Collections.singletonList(ImageConstant.RAW_FORMAT_STRING)); capabilities.setDefaultIsoActiveProtocol(VolumeProtocol.CBD); capabilities.setDefaultImageExportProtocol(VolumeProtocol.NBD); @@ -126,6 +135,7 @@ public class ZbsStorageController implements PrimaryStorageControllerSvc, Primar @Override public void activate(BaseVolumeInfo v, HostInventory h, boolean shareable, ReturnValueCompletion comp) { if (VolumeProtocol.CBD.toString().equals(v.getProtocol())) { + comp.success(new CbdVolumeTo()); return; } @@ -151,7 +161,11 @@ public void blacklist(String installPath, String protocol, HostInventory h, Comp @Override public String getActivePath(BaseVolumeInfo v, HostInventory h, boolean shareable) { - return null; + if (VolumeProtocol.CBD.toString().equals(v.getProtocol())) { + return convertZbsPathToCbdPath(v.getInstallPath(), this::getPhysicalPoolName); + } else { + throw new OperationFailureException(operr("not supported protocol[%s] for active", v.getProtocol())); + } } @Override @@ -295,9 +309,10 @@ public synchronized void activateHeartbeatVolume(HostInventory h, ReturnValueCom @Override public void success(CreateVolumeRsp returnValue) { CbdHeartbeatVolumeTO to = new CbdHeartbeatVolumeTO(); - to.setInstallPath(returnValue.installPath); + String zbsPath = returnValue.installPath; + to.setInstallPath(ZbsHelper.convertZbsPathToCbdPath(zbsPath, ZbsStorageController.this::getPhysicalPoolName)); to.setHeartbeatRequiredSpace(SizeUnit.MEGABYTE.toByte(1)); - to.setCoveringPaths(Collections.singletonList(config.getLogicalPoolName())); + to.setCoveringPaths(config.getPoolNames()); comp.success(to); } @@ -319,10 +334,13 @@ public HeartbeatVolumeTO getHeartbeatVolumeActiveInfo(HostInventory h) { reloadDbInfo(); } + String zbsPath = buildHeartbeatVolumePath(config.getLogicalPoolName()); + String cbdPath = ZbsHelper.convertZbsPathToCbdPath(zbsPath, this::getPhysicalPoolName); + CbdHeartbeatVolumeTO to = new CbdHeartbeatVolumeTO(); - to.setInstallPath(buildHeartbeatVolumePath(config.getLogicalPoolName())); + to.setInstallPath(cbdPath); to.setHeartbeatRequiredSpace(SizeUnit.MEGABYTE.toByte(1)); - to.setCoveringPaths(Collections.singletonList(config.getLogicalPoolName())); + to.setCoveringPaths(config.getPoolNames()); return to; } @@ -486,7 +504,6 @@ public void done(ErrorCodeList errorCodeList) { done(new FlowDoneHandler(completion) { @Override public void handle(Map data) { - configUrl(self.getUuid()); addonInfo = newAddonInfo; completion.success(JSONObjectUtil.rehashObject(newAddonInfo, LinkedHashMap.class)); } @@ -546,12 +563,21 @@ public void done(ErrorCodeList errorCodeList) { }); } + @Override + public void getCapacity(List requiredUrls, ReturnValueCompletion comp) { + List poolNames = requiredUrls.stream().map(ZbsHelper::getPoolFromVolumePath).collect(Collectors.toList()); + getPoolCapacities(poolNames, comp); + } + @Override public void reportCapacity(ReturnValueCompletion comp) { reloadDbInfo(); + getPoolCapacities(config.getPoolNames(), comp); + } + private void getPoolCapacities(List poolNames, ReturnValueCompletion comp) { GetCapacityCmd cmd = new GetCapacityCmd(); - cmd.setLogicalPool(config.getLogicalPoolName()); + cmd.logicalPoolNames = poolNames; httpCall(GET_CAPACITY_PATH, cmd, GetCapacityRsp.class, new ReturnValueCompletion(comp) { @Override @@ -570,6 +596,9 @@ public void success(GetCapacityRsp returnValue) { cap.setTotalCapacity(total); cap.setAvailableCapacity(avail); cap.setHealthy(StorageHealthy.Ok); + for (LogicalPoolInfo pool : logicalPoolInfos) { + cap.putCapacity(buildPoolPath(pool.getLogicalPoolName()), pool.getCapacity() - pool.getUsedSize(), pool.getCapacity()); + } comp.success(cap); } @@ -582,14 +611,26 @@ public void fail(ErrorCode errorCode) { @Override public void reportHealthy(ReturnValueCompletion comp) { + // TODO: more accurate healthy report + getPoolCapacities(config.getPoolNames(), new ReturnValueCompletion(comp) { + @Override + public void success(StorageCapacity returnValue) { + comp.success(StorageHealthy.Ok); + } + @Override + public void fail(ErrorCode errorCode) { + comp.success(StorageHealthy.Unknown); + } + }); } @Override public void reportNodeHealthy(HostInventory host, ReturnValueCompletion comp) { CheckHostStorageConnectionCmd cmd = new CheckHostStorageConnectionCmd(); cmd.setHostUuid(host.getUuid()); - cmd.setPath(buildHeartbeatVolumePath(config.getLogicalPoolName())); + String zbsHbPath = buildHeartbeatVolumePath(config.getLogicalPoolName()); + cmd.setPath(ZbsHelper.convertZbsPathToCbdPath(zbsHbPath, this::getPhysicalPoolName)); KVMHostAsyncHttpCallMsg msg = new KVMHostAsyncHttpCallMsg(); msg.setCommand(cmd); @@ -625,26 +666,34 @@ public String allocateSpace(AllocateSpaceSpec aspec) { reloadDbInfo(); } - // TODO allocate pool - LogicalPoolInfo logicalPoolInfo = allocateFreePool(aspec.getSize()); + Predicate p = aspec.getRequiredUrl() == null ? null : it -> { + String pool = getPoolFromVolumePath(aspec.getRequiredUrl()); + return StringUtils.equals(pool, it.getLogicalPoolName()); + }; + + LogicalPoolInfo logicalPoolInfo = allocateFreePool(aspec.getSize(), p); if (logicalPoolInfo == null) { - throw new OperationFailureException(operr("no available logical pool with enough space[%d]", aspec.getSize())); + throw new OperationFailureException(operr("no available logical pool with enough space[%d] and required url: %s", + aspec.getSize(), aspec.getRequiredUrl())); } - return buildVolumePath("", config.getLogicalPoolName(), ""); + return buildPoolPath(logicalPoolInfo.getLogicalPoolName()); } - private LogicalPoolInfo allocateFreePool(long size) { + private LogicalPoolInfo allocateFreePool(long size, Predicate filter) { List logicalPoolInfos = getSelfPools(); - return logicalPoolInfos.stream().filter(it -> it.getCapacity() - it.getUsedSize() > size) - .max(Comparator.comparingLong(it -> it.getCapacity() - it.getUsedSize())) + Stream s = logicalPoolInfos.stream().filter(it -> it.getCapacity() - it.getUsedSize() > size); + if (filter != null) { + s = s.filter(filter); + } + + return s.max(Comparator.comparingLong(it -> it.getCapacity() - it.getUsedSize())) .orElse(null); } private List getSelfPools() { - String configLogicalPoolName = config.getLogicalPoolName(); List logicalPoolInfos = addonInfo.getLogicalPoolInfos(); - logicalPoolInfos.removeIf(it -> !configLogicalPoolName.equals(it.getLogicalPoolName())); + logicalPoolInfos.removeIf(it -> !config.getPoolNames().contains(it.getLogicalPoolName())); return logicalPoolInfos; } @@ -653,11 +702,13 @@ public void createVolume(CreateVolumeSpec v, ReturnValueCompletion reloadDbInfo(); CreateVolumeCmd cmd = new CreateVolumeCmd(); - cmd.setLogicalPool(config.getLogicalPoolName()); cmd.setVolume(v.getName()); cmd.setUnit(getSizeUnit(addonInfo.getClusterInfo().getVersion())); cmd.setSize(alignSizeTo(v.getSize(), cmd.getUnit())); cmd.setSkipIfExisting(true); + String poolName = v.getAllocatedUrl() != null ? getPoolFromVolumePath(v.getAllocatedUrl()) : + allocateFreePool(cmd.getSize(), null).getLogicalPoolName(); + cmd.setLogicalPool(poolName); httpCall(CREATE_VOLUME_PATH, cmd, CreateVolumeRsp.class, new ReturnValueCompletion(comp) { @Override @@ -740,7 +791,7 @@ public boolean skip(Map data) { @Override public void run(FlowTrigger trigger, Map data) { ExpandVolumeCmd cmd = new ExpandVolumeCmd(); - cmd.setPath(stats.getInstallPath()); + cmd.setPath(convertZbsPathToCbdPath(stats.getInstallPath(), ZbsStorageController.this::getPhysicalPoolName)); cmd.setUnit(getSizeUnit(addonInfo.getClusterInfo().getVersion())); cmd.setSize(alignSizeTo(dst.getSize(), cmd.getUnit())); @@ -850,9 +901,11 @@ public void fail(ErrorCode errorCode) { } @Override - public void batchStats(Collection installPath, ReturnValueCompletion> comp) { + public void batchStats(Collection installPaths, ReturnValueCompletion> comp) { BatchQueryVolumeCmd cmd = new BatchQueryVolumeCmd(); - cmd.setInstallPaths(installPath); + + cmd.setInstallPaths(installPaths.stream().map(it -> convertZbsPathToCbdPath(it, this::getPhysicalPoolName)) + .collect(Collectors.toList())); httpCall(BATCH_QUERY_VOLUME_PATH, cmd, BatchQueryVolumeRsp.class, new ReturnValueCompletion(comp) { @Override @@ -1053,23 +1106,42 @@ public void fail(ErrorCode errorCode) { } @Override - public void validateConfig(String config) { + public String validateConfig(String config) throws ApiMessageInterceptionException { Config old = JSONObjectUtil.toObject(self.getConfig(), Config.class); Config current = JSONObjectUtil.toObject(config, Config.class); + if (current.getLogicalPoolName() == null && !CollectionUtils.isEmpty(current.getPools())) { + if (current.getPoolNames().contains(old.getLogicalPoolName())) { + current.setLogicalPoolName(old.getLogicalPoolName()); + } else { + current.setLogicalPoolName(current.getPoolNames().get(0)); + } + } + + if (current.getLogicalPoolName() != null && CollectionUtils.isEmpty(current.getPools())) { + current.setPools(Arrays.asList(new Config.Pool(current.getLogicalPoolName(), null))); + } if (current.getLogicalPoolName().contains("/")) { - throw new CloudRuntimeException(String.format("invalid logical pool name[%s]", current.getLogicalPoolName())); + throw new ApiMessageInterceptionException(argerr("invalid logical pool name[%s]", current.getLogicalPoolName())); } - if (current.getMdsUrls().isEmpty()) { - throw new OperationFailureException(operr("ensure at least one MDS is configured")); + if (!current.getPoolNames().contains(current.getLogicalPoolName())) { + throw new ApiMessageInterceptionException(argerr("invalid pool name[%s]", current.getLogicalPoolName())); + } + + if (CollectionUtils.isEmpty(current.getPoolNames())) { + throw new ApiMessageInterceptionException(argerr("ensure at least one pool is configured")); + } + + if (CollectionUtils.isEmpty(current.getMdsUrls())) { + throw new ApiMessageInterceptionException(argerr("ensure at least one MDS is configured")); } List newMdsInfos = parseMdsInfos(current.getMdsUrls()); List duplicateMdsInfos = newMdsInfos.stream().collect(Collectors.groupingBy(MdsInfo::getAddr)) .values().stream().filter(addr -> addr.size() > 1).flatMap(List::stream).collect(Collectors.toList()); if (!duplicateMdsInfos.isEmpty()) { - throw new OperationFailureException(operr("do not allow to add duplicate MDS[%s]", + throw new ApiMessageInterceptionException(argerr("do not allow to add duplicate MDS[%s]", duplicateMdsInfos.stream().map(MdsInfo::getAddr).distinct().collect(Collectors.joining(", ")) )); } @@ -1083,6 +1155,7 @@ public void validateConfig(String config) { base.checkStorageHealth(); } } + return JSONObjectUtil.toJsonString(current); } @Override @@ -1125,6 +1198,8 @@ private void reloadDbInfo() { self = dbf.reload(self); addonInfo = StringUtils.isEmpty(self.getAddonInfo()) ? new AddonInfo() : JSONObjectUtil.toObject(self.getAddonInfo(), AddonInfo.class); config = StringUtils.isEmpty(self.getConfig()) ? new Config() : JSONObjectUtil.toObject(self.getConfig(), Config.class); + physicalPoolByLogicalPool = addonInfo.getLogicalPoolInfos().stream() + .collect(Collectors.toMap(LogicalPoolInfo::getLogicalPoolName, LogicalPoolInfo::getPhysicalPoolName) ); } private List parseMdsInfos(List mdsUrls) { @@ -1139,6 +1214,19 @@ private List parseMdsInfos(List mdsUrls) { }).collect(Collectors.toList()); } + protected String getPhysicalPoolName(String logicalPoolName) { + if (physicalPoolByLogicalPool.containsKey(logicalPoolName)) { + return physicalPoolByLogicalPool.get(logicalPoolName); + } else { + reloadDbInfo(); + String physicalPool = physicalPoolByLogicalPool.get(logicalPoolName); + if (physicalPool == null) { + throw new OperationFailureException(operr("cannot find physical pool for logical pool[%s]", logicalPoolName)); + } + return physicalPool; + } + } + protected T syncHttpCall(final String path, final AgentCommand cmd, final Class retClass) { return httpCall(path, cmd, retClass, null, 0, true); } @@ -1211,6 +1299,10 @@ HttpCaller setTargetMds(String mdsAddr) { } private void prepareCmd() { + if (cmd instanceof VolumeCommand) { + String cbdPath = convertZbsPathToCbdPath(((VolumeCommand) cmd).getPath(), ZbsStorageController.this::getPhysicalPoolName); + ((VolumeCommand) cmd).setPath(cbdPath); + } cmd.setUuid(self.getUuid()); } @@ -1268,6 +1360,13 @@ private void doCall() { ReturnValueCompletion completion = new ReturnValueCompletion(callback) { @Override public void success(T ret) { + if (ret instanceof VolumeResponse) { + String path = ((VolumeResponse) ret).installPath; + if (path != null && path.startsWith("cbd:")) { + ((VolumeResponse) ret).installPath = ZbsHelper.convertCbdPathToZbsPath(path); + } + } + callback.success(ret); } @@ -1309,64 +1408,10 @@ public void setSize(long size) { } } - public static class CopyRsp extends AgentResponse { - private String installPath; - private long size; - private long actualSize; - - public String getInstallPath() { - return installPath; - } - - public void setInstallPath(String installPath) { - this.installPath = installPath; - } - - public long getSize() { - return size; - } - - public void setSize(long size) { - this.size = size; - } - - public long getActualSize() { - return actualSize; - } - - public void setActualSize(long actualSize) { - this.actualSize = actualSize; - } + public static class CopyRsp extends VolumeResponse { } - public static class RollbackSnapshotRsp extends AgentResponse { - private String installPath; - private long size; - private long actualSize; - - public String getInstallPath() { - return installPath; - } - - public void setInstallPath(String installPath) { - this.installPath = installPath; - } - - public long getSize() { - return size; - } - - public void setSize(long size) { - this.size = size; - } - - public long getActualSize() { - return actualSize; - } - - public void setActualSize(long actualSize) { - this.actualSize = actualSize; - } + public static class RollbackSnapshotRsp extends VolumeResponse { } public static class DeleteSnapshotRsp extends AgentResponse { @@ -1440,97 +1485,16 @@ public void setPort(int port) { } } - public static class CloneVolumeRsp extends AgentResponse { - private long size; - private long actualSize; - private String installPath; - - public long getSize() { - return size; - } - - public void setSize(long size) { - this.size = size; - } - - public long getActualSize() { - return actualSize; - } - - public void setActualSize(long actualSize) { - this.actualSize = actualSize; - } - - public String getInstallPath() { - return installPath; - } - - public void setInstallPath(String installPath) { - this.installPath = installPath; - } + public static class CloneVolumeRsp extends VolumeResponse { } - public static class CreateSnapshotRsp extends AgentResponse { - private String installPath; - private long size; - private long actualSize; - - public String getInstallPath() { - return installPath; - } - - public void setInstallPath(String installPath) { - this.installPath = installPath; - } - - public long getSize() { - return size; - } - - public void setSize(long size) { - this.size = size; - } - - public long getActualSize() { - return actualSize; - } - - public void setActualSize(long actualSize) { - this.actualSize = actualSize; - } + public static class CreateSnapshotRsp extends VolumeResponse { } public static class DeleteVolumeRsp extends AgentResponse { } - public static class CreateVolumeRsp extends AgentResponse { - private String installPath; - private long size; - private long actualSize; - - public String getInstallPath() { - return installPath; - } - - public void setInstallPath(String installPath) { - this.installPath = installPath; - } - - public long getSize() { - return size; - } - - public void setSize(long size) { - this.size = size; - } - - public long getActualSize() { - return actualSize; - } - - public void setActualSize(long actualSize) { - this.actualSize = actualSize; - } + public static class CreateVolumeRsp extends VolumeResponse { } public static class GetCapacityRsp extends AgentResponse { @@ -1561,19 +1525,10 @@ public void setPath(String path) { } } - public static class CopyCmd extends AgentCommand implements HasThreadContext { - private String path; + public static class CopyCmd extends VolumeCommand implements HasThreadContext { private String dstVolume; private long dstSize; - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } - public String getDstVolume() { return dstVolume; } @@ -1591,52 +1546,16 @@ public void setDstSize(long dstSize) { } } - public static class RollbackSnapshotCmd extends AgentCommand { - private String path; - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } + public static class RollbackSnapshotCmd extends VolumeCommand { } - public static class DeleteSnapshotCmd extends AgentCommand { - private String path; - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } + public static class DeleteSnapshotCmd extends VolumeCommand { } - public static class QueryVolumeCmd extends AgentCommand { - private String path; - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } + public static class QueryVolumeCmd extends VolumeCommand { } - public static class FlattenVolumeCmd extends AgentCommand { - private String path; - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } + public static class FlattenVolumeCmd extends VolumeCommand { } public static class BatchQueryVolumeCmd extends AgentCommand { @@ -1672,18 +1591,9 @@ public void setPort(int port) { } } - public static class CbdToNbdCmd extends AgentCommand { - private String path; + public static class CbdToNbdCmd extends VolumeCommand { private String portRange; - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } - public String getPortRange() { return portRange; } @@ -1693,18 +1603,9 @@ public void setPortRange(String portRange) { } } - public static class CloneVolumeCmd extends AgentCommand { - private String path; + public static class CloneVolumeCmd extends VolumeCommand { private String dstVolume; - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } - public String getDstVolume() { return dstVolume; } @@ -1714,19 +1615,10 @@ public void setDstVolume(String dstVolume) { } } - public static class CreateSnapshotCmd extends AgentCommand { - private String path; + public static class CreateSnapshotCmd extends VolumeCommand { private String snapshot; private boolean skipOnExisting; - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } - public String getSnapshot() { return snapshot; } @@ -1744,18 +1636,9 @@ public void setSkipOnExisting(boolean skipOnExisting) { } } - public static class DeleteVolumeCmd extends AgentCommand { - private String path; + public static class DeleteVolumeCmd extends VolumeCommand { private boolean force; - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } - public boolean isForce() { return force; } @@ -1765,16 +1648,7 @@ public void setForce(boolean force) { } } - public static class GetVolumeClientsCmd extends AgentCommand { - private String path; - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } + public static class GetVolumeClientsCmd extends VolumeCommand { } public static class ClientInfo { @@ -1834,6 +1708,14 @@ public String getUnit() { public void setUnit(String unit) { this.unit = unit; } + + public long getSizeInBytes() { + if (unit != null && unit.toLowerCase().startsWith("m")) { + return SizeUnit.MEGABYTE.toByte(size); + } else { + return size; + } + } } public static class CreateVolumeCmd extends SizeCmd { @@ -1867,14 +1749,14 @@ public void setSkipIfExisting(boolean skipIfExisting) { } public static class GetCapacityCmd extends AgentCommand { - private String logicalPool; + private List logicalPoolNames; - public String getLogicalPool() { - return logicalPool; + public List getLogicalPoolNames() { + return logicalPoolNames; } - public void setLogicalPool(String logicalPool) { - this.logicalPool = logicalPool; + public void setLogicalPoolNames(List logicalPoolNames) { + this.logicalPoolNames = logicalPoolNames; } } @@ -1941,9 +1823,8 @@ public void setVersion(String version) { public static class GetFactsCmd extends AgentCommand { } - public static class CheckHostStorageConnectionCmd extends AgentCommand { + public static class CheckHostStorageConnectionCmd extends VolumeCommand { public String hostUuid; - private String path; public String getHostUuid() { return hostUuid; @@ -1952,17 +1833,51 @@ public String getHostUuid() { public void setHostUuid(String hostUuid) { this.hostUuid = hostUuid; } + } - public String getPath() { - return path; - } + public static class CheckHostStorageConnectionRsp extends AgentResponse { + } + + public static abstract class VolumeCommand extends AgentCommand { + protected String path; public void setPath(String path) { this.path = path; } + + public String getPath() { + return path; + } } - public static class CheckHostStorageConnectionRsp extends AgentResponse { + public static abstract class VolumeResponse extends AgentResponse { + protected String installPath; + protected long size; + protected long actualSize; + + public void setInstallPath(String installPath) { + this.installPath = installPath; + } + + public String getInstallPath() { + return installPath; + } + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + public long getActualSize() { + return actualSize; + } + + public void setActualSize(long actualSize) { + this.actualSize = actualSize; + } } public static class UpdateHostDependencyCmd extends AgentCommand { diff --git a/storage/src/main/java/org/zstack/storage/addon/primary/BlockExternalPrimaryStorageBackend.java b/storage/src/main/java/org/zstack/storage/addon/primary/BlockExternalPrimaryStorageBackend.java index 4641315ed6..dc2cfa760b 100644 --- a/storage/src/main/java/org/zstack/storage/addon/primary/BlockExternalPrimaryStorageBackend.java +++ b/storage/src/main/java/org/zstack/storage/addon/primary/BlockExternalPrimaryStorageBackend.java @@ -3,6 +3,10 @@ import org.zstack.header.storage.primary.*; import org.zstack.header.volume.block.GetAccessPathMsg; +/** + * do not match external primary storage design. + */ +@Deprecated public interface BlockExternalPrimaryStorageBackend { String getType(); diff --git a/storage/src/main/java/org/zstack/storage/addon/primary/BlockExternalPrimaryStorageFactory.java b/storage/src/main/java/org/zstack/storage/addon/primary/BlockExternalPrimaryStorageFactory.java index 2c561cc03a..7c1b5839ef 100644 --- a/storage/src/main/java/org/zstack/storage/addon/primary/BlockExternalPrimaryStorageFactory.java +++ b/storage/src/main/java/org/zstack/storage/addon/primary/BlockExternalPrimaryStorageFactory.java @@ -1,11 +1,13 @@ package org.zstack.storage.addon.primary; -import org.zstack.header.host.HostInventory; -import org.zstack.header.storage.addon.primary.BaseVolumeInfo; import org.zstack.header.storage.primary.PrimaryStorageVO; import java.util.Map; +/** + * do not match external primary storage design. + */ +@Deprecated public interface BlockExternalPrimaryStorageFactory { String getType(); diff --git a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java index 79332acdc8..18fc2af1f1 100644 --- a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java +++ b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java @@ -183,8 +183,8 @@ private void handle(APIUpdateExternalPrimaryStorageMsg msg) { } boolean needReconnect = false; if (msg.getConfig() != null) { - controller.validateConfig(msg.getConfig()); - externalVO.setConfig(msg.getConfig()); + String config = controller.validateConfig(msg.getConfig()); + externalVO.setConfig(config); needReconnect = true; } externalVO = dbf.updateAndRefresh(externalVO); @@ -336,7 +336,7 @@ public void setup() { @Override public void run(final FlowTrigger trigger, Map data) { - downloadImageCache(msg.getTemplateSpec().getInventory(), new ReturnValueCompletion(trigger) { + downloadImageCache(msg.getTemplateSpec().getInventory(), spec.getAllocatedUrl(), new ReturnValueCompletion(trigger) { @Override public void success(ImageCacheInventory returnValue) { pathInCache = ImageCacheUtil.getImageCachePath(returnValue); @@ -1156,7 +1156,7 @@ public void fail(ErrorCode errorCode) { }); } - private void downloadImageCache(ImageInventory image, ReturnValueCompletion completion) { + private void downloadImageCache(ImageInventory image, String allocatedUrl, ReturnValueCompletion completion) { thdf.chainSubmit(new ChainTask(completion) { @Override public String getSyncSignature() { @@ -1165,7 +1165,7 @@ public String getSyncSignature() { @Override public void run(SyncTaskChain chain) { - doDownloadImageCache(image, new ReturnValueCompletion(chain) { + doDownloadImageCache(image, allocatedUrl, new ReturnValueCompletion(chain) { @Override public void success(ImageCacheInventory returnValue) { completion.success(returnValue); @@ -1187,19 +1187,24 @@ public String getName() { }); } - private void doDownloadImageCache(ImageInventory image, ReturnValueCompletion completion) { + private void doDownloadImageCache(ImageInventory image, String allocatedUrl, ReturnValueCompletion completion) { CreateVolumeSpec spec = new CreateVolumeSpec(); spec.setUuid(image.getUuid()); spec.setName(buildImageName(image.getUuid())); + spec.setAllocatedUrl(allocatedUrl); - ImageCacheVO cache = Q.New(ImageCacheVO.class) + List caches = Q.New(ImageCacheVO.class) .eq(ImageCacheVO_.primaryStorageUuid, self.getUuid()) .eq(ImageCacheVO_.imageUuid, image.getUuid()) - .find(); - if (cache != null) { - // TODO check exists in ps - completion.success(ImageCacheInventory.valueOf(cache)); - return; + .list(); + + for (ImageCacheVO cache : caches) { + ImageCacheInventory inv = cache.toInventory(); + // TODO: suppose that path always starts with allocatedUrl + if (allocatedUrl != null && ImageCacheUtil.getImageCachePath(inv).startsWith(allocatedUrl)) { + completion.success(inv); + return; + } } downloadImageTo(image, spec, ImageCacheVO.class.getSimpleName(), new ReturnValueCompletion(completion) { @@ -1429,6 +1434,7 @@ protected void handle(GetInstallPathForDataVolumeDownloadMsg msg) { AllocateSpaceSpec aspec = new AllocateSpaceSpec(); aspec.setSize(msg.getImage().getSize()); aspec.setPurpose(PrimaryStorageAllocationPurpose.CreateDataVolume); + aspec.setRequiredUrl(msg.getAllocatedInstallUrl()); String installPath = controller.allocateSpace(aspec); reply.setInstallPath(installPath); @@ -1567,6 +1573,8 @@ protected void handle(DeleteVolumeOnPrimaryStorageMsg msg) { trashVolume(msg.getVolume().getInstallPath(), msg.getVolume().getProtocol(), force, new Completion(msg) { @Override public void success() { + ExternalPrimaryStorageSpaceCapacityHelper helper = new ExternalPrimaryStorageSpaceCapacityHelper(self.getUuid(), controller.getIdentity()); + helper.releaseAvailableCapWithRatio(msg.getVolume().getInstallPath(), msg.getVolume().getSize()); bus.reply(msg, reply); } @@ -1617,7 +1625,12 @@ public void fail(ErrorCode errorCode) { @Override protected void handle(DownloadIsoToPrimaryStorageMsg msg) { DownloadIsoToPrimaryStorageReply reply = new DownloadIsoToPrimaryStorageReply(); - downloadImageCache(msg.getIsoSpec().getInventory(), new ReturnValueCompletion(msg) { + String urlTag = msg.getSystemTag(ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL::isMatch); + String allocatedUrl = urlTag == null ? null : + ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL.getTokenByTag(urlTag, + ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL_TOKEN); + + downloadImageCache(msg.getIsoSpec().getInventory(), allocatedUrl, new ReturnValueCompletion(msg) { @Override public void success(ImageCacheInventory cache) { String isoProtocol = controller.reportCapabilities().getDefaultIsoActiveProtocol() != null @@ -1774,6 +1787,8 @@ protected void handle(DeleteSnapshotOnPrimaryStorageMsg msg) { controller.deleteSnapshot(msg.getSnapshot().getPrimaryStorageInstallPath(), new Completion(msg) { @Override public void success() { + ExternalPrimaryStorageSpaceCapacityHelper helper = new ExternalPrimaryStorageSpaceCapacityHelper(self.getUuid(), controller.getIdentity()); + helper.releaseAvailableCapacity(msg.getSnapshot().getPrimaryStorageInstallPath(), msg.getSnapshot().getSize()); bus.reply(msg, reply); } @@ -1828,7 +1843,7 @@ public void run(final FlowTrigger trigger, Map data) { } ImageInventory image = ImageInventory.valueOf(ivo); - downloadImageCache(image, new ReturnValueCompletion(trigger) { + downloadImageCache(image, msg.getAllocatedInstallUrl(), new ReturnValueCompletion(trigger) { @Override public void success(ImageCacheInventory returnValue) { installUrl = returnValue.getInstallUrl(); @@ -1964,15 +1979,19 @@ protected void handle(CheckVolumeSnapshotOperationOnPrimaryStorageMsg msg) { @Override protected void connectHook(ConnectParam param, Completion completion) { - controller.validateConfig(externalVO.getConfig()); - controller.connect(externalVO.getConfig(), self.getUrl(), new ReturnValueCompletion(completion) { + String config = controller.validateConfig(externalVO.getConfig()); + controller.connect(config, self.getUrl(), new ReturnValueCompletion(completion) { @Override public void success(LinkedHashMap addonInfo) { if (param.isNewAdded()) { controller.onFirstAdditionConfigure(new NopeCompletion()); } + SQL.New(ExternalPrimaryStorageVO.class).eq(ExternalPrimaryStorageVO_.uuid, self.getUuid()) .set(ExternalPrimaryStorageVO_.addonInfo, JSONObjectUtil.toJsonString(addonInfo)) + .set(ExternalPrimaryStorageVO_.config, config) + .set(ExternalPrimaryStorageVO_.url, StringUtils.isEmpty(self.getUrl()) ? + externalVO.getIdentity() + "://" + self.getUuid() : self.getUrl()) .update(); controller.setTrashExpireTime(PrimaryStorageGlobalConfig.TRASH_EXPIRATION_TIME.value(Integer.class), new NopeCompletion()); pingHook(completion); @@ -2031,6 +2050,8 @@ public void success(StorageCapacity capacity) { return cap; }); + + new ExternalPrimaryStorageSpaceCapacityHelper(externalVO).updateStorageSpace(capacity); trigger.next(); } else { trigger.fail(operr("storage is not healthy:%s", capacity.getHealthy().toString())); diff --git a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageFactory.java b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageFactory.java index a8e00d3a0a..8e715f6a6f 100644 --- a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageFactory.java +++ b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageFactory.java @@ -2,6 +2,8 @@ import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; import org.zstack.core.Platform; import org.zstack.core.asyncbatch.While; import org.zstack.core.cloudbus.CloudBus; @@ -43,6 +45,7 @@ import org.zstack.header.volume.VolumeDeletionPolicyManager; import org.zstack.header.volume.VolumeInventory; import org.zstack.header.volume.VolumeVO; +import org.zstack.header.volume.VolumeVO_; import org.zstack.header.volume.block.BlockVolumeVO; import org.zstack.storage.addon.backup.ExternalBackupStorageFactory; import org.zstack.storage.primary.PrimaryStorageFeatureAllocatorExtensionPoint; @@ -65,7 +68,8 @@ public class ExternalPrimaryStorageFactory implements PrimaryStorageFactory, Com VmAttachVolumeExtensionPoint, VmDetachVolumeExtensionPoint, BeforeTakeLiveSnapshotsOnVolumes, CreateTemplateFromVolumeSnapshotExtensionPoint, MarkRootVolumeAsSnapshotExtension, VmInstanceMigrateExtensionPoint, ManagementNodeChangeListener, PrimaryStorageFeatureAllocatorExtensionPoint, HostResizeVolumeExtensionPoint, - VolumeSnapshotAfterDeleteExtensionPoint, ChangeVolumeProcessingMethodExtensionPoint { + VolumeSnapshotAfterDeleteExtensionPoint, ChangeVolumeProcessingMethodExtensionPoint, + RecalculatePrimaryStorageCapacityExtensionPoint { private static final CLogger logger = Utils.getLogger(ExternalBackupStorageFactory.class); public static PrimaryStorageType type = new PrimaryStorageType(PrimaryStorageConstant.EXTERNAL_PRIMARY_STORAGE_TYPE); @@ -173,38 +177,87 @@ public boolean stop() { return false; } + private String getRequiredUrl(ExternalPrimaryStorageSpaceCapacityHelper helper, AllocatePrimaryStorageSpaceMsg msg) { + if (msg.getRequiredInstallUri() != null) { + String url = msg.getRequiredInstallUri(); + if (!url.startsWith("volume://")) { + return url; + } + + String volUuid = url.substring("volume://".length()); + String volumePath = Q.New(VolumeVO.class).eq(VolumeVO_.uuid, volUuid).select(VolumeVO_.installPath).findValue(); + if (volumePath == null) { + throw new OperationFailureException( + Platform.operr("cannot find volume[uuid:%s] install path", volUuid) + ); + } + + return helper.getLocationSpaceUrl(volumePath); + } + + String requiredSystag = msg.getSystemTag(ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL::isMatch); + if (requiredSystag != null) { + return ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL.getTokenByTag(requiredSystag, + ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL_TOKEN); + } + + return null; + } + @Override - public String buildAllocatedInstallUrl(AllocatePrimaryStorageSpaceMsg msg, PrimaryStorageInventory psInv) { + public String allocateSpaceDryRun(AllocatePrimaryStorageSpaceMsg msg, PrimaryStorageInventory psInv) { PrimaryStorageControllerSvc controller = controllers.get(psInv.getUuid()); if (controller == null) { return psInv.getUrl(); } - AllocateSpaceSpec aspec = new AllocateSpaceSpec(); - aspec.setDryRun(true); - aspec.setSize(msg.getSize()); - aspec.setRequiredUrl(msg.getRequiredInstallUri()); - return controller.allocateSpace(aspec); + ExternalPrimaryStorageSpaceCapacityHelper helper = new ExternalPrimaryStorageSpaceCapacityHelper(psInv.getUuid(), controller.getIdentity()); + String requiredUrl = getRequiredUrl(helper, msg); + + // TODO: remove it + if (!controller.reportCapabilities().isSupportMultiSpace()) { + AllocateSpaceSpec aspec = new AllocateSpaceSpec(); + aspec.setDryRun(true); + aspec.setSize(msg.getSize()); + aspec.setRequiredUrl(requiredUrl); + return controller.allocateSpace(aspec); + } + + if (requiredUrl != null) { + if (msg.isForce() || helper.checkVirtualSizeByRatio(requiredUrl, msg.getSize())) { + return requiredUrl; + } else { + return null; + } + } + + // return max available capacity space + return helper.findMostSuitableSpace(msg.getSize(), Comparator.comparingLong(ExternalPrimaryStorageSpaceVO::getAvailableCapacity).reversed()); } @Override + @Transactional(propagation = Propagation.MANDATORY) public long reserveCapacity(AllocatePrimaryStorageSpaceMsg msg, String allocatedInstallUrl, long size, String psUuid) { PrimaryStorageControllerSvc controller = controllers.get(psUuid); - if (controller == null) { + if (controller == null || !controller.reportCapabilities().isSupportMultiSpace()) { return size; } - AllocateSpaceSpec aspec = new AllocateSpaceSpec(); - aspec.setDryRun(false); - aspec.setSize(msg.getSize()); - aspec.setRequiredUrl(msg.getRequiredInstallUri()); - controller.allocateSpace(aspec); + ExternalPrimaryStorageSpaceCapacityHelper helper = new ExternalPrimaryStorageSpaceCapacityHelper(psUuid, controller.getIdentity()); + helper.reserveAvailableCapacity(allocatedInstallUrl, size); return size; } @Override + @Transactional(propagation = Propagation.MANDATORY) public void releaseCapacity(String allocatedInstallUrl, long size, String psUuid) { + PrimaryStorageControllerSvc controller = controllers.get(psUuid); + if (controller == null || !controller.reportCapabilities().isSupportMultiSpace()) { + return; + } + ExternalPrimaryStorageSpaceCapacityHelper helper = new ExternalPrimaryStorageSpaceCapacityHelper(psUuid, controller.getIdentity()); + helper.releaseAvailableCapacity(allocatedInstallUrl, size); } @Override @@ -274,6 +327,10 @@ public void validateStorageProtocol(String protocol) { } } + public List getAllControllerSvcs() { + return new ArrayList<>(controllers.values()); + } + public PrimaryStorageControllerSvc getControllerSvc(String primaryStorageUuid) { return controllers.get(primaryStorageUuid); } @@ -1076,4 +1133,20 @@ public VolumeDeletionPolicyManager.VolumeDeletionPolicy getTransientVolumeDeleti } return VolumeDeletionPolicyManager.VolumeDeletionPolicy.DBOnly; } + + public String getPrimaryStorageTypeForRecalculateCapacityExtensionPoint() { + return type.toString(); + } + + @Override + public void afterRecalculatePrimaryStorageCapacity(RecalculatePrimaryStorageCapacityStruct struct) { + PrimaryStorageControllerSvc controller = controllers.get(struct.getPrimaryStorageUuid()); + if (controller == null || !controller.reportCapabilities().isSupportMultiSpace()) { + return; + } + new ExternalPrimaryStorageSpaceCapacityHelper(struct.getPrimaryStorageUuid(), controller.getIdentity()).recalculateAvailableCapacity(); + } + + @Override + public void beforeRecalculatePrimaryStorageCapacity(RecalculatePrimaryStorageCapacityStruct struct) {} } diff --git a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageSpaceCapacityHelper.java b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageSpaceCapacityHelper.java new file mode 100644 index 0000000000..9fa5f2269b --- /dev/null +++ b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageSpaceCapacityHelper.java @@ -0,0 +1,285 @@ +package org.zstack.storage.addon.primary; + +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowire; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Configurable; +import org.springframework.transaction.annotation.Transactional; +import org.zstack.core.Platform; +import org.zstack.core.db.DatabaseFacade; +import org.zstack.core.db.DeadlockAutoRestart; +import org.zstack.core.db.Q; +import org.zstack.core.db.SQL; +import org.zstack.header.errorcode.OperationFailureException; +import org.zstack.header.storage.addon.StorageCapacity; +import org.zstack.header.storage.addon.primary.ExternalPrimaryStorageSpaceVO; +import org.zstack.header.storage.addon.primary.ExternalPrimaryStorageSpaceVO_; +import org.zstack.header.storage.addon.primary.ExternalPrimaryStorageVO; +import org.zstack.header.storage.primary.ImageCacheVO; +import org.zstack.header.storage.primary.ImageCacheVO_; +import org.zstack.header.storage.primary.PrimaryStorageOverProvisioningManager; +import org.zstack.header.storage.snapshot.VolumeSnapshotVO; +import org.zstack.header.storage.snapshot.VolumeSnapshotVO_; +import org.zstack.header.volume.VolumeVO; +import org.zstack.header.volume.VolumeVO_; +import org.zstack.storage.primary.PrimaryStorageCapacityChecker; +import org.zstack.utils.Utils; +import org.zstack.utils.logging.CLogger; +import org.zstack.utils.stopwatch.StopWatch; + +import java.util.*; +import java.util.stream.Collectors; + +import static java.util.Arrays.asList; +import static org.zstack.core.Platform.operr; + + +@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE) +public class ExternalPrimaryStorageSpaceCapacityHelper extends ExternalPrimaryStorageSpaceHelper { + @Autowired + protected PrimaryStorageOverProvisioningManager ratioMgr; + @Autowired + protected ExternalPrimaryStorageFactory extFactory; + @Autowired + protected DatabaseFacade dbf; + + + private static final CLogger logger = Utils.getLogger(ExternalPrimaryStorageSpaceCapacityHelper.class); + + private String primaryStorageUuid; + private String spaceName; + private Map storageSpacesByUrl; + + public ExternalPrimaryStorageSpaceCapacityHelper(ExternalPrimaryStorageVO ps) { + super(ps); + this.primaryStorageUuid = ps.getUuid(); + this.spaceName = ps.getIdentity(); + } + + public ExternalPrimaryStorageSpaceCapacityHelper(String psUuid, String identity) { + super(psUuid, identity); + this.primaryStorageUuid = psUuid; + spaceName = identity; + } + + protected void updateStorageSpace(StorageCapacity cap) { + if (cap.getCapacitiesByLocationUrl() == null || cap.getCapacitiesByLocationUrl().isEmpty()) { + return; + } + + List beforeSpaces = Q.New(ExternalPrimaryStorageSpaceVO.class) + .eq(ExternalPrimaryStorageSpaceVO_.primaryStorageUuid, primaryStorageUuid) + .list(); + + Map beforeSpacesByUrl = beforeSpaces.stream() + .collect(Collectors.toMap(ExternalPrimaryStorageSpaceVO::getLocationUrl, it -> it)); + List toPersistSpaces = new ArrayList<>(); + List toRemoveSpaces = new ArrayList<>(); + + for (Map.Entry e : cap.getCapacitiesByLocationUrl().entrySet()) { + String locationUrl = e.getKey(); + StorageCapacity.Capacity capacity = e.getValue(); + ExternalPrimaryStorageSpaceVO spaceVO = beforeSpacesByUrl.get(locationUrl); + if (spaceVO == null) { + spaceVO = new ExternalPrimaryStorageSpaceVO(); + spaceVO.setUuid(Platform.getUuidFromBytes((primaryStorageUuid + locationUrl).getBytes())); + spaceVO.setPrimaryStorageUuid(primaryStorageUuid); + spaceVO.setLocationUrl(locationUrl.replaceAll("/$", "")); + spaceVO.setTotalPhysicalCapacity(capacity.total); + spaceVO.setAvailablePhysicalCapacity(capacity.available); + spaceVO.setTotalCapacity(capacity.total); + spaceVO.setAvailableCapacity(capacity.available); + toPersistSpaces.add(spaceVO); + } else { + spaceVO.setTotalPhysicalCapacity(capacity.total); + spaceVO.setAvailablePhysicalCapacity(capacity.available); + spaceVO.setTotalCapacity(capacity.total); + } + } + + for (Iterator> it = beforeSpacesByUrl.entrySet().iterator(); it.hasNext(); ) { + Map.Entry entry = it.next(); + if (!cap.getCapacitiesByLocationUrl().containsKey(entry.getKey())) { + toRemoveSpaces.add(entry.getValue()); + it.remove(); + } + } + + if (!toRemoveSpaces.isEmpty()) { + dbf.removeCollection(toRemoveSpaces, ExternalPrimaryStorageSpaceVO.class); + } + if (!toPersistSpaces.isEmpty()) { + dbf.persistCollection(toPersistSpaces); + } + dbf.updateCollection(beforeSpacesByUrl.values()); + } + + private ExternalPrimaryStorageSpaceVO getSpaceFromInstallUrl(String installPath) { + Map spacesByUrl = getStorageSpacesByUrl(); + String spaceUrl = spacesByUrl.keySet().stream().filter(installPath::startsWith) + .findFirst().orElseThrow(() -> new OperationFailureException(operr("cannot find storage space for installPath[%s]", installPath))); + return spacesByUrl.get(spaceUrl); + } + + @DeadlockAutoRestart + public void releaseAvailableCapWithRatio(String installPath, long size) { + long ratioSize = ratioMgr.calculateByRatio(primaryStorageUuid, size); + _release(installPath, ratioSize); + } + + @DeadlockAutoRestart + public void releaseAvailableCapacity(String installPath, long size) { + _release(installPath, size); + } + + @Transactional + protected void _release(String installPath, long size) { + if (installPath == null) { + logger.debug(String.format("no install path found, skip release %s capacity", spaceName)); + return; + } + + ExternalPrimaryStorageSpaceVO space = getSpaceFromInstallUrl(installPath); + space.setAvailableCapacity(space.getAvailableCapacity() + size); + if (space.getAvailableCapacity() > space.getTotalPhysicalCapacity()) { + logger.warn(String.format("invalid space[locationUrl:%s] capacity after release size %s, available capacity[%s] > total capacity[%s], " + + "try to reconnect ps to recalculate pool capacity", + space.getLocationUrl(), size, space.getAvailableCapacity(), space.getTotalPhysicalCapacity())); + } + + dbf.getEntityManager().merge(space); + logger.debug(String.format("ps space [%s] release capacity: %s, updated: %s", + space.getLocationUrl(), size, space.getAvailableCapacity())); + } + + @DeadlockAutoRestart + public long reserveAvailableCapacity(String installPath, long size) { + return _reserve(installPath, size); + } + + @Transactional + protected long _reserve(String installPath, long size) { + if (installPath == null) { + logger.debug(String.format("no install path found, skip reserve %s capacity", spaceName)); + return 0; + } + + + ExternalPrimaryStorageSpaceVO space = getSpaceFromInstallUrl(installPath); + long originAvailableCapacity = space.getAvailableCapacity(); + if (originAvailableCapacity < size) { + throw new OperationFailureException(operr("required space[locationUrl:%s] cannot satisfy conditions [availableSize > %s bytes], " + + "current available size %s", space.getLocationUrl(), size, originAvailableCapacity)); + } + + space.setAvailableCapacity(space.getAvailableCapacity() - size); + dbf.getEntityManager().merge(space); + + logger.debug(String.format("%s[%s] reserve capacity: %s, origin: %s, updated: %s", + spaceName, space.getLocationUrl(), size, originAvailableCapacity, space.getAvailableCapacity())); + return originAvailableCapacity; + } + + public void recalculateAvailableCapacity() { + Map spacesByUrl = getStorageSpacesByUrl(); + Map usedCapBySpaceUrl = spacesByUrl.keySet().stream() + .collect(Collectors.toMap(url -> url, url -> 0L )); + + StopWatch watch = Utils.getStopWatch(); + watch.start(); + + // 1. calculate used capacity from volumes + long total = Q.New(VolumeVO.class).eq(VolumeVO_.primaryStorageUuid, primaryStorageUuid).count(); + SQL.New("select vol from VolumeVO vol" + + " where primaryStorageUuid = :psUuid", VolumeVO.class) + .param("psUuid", primaryStorageUuid) + .limit(1000) + .paginate(total, vos -> { + for (Object v : vos) { + VolumeVO vo = (VolumeVO) v; + if (vo.getInstallPath() != null) { + ExternalPrimaryStorageSpaceVO space = getSpaceFromInstallUrl(vo.getInstallPath()); + usedCapBySpaceUrl.compute(space.getLocationUrl(), (k, usedCap) -> usedCap + vo.getSize()); + } + } + }); + + for (String key : usedCapBySpaceUrl.keySet()) { + usedCapBySpaceUrl.compute(key, (k, usedCap) -> ratioMgr.calculateByRatio(primaryStorageUuid, usedCap)); + } + + // 2. calculate used capacity from image caches + total = Q.New(ImageCacheVO.class).eq(ImageCacheVO_.primaryStorageUuid, primaryStorageUuid).count(); + SQL.New("select img from ImageCacheVO img" + + " where primaryStorageUuid = :psUuid", ImageCacheVO.class) + .param("psUuid", primaryStorageUuid) + .limit(1000) + .paginate(total, imgs -> { + for (Object i : imgs) { + ImageCacheVO img = (ImageCacheVO) i; + if (img.getInstallUrl() != null) { + ExternalPrimaryStorageSpaceVO space = getSpaceFromInstallUrl(img.getInstallUrl()); + usedCapBySpaceUrl.compute(space.getLocationUrl(), (k, usedCap) -> usedCap + img.getSize()); + } + } + }); + + + // 3. calculate used capacity from snapshots + total = Q.New(VolumeSnapshotVO.class).eq(VolumeSnapshotVO_.primaryStorageUuid, primaryStorageUuid).count(); + SQL.New("select snap from VolumeSnapshotVO snap" + + " where primaryStorageUuid = :psUuid", VolumeSnapshotVO.class) + .param("psUuid", primaryStorageUuid) + .limit(1000) + .paginate(total, snaps -> { + for (Object s : snaps) { + VolumeSnapshotVO snap = (VolumeSnapshotVO) s; + if (snap.getPrimaryStorageInstallPath() != null) { + ExternalPrimaryStorageSpaceVO space = getSpaceFromInstallUrl(snap.getPrimaryStorageInstallPath()); + usedCapBySpaceUrl.compute(space.getLocationUrl(), (k, usedCap) -> usedCap + snap.getSize()); + } + } + }); + + watch.stop(); + logger.info(String.format("it takes %d ms to recalculate external primary storage [%s] space used capacity", + watch.getLapse(), primaryStorageUuid)); + + // 4. update available capacity + for (Map.Entry e : spacesByUrl.entrySet()) { + String url = e.getKey(); + ExternalPrimaryStorageSpaceVO space = e.getValue(); + long usedCap = usedCapBySpaceUrl.get(url); + long availableCap = space.getTotalPhysicalCapacity() - usedCap; + space.setAvailableCapacity(availableCap); + logger.info(String.format("recalculated external primary storage [%s] space [%s] available capacity: %s, used capacity: %s, total capacity: %s", + primaryStorageUuid, url, availableCap, usedCap, space.getTotalPhysicalCapacity())); + } + + dbf.updateCollection(spacesByUrl.values()); + } + + public boolean checkVirtualSizeByRatio(String requiredInstallUrl, long requiredSize) { + ExternalPrimaryStorageSpaceVO space = getSpaceFromInstallUrl(requiredInstallUrl); + return PrimaryStorageCapacityChecker.New(primaryStorageUuid, + space.getAvailableCapacity(), space.getTotalPhysicalCapacity(), space.getAvailablePhysicalCapacity()) + .checkRequiredSize(requiredSize); + } + + public String findMostSuitableSpace(long requiredSize, Comparator comparator) { + Map spacesByUrl = getStorageSpacesByUrl(); + List suitableSpaces = spacesByUrl.values().stream() + .filter(space -> PrimaryStorageCapacityChecker.New(primaryStorageUuid, + space.getAvailableCapacity(), space.getTotalPhysicalCapacity(), space.getAvailablePhysicalCapacity()) + .checkRequiredSize(requiredSize)) + .collect(Collectors.toList()); + if (CollectionUtils.isEmpty(suitableSpaces)) { + return null; + } + + suitableSpaces.sort(comparator); + return suitableSpaces.get(0).getLocationUrl(); + } + + +} diff --git a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageSpaceHelper.java b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageSpaceHelper.java new file mode 100644 index 0000000000..ee176db224 --- /dev/null +++ b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageSpaceHelper.java @@ -0,0 +1,56 @@ +package org.zstack.storage.addon.primary; + +import org.apache.commons.collections.CollectionUtils; +import org.zstack.core.db.Q; +import org.zstack.header.errorcode.OperationFailureException; +import org.zstack.header.storage.addon.primary.ExternalPrimaryStorageSpaceVO; +import org.zstack.header.storage.addon.primary.ExternalPrimaryStorageSpaceVO_; +import org.zstack.header.storage.addon.primary.ExternalPrimaryStorageVO; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.zstack.core.Platform.operr; + +public class ExternalPrimaryStorageSpaceHelper { + protected String primaryStorageUuid; + protected String spaceName; + protected Map storageSpacesByUrl; + + public ExternalPrimaryStorageSpaceHelper(ExternalPrimaryStorageVO ps) { + super(); + this.primaryStorageUuid = ps.getUuid(); + this.spaceName = ps.getIdentity(); + } + + public ExternalPrimaryStorageSpaceHelper(String psUuid, String identity) { + this.primaryStorageUuid = psUuid; + spaceName = identity; + } + + public Map getStorageSpacesByUrl() { + if (storageSpacesByUrl == null) { + List spaces = Q.New(ExternalPrimaryStorageSpaceVO.class) + .eq(ExternalPrimaryStorageSpaceVO_.primaryStorageUuid, primaryStorageUuid) + .list(); + if (CollectionUtils.isEmpty(spaces)) { + storageSpacesByUrl = new HashMap<>(); + } else { + storageSpacesByUrl = spaces.stream() + .collect(Collectors.toMap(ExternalPrimaryStorageSpaceVO::getLocationUrl, it -> it)); + spaceName += (" " + spaces.get(0).getType()); + } + } + return storageSpacesByUrl; + } + + // TODO: add cache for db result + public String getLocationSpaceUrl(String installUrl) { + Set spaceUrls = getStorageSpacesByUrl().keySet(); + return spaceUrls.stream().filter(installUrl::startsWith).findFirst() + .orElseThrow(() -> new OperationFailureException(operr("cannot find storage space for installUrl[%s]", installUrl))); + } +} diff --git a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageSystemTags.java b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageSystemTags.java new file mode 100644 index 0000000000..3ffca439ee --- /dev/null +++ b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageSystemTags.java @@ -0,0 +1,13 @@ +package org.zstack.storage.addon.primary; + +import org.zstack.header.cluster.ClusterVO; +import org.zstack.header.tag.TagDefinition; +import org.zstack.tag.EphemeralPatternSystemTag; + +@TagDefinition +public class ExternalPrimaryStorageSystemTags { + public static String REQUIRED_INSTALL_URL_TOKEN = "requiredInstallUrl"; + public static EphemeralPatternSystemTag REQUIRED_INSTALL_URL = new EphemeralPatternSystemTag( + String.format("required::installUrl::{%s}", REQUIRED_INSTALL_URL_TOKEN), + ClusterVO.class); +} \ No newline at end of file diff --git a/storage/src/main/java/org/zstack/storage/primary/ImageCacheUtil.java b/storage/src/main/java/org/zstack/storage/primary/ImageCacheUtil.java index bdae91b21f..3c835bf738 100644 --- a/storage/src/main/java/org/zstack/storage/primary/ImageCacheUtil.java +++ b/storage/src/main/java/org/zstack/storage/primary/ImageCacheUtil.java @@ -23,10 +23,14 @@ public static String getImageCachePath(ImageInventory image, Function e -> def cmd = JSONObjectUtil.toObject(e.body, ZbsPrimaryStorageMdsBase.PingCmd.class) @@ -338,7 +391,12 @@ class ZbsPrimaryStorageCase extends SubCase { addonInfo = Q.New(ExternalPrimaryStorageVO.class).select(ExternalPrimaryStorageVO_.addonInfo).eq(ExternalPrimaryStorageVO_.uuid, ps.uuid).findValue() - assert addonInfo == "{\"clusterInfo\":{\"uuid\":\"123456789\",\"version\":\"1.6.1-for-test\"},\"mdsInfos\":[{\"username\":\"root\",\"password\":\"password\",\"port\":22,\"addr\":\"127.0.1.1\",\"externalAddr\":\"127.0.0.1\",\"status\":\"Disconnected\"},{\"username\":\"root\",\"password\":\"password\",\"port\":22,\"addr\":\"127.0.1.2\",\"externalAddr\":\"127.0.0.1\",\"status\":\"Connected\"},{\"username\":\"root\",\"password\":\"password\",\"port\":22,\"addr\":\"127.0.1.3\",\"externalAddr\":\"127.0.0.1\",\"status\":\"Connected\"}],\"logicalPoolInfos\":[{\"physicalPoolID\":1,\"redundanceAndPlaceMentPolicy\":{\"copysetNum\":300,\"replicaNum\":3,\"zoneNum\":3},\"logicalPoolID\":1,\"usedSize\":322961408,\"quota\":0,\"createTime\":1735875794,\"type\":0,\"rawWalUsedSize\":0,\"allocateStatus\":0,\"rawUsedSize\":968884224,\"physicalPoolName\":\"pool1\",\"capacity\":579933831168,\"logicalPoolName\":\"lpool1\",\"userPolicy\":\"eyJwb2xpY3kiIDogMX0=\",\"allocatedSize\":3221225472}]}" + assert addonInfo == "{\"clusterInfo\":{\"uuid\":\"123456789\",\"version\":\"1.6.1-for-test\"}," + + "\"mdsInfos\":[{\"username\":\"root\",\"password\":\"password\",\"port\":22,\"addr\":\"127.0.1.1\",\"externalAddr\":\"127.0.0.1\",\"status\":\"Disconnected\"}," + + "{\"username\":\"root\",\"password\":\"password\",\"port\":22,\"addr\":\"127.0.1.2\",\"externalAddr\":\"127.0.0.1\",\"status\":\"Connected\"}," + + "{\"username\":\"root\",\"password\":\"password\",\"port\":22,\"addr\":\"127.0.1.3\",\"externalAddr\":\"127.0.0.1\",\"status\":\"Connected\"}]," + + "\"logicalPoolInfos\":[{\"physicalPoolID\":1,\"redundanceAndPlaceMentPolicy\":{\"copysetNum\":300,\"replicaNum\":3,\"zoneNum\":3},\"logicalPoolID\":1,\"usedSize\":322961408,\"quota\":0,\"createTime\":1735875794,\"type\":0,\"rawWalUsedSize\":0,\"allocateStatus\":0,\"rawUsedSize\":968884224,\"physicalPoolName\":\"pool1\",\"capacity\":579933831168,\"logicalPoolName\":\"lpool1\",\"userPolicy\":\"eyJwb2xpY3kiIDogMX0=\",\"allocatedSize\":3221225472}," + + "{\"physicalPoolID\":2,\"redundanceAndPlaceMentPolicy\":{\"copysetNum\":300,\"replicaNum\":3,\"zoneNum\":3},\"logicalPoolID\":2,\"usedSize\":123456789,\"quota\":0,\"createTime\":1735875794,\"type\":0,\"rawWalUsedSize\":0,\"allocateStatus\":0,\"rawUsedSize\":123456789,\"physicalPoolName\":\"pool2\",\"capacity\":579933831168,\"logicalPoolName\":\"lpool2\",\"userPolicy\":\"eyJwb2xpY3kiIDogMX0=\",\"allocatedSize\":987654321}]}" assert Q.New(ExternalPrimaryStorageVO.class).select(ExternalPrimaryStorageVO_.status).eq(ExternalPrimaryStorageVO_.uuid, ps.uuid).findValue() == PrimaryStorageStatus.Connected @@ -363,7 +421,12 @@ class ZbsPrimaryStorageCase extends SubCase { addonInfo = Q.New(ExternalPrimaryStorageVO.class).select(ExternalPrimaryStorageVO_.addonInfo).eq(ExternalPrimaryStorageVO_.uuid, ps.uuid).findValue() - assert addonInfo == "{\"clusterInfo\":{\"uuid\":\"123456789\",\"version\":\"1.6.1-for-test\"},\"mdsInfos\":[{\"username\":\"root\",\"password\":\"password\",\"port\":22,\"addr\":\"127.0.1.1\",\"externalAddr\":\"127.0.0.1\",\"status\":\"Disconnected\"},{\"username\":\"root\",\"password\":\"password\",\"port\":22,\"addr\":\"127.0.1.2\",\"externalAddr\":\"127.0.0.1\",\"status\":\"Disconnected\"},{\"username\":\"root\",\"password\":\"password\",\"port\":22,\"addr\":\"127.0.1.3\",\"externalAddr\":\"127.0.0.1\",\"status\":\"Disconnected\"}],\"logicalPoolInfos\":[{\"physicalPoolID\":1,\"redundanceAndPlaceMentPolicy\":{\"copysetNum\":300,\"replicaNum\":3,\"zoneNum\":3},\"logicalPoolID\":1,\"usedSize\":322961408,\"quota\":0,\"createTime\":1735875794,\"type\":0,\"rawWalUsedSize\":0,\"allocateStatus\":0,\"rawUsedSize\":968884224,\"physicalPoolName\":\"pool1\",\"capacity\":579933831168,\"logicalPoolName\":\"lpool1\",\"userPolicy\":\"eyJwb2xpY3kiIDogMX0=\",\"allocatedSize\":3221225472}]}" + assert addonInfo == "{\"clusterInfo\":{\"uuid\":\"123456789\",\"version\":\"1.6.1-for-test\"}," + + "\"mdsInfos\":[{\"username\":\"root\",\"password\":\"password\",\"port\":22,\"addr\":\"127.0.1.1\",\"externalAddr\":\"127.0.0.1\",\"status\":\"Disconnected\"}," + + "{\"username\":\"root\",\"password\":\"password\",\"port\":22,\"addr\":\"127.0.1.2\",\"externalAddr\":\"127.0.0.1\",\"status\":\"Disconnected\"}," + + "{\"username\":\"root\",\"password\":\"password\",\"port\":22,\"addr\":\"127.0.1.3\",\"externalAddr\":\"127.0.0.1\",\"status\":\"Disconnected\"}]," + + "\"logicalPoolInfos\":[{\"physicalPoolID\":1,\"redundanceAndPlaceMentPolicy\":{\"copysetNum\":300,\"replicaNum\":3,\"zoneNum\":3},\"logicalPoolID\":1,\"usedSize\":322961408,\"quota\":0,\"createTime\":1735875794,\"type\":0,\"rawWalUsedSize\":0,\"allocateStatus\":0,\"rawUsedSize\":968884224,\"physicalPoolName\":\"pool1\",\"capacity\":579933831168,\"logicalPoolName\":\"lpool1\",\"userPolicy\":\"eyJwb2xpY3kiIDogMX0=\",\"allocatedSize\":3221225472}," + + "{\"physicalPoolID\":2,\"redundanceAndPlaceMentPolicy\":{\"copysetNum\":300,\"replicaNum\":3,\"zoneNum\":3},\"logicalPoolID\":2,\"usedSize\":123456789,\"quota\":0,\"createTime\":1735875794,\"type\":0,\"rawWalUsedSize\":0,\"allocateStatus\":0,\"rawUsedSize\":123456789,\"physicalPoolName\":\"pool2\",\"capacity\":579933831168,\"logicalPoolName\":\"lpool2\",\"userPolicy\":\"eyJwb2xpY3kiIDogMX0=\",\"allocatedSize\":987654321}]}" assert Q.New(ExternalPrimaryStorageVO.class).select(ExternalPrimaryStorageVO_.status).eq(ExternalPrimaryStorageVO_.uuid, ps.uuid).findValue() == PrimaryStorageStatus.Disconnected @@ -377,13 +440,26 @@ class ZbsPrimaryStorageCase extends SubCase { } void testDataVolumeLifecycle() { + long usedCapPoolBefore = getUsedCapacity("lpool2") + long usedCapPsBefore = getUsedCapacity() vol = createDataVolume { name = "test" diskOfferingUuid = diskOffering.uuid primaryStorageUuid = ps.uuid + systemTags = [ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL.instantiateTag( + Collections.singletonMap(ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL_TOKEN, "zbs://lpool2"))] + } as VolumeInventory + assert getUsedCapacity("lpool2") == usedCapPoolBefore + vol.size + assert getUsedCapacity() == usedCapPsBefore + vol.size + assert vol.installPath.startsWith("zbs://lpool2") deleteVolume(vol.uuid) + + retryInSecs { + assert getUsedCapacity("lpool2") == usedCapPoolBefore + assert getUsedCapacity() == usedCapPsBefore + } } void testNegativeScenario() { @@ -512,4 +588,21 @@ class ZbsPrimaryStorageCase extends SubCase { uuid = volUuid } } + + long getUsedCapacity(String poolName) { + ExternalPrimaryStorageSpaceVO spaceVO = Q.New(ExternalPrimaryStorageSpaceVO.class) + .eq(ExternalPrimaryStorageSpaceVO_.primaryStorageUuid, ps.uuid) + .eq(ExternalPrimaryStorageSpaceVO_.locationUrl, "zbs://" + poolName) + .find() + + return spaceVO.totalCapacity - spaceVO.availableCapacity + } + + long getUsedCapacity() { + PrimaryStorageCapacityVO cap = Q.New(PrimaryStorageCapacityVO.class) + .eq(PrimaryStorageCapacityVO_.uuid, ps.uuid) + .find() + + return cap.totalCapacity - cap.availableCapacity + } } diff --git a/testlib/src/main/java/org/zstack/testlib/ExternalPrimaryStorageSpec.groovy b/testlib/src/main/java/org/zstack/testlib/ExternalPrimaryStorageSpec.groovy index 19dedb00cc..67092a73bb 100644 --- a/testlib/src/main/java/org/zstack/testlib/ExternalPrimaryStorageSpec.groovy +++ b/testlib/src/main/java/org/zstack/testlib/ExternalPrimaryStorageSpec.groovy @@ -1,9 +1,8 @@ package org.zstack.testlib import org.springframework.http.HttpEntity -import org.zstack.cbd.LogicalPoolInfo +import org.zstack.storage.zbs.LogicalPoolInfo import org.zstack.cbd.kvm.KvmCbdCommands -import org.zstack.kvm.KVMAgentCommands import org.zstack.sdk.PrimaryStorageInventory import org.zstack.storage.zbs.ZbsPrimaryStorageMdsBase import org.zstack.storage.zbs.ZbsStorageController @@ -124,13 +123,31 @@ class ExternalPrimaryStorageSpec extends PrimaryStorageSpec { logicalPoolInfo.setRawUsedSize(968884224); logicalPoolInfo.setPhysicalPoolName("pool1"); logicalPoolInfo.setCapacity(579933831168); - logicalPoolInfo.setLogicalPoolName(cmd.logicalPool); + logicalPoolInfo.setLogicalPoolName(cmd.logicalPoolNames[0]); logicalPoolInfo.setUserPolicy("eyJwb2xpY3kiIDogMX0="); logicalPoolInfo.setAllocatedSize(3221225472); List logicalPoolInfos = new ArrayList<>() logicalPoolInfos.add(logicalPoolInfo) + logicalPoolInfos.add(new LogicalPoolInfo( + physicalPoolID: 2, + logicalPoolID: 2, + logicalPoolName: "lpool2", + physicalPoolName: "pool2", + capacity: 579933831168, + usedSize: 123456789, + allocatedSize: 987654321, + quota: 0, + createTime: 1735875794, + type: 0, + rawWalUsedSize: 0, + allocateStatus: 0, + rawUsedSize: 123456789, + redundanceAndPlaceMentPolicy: redundanceAndPlaceMentPolicy, + userPolicy: "eyJwb2xpY3kiIDogMX0=" + )) + def rsp = new ZbsStorageController.GetCapacityRsp() rsp.setLogicalPoolInfos(logicalPoolInfos) @@ -143,7 +160,7 @@ class ExternalPrimaryStorageSpec extends PrimaryStorageSpec { assert zspec != null: "cannot found zbs primary storage[uuid:${cmd.uuid}], check your environment()." def rsp = new ZbsStorageController.CreateVolumeRsp() - rsp.setSize(actualSize) + rsp.setSize(cmd.getSizeInBytes()) rsp.setActualSize(actualSize) rsp.setInstallPath(String.format("cbd:pool1/%s/%s", cmd.logicalPool, cmd.volume)) From 8f59d57958b71db58457ab926578dfd2e2bf1884 Mon Sep 17 00:00:00 2001 From: J M Date: Mon, 15 Dec 2025 11:08:21 +0800 Subject: [PATCH 38/48] [conf]: modify addon info to TEXT DBImpact Resolves: ZSTAC-80673 Change-Id: I6b707a6c727179786b7a706e656e64756c706f66 --- conf/db/upgrade/V5.5.0__schema.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf/db/upgrade/V5.5.0__schema.sql b/conf/db/upgrade/V5.5.0__schema.sql index 5d1587afdc..e127f59504 100644 --- a/conf/db/upgrade/V5.5.0__schema.sql +++ b/conf/db/upgrade/V5.5.0__schema.sql @@ -65,3 +65,5 @@ END $$ DELIMITER ; CALL UpdateVolumeInstallPathForZbs(); + +ALTER TABLE `zstack`.`ExternalPrimaryStorageVO` MODIFY `addonInfo` TEXT DEFAULT NULL; From 4a61ea147f55e32b67fe8542f52dd2c42d7db6d8 Mon Sep 17 00:00:00 2001 From: J M Date: Tue, 16 Dec 2025 18:37:15 +0800 Subject: [PATCH 39/48] [zbs]: support zbs storage discover refactor some cbd class to zbs Resolves: ZSTAC-80635 Change-Id: I787a7a7469676f766c73647a6f706e6b76616273 --- .../java/org/zstack/cbd/CbdConstants.java | 12 - .../org/zstack/cbd/kvm/KvmCbdCommands.java | 13 - .../org/zstack/storage/zbs/AddonInfo.java | 6 +- .../zstack/storage/zbs/LogicalPoolInfo.java | 24 ++ .../java/org/zstack/storage/zbs}/MdsInfo.java | 19 +- .../org/zstack/storage/zbs}/MdsStatus.java | 2 +- .../java/org/zstack/storage/zbs}/MdsUri.java | 8 +- .../zstack/storage/zbs/ZbsListPoolResult.java | 277 ++++++++++++++++++ .../org/zstack/storage/zbs/ZbsMdsBase.java | 1 - .../storage/zbs/ZbsPrimaryStorageMdsBase.java | 2 - .../storage/zbs/ZbsStorageController.java | 27 +- .../zstack/storage/zbs/ZbsStorageFactory.java | 54 +++- .../addon/zbs/ZbsPrimaryStorageCase.groovy | 2 +- 13 files changed, 393 insertions(+), 54 deletions(-) delete mode 100644 plugin/cbd/src/main/java/org/zstack/cbd/CbdConstants.java rename plugin/{cbd/src/main/java/org/zstack/cbd => zbs/src/main/java/org/zstack/storage/zbs}/MdsInfo.java (73%) rename plugin/{cbd/src/main/java/org/zstack/cbd => zbs/src/main/java/org/zstack/storage/zbs}/MdsStatus.java (80%) rename plugin/{cbd/src/main/java/org/zstack/cbd => zbs/src/main/java/org/zstack/storage/zbs}/MdsUri.java (95%) create mode 100644 plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsListPoolResult.java 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/kvm/KvmCbdCommands.java b/plugin/cbd/src/main/java/org/zstack/cbd/kvm/KvmCbdCommands.java index 52653a0bc4..8ff948fc8c 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,6 +1,5 @@ package org.zstack.cbd.kvm; -import org.zstack.cbd.MdsInfo; import org.zstack.kvm.KVMAgentCommands; import java.util.List; @@ -19,18 +18,6 @@ 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; diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/AddonInfo.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/AddonInfo.java index d711cf7da4..fba2dd72a6 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/AddonInfo.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/AddonInfo.java @@ -1,7 +1,5 @@ package org.zstack.storage.zbs; -import org.zstack.cbd.MdsInfo; - import java.util.ArrayList; import java.util.List; @@ -37,4 +35,8 @@ public List getLogicalPoolInfos() { public void setLogicalPoolInfos(List logicalPoolInfos) { this.logicalPoolInfos = logicalPoolInfos; } + + public void addLogicalPoolInfo(LogicalPoolInfo logicalPoolInfo) { + this.logicalPoolInfos.add(logicalPoolInfo); + } } diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/LogicalPoolInfo.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/LogicalPoolInfo.java index bc3a1a1dfa..4a3a5411db 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/LogicalPoolInfo.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/LogicalPoolInfo.java @@ -170,4 +170,28 @@ public void setZoneNum(int zoneNum) { this.zoneNum = zoneNum; } } + + public static LogicalPoolInfo valueOf(ZbsListPoolResult.LogicalPoolInfo logicalPoolInfo) { + if (logicalPoolInfo == null) { + return null; + } + + LogicalPoolInfo info = new LogicalPoolInfo(); + info.setAllocatedSize(logicalPoolInfo.getAllocatedSize()); + info.setCapacity(logicalPoolInfo.getCapacity()); + info.setCreateTime(logicalPoolInfo.getCreateTime()); + info.setLogicalPoolID(logicalPoolInfo.getLogicalPoolID()); + info.setLogicalPoolName(logicalPoolInfo.getLogicalPoolName()); + info.setPhysicalPoolID(logicalPoolInfo.getPhysicalPoolID()); + info.setPhysicalPoolName(logicalPoolInfo.getPhysicalPoolName()); + info.setQuota(logicalPoolInfo.getQuota()); + info.setRawUsedSize(logicalPoolInfo.getRawUsedSize()); + info.setRawWalUsedSize(logicalPoolInfo.getRawWalUsedSize()); + info.setType(logicalPoolInfo.getType()); + info.setUsedSize(logicalPoolInfo.getUsedSize()); + info.setUserPolicy(logicalPoolInfo.getUserPolicy()); + info.setAllocateStatus(logicalPoolInfo.getAllocateStatus()); + return info; + + } } diff --git a/plugin/cbd/src/main/java/org/zstack/cbd/MdsInfo.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/MdsInfo.java similarity index 73% rename from plugin/cbd/src/main/java/org/zstack/cbd/MdsInfo.java rename to plugin/zbs/src/main/java/org/zstack/storage/zbs/MdsInfo.java index a41fff0930..4085e6657a 100644 --- a/plugin/cbd/src/main/java/org/zstack/cbd/MdsInfo.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/MdsInfo.java @@ -1,6 +1,9 @@ -package org.zstack.cbd; +package org.zstack.storage.zbs; +import java.util.Collection; +import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; /** * @author Xingwei Yu @@ -78,4 +81,18 @@ public MdsStatus getStatus() { public void setStatus(MdsStatus status) { this.status = status; } + + public static MdsInfo valueOf(String mdsUrl) { + MdsUri uri = new MdsUri(mdsUrl); + MdsInfo mdsInfo = new MdsInfo(); + mdsInfo.setUsername(uri.getUsername()); + mdsInfo.setPassword(uri.getPassword()); + mdsInfo.setPort(uri.getSshPort()); + mdsInfo.setAddr(uri.getHostname()); + return mdsInfo; + } + + public static List valueOf(Collection mdsUrls) { + return mdsUrls.stream().map(MdsInfo::valueOf).collect(Collectors.toList()); + } } diff --git a/plugin/cbd/src/main/java/org/zstack/cbd/MdsStatus.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/MdsStatus.java similarity index 80% rename from plugin/cbd/src/main/java/org/zstack/cbd/MdsStatus.java rename to plugin/zbs/src/main/java/org/zstack/storage/zbs/MdsStatus.java index 7ed70af64c..279d2605eb 100644 --- a/plugin/cbd/src/main/java/org/zstack/cbd/MdsStatus.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/MdsStatus.java @@ -1,4 +1,4 @@ -package org.zstack.cbd; +package org.zstack.storage.zbs; /** * @author Xingwei Yu diff --git a/plugin/cbd/src/main/java/org/zstack/cbd/MdsUri.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/MdsUri.java similarity index 95% rename from plugin/cbd/src/main/java/org/zstack/cbd/MdsUri.java rename to plugin/zbs/src/main/java/org/zstack/storage/zbs/MdsUri.java index 9fef3451b0..9fa1e00f38 100644 --- a/plugin/cbd/src/main/java/org/zstack/cbd/MdsUri.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/MdsUri.java @@ -1,4 +1,4 @@ -package org.zstack.cbd; +package org.zstack.storage.zbs; import org.apache.http.NameValuePair; import org.apache.http.client.utils.URLEncodedUtils; @@ -30,8 +30,10 @@ public class MdsUri { private static final Integer DEFAULT_SSH_PORT = 22; private static List allowedQueryParameter; + + private static final String MDS_PARAM_MDS_PORT = "mdsPort"; static { - allowedQueryParameter = list(CbdConstants.MDS_PARAM_MDS_PORT); + allowedQueryParameter = list(MDS_PARAM_MDS_PORT); } public static String getQueryValue(URI uri, String name) { @@ -90,7 +92,7 @@ public MdsUri(String url) { " in format of %s", url, MDS_URL_FORMAT) ); } - String v = getQueryValue(uri, CbdConstants.MDS_PARAM_MDS_PORT); + String v = getQueryValue(uri, MDS_PARAM_MDS_PORT); mdsPort = v == null ? mdsPort : Integer.parseInt(v); } catch (URISyntaxException e) { throw new CloudRuntimeException(e); diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsListPoolResult.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsListPoolResult.java new file mode 100644 index 0000000000..6a7b2f106c --- /dev/null +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsListPoolResult.java @@ -0,0 +1,277 @@ +package org.zstack.storage.zbs; + +import java.util.List; + +/** + * example: + * { + * "error": { + * "code": 0, + * "message": "success" + * }, + * "result": [ + * { + * "statusCode": 0, + * "logicalPoolInfos": [ + * { + * "logicalPoolID": 6, + * "logicalPoolName": "pool-4676f61e5c4c456891cc3ec22ef118c3", + * "physicalPoolID": 6, + * "physicalPoolName": "pool-4676f61e5c4c456891cc3ec22ef118c3_physical", + * "type": 0, + * "createTime": 1765855781, + * "redundanceAndPlaceMentPolicy": "eyJjb3B5c2V0TnVtIjoyMDAsInJlcGxpY2FOdW0iOjMsInpvbmVOdW0iOjN9Cg==", + * "userPolicy": "eyJwb2xpY3kiIDogMX0=", + * "allocateStatus": 0, + * "capacity": 390607142912, + * "usedSize": 2617245696, + * "allocatedSize": 4294967296, + * "rawUsedSize": 7851737088, + * "rawWalUsedSize": 533196800, + * "quota": 0, + * "ioPriority": 0 + * } + * ] + * }, + * { + * "statusCode": 0, + * "logicalPoolInfos": [ + * { + * "logicalPoolID": 5, + * "logicalPoolName": "pool-a65b5d3a96f44dfc95971a4fa8032a4f", + * "physicalPoolID": 5, + * "physicalPoolName": "pool-a65b5d3a96f44dfc95971a4fa8032a4f_physical", + * "type": 0, + * "createTime": 1765855755, + * "redundanceAndPlaceMentPolicy": "eyJjb3B5c2V0TnVtIjoyMDAsInJlcGxpY2FOdW0iOjMsInpvbmVOdW0iOjN9Cg==", + * "userPolicy": "eyJwb2xpY3kiIDogMX0=", + * "allocateStatus": 0, + * "capacity": 390607142912, + * "usedSize": 3162505216, + * "allocatedSize": 9663676416, + * "rawUsedSize": 9487515648, + * "rawWalUsedSize": 608768000, + * "quota": 0, + * "ioPriority": 0 + * } + * ] + * } + * ] + * } + */ + + +public class ZbsListPoolResult { + private ErrorInfo error; + private List result; + + public ErrorInfo getError() { + return error; + } + + public void setError(ErrorInfo error) { + this.error = error; + } + + public List getResult() { + return result; + } + + public void setResult(List result) { + this.result = result; + } + + public static class ErrorInfo { + private int code; + private String message; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + } + + public static class Result { + private int statusCode; + private List logicalPoolInfos; + + public int getStatusCode() { + return statusCode; + } + + public void setStatusCode(int statusCode) { + this.statusCode = statusCode; + } + + public List getLogicalPoolInfos() { + return logicalPoolInfos; + } + + public void setLogicalPoolInfos(List logicalPoolInfos) { + this.logicalPoolInfos = logicalPoolInfos; + } + } + + public boolean isSuccess() { + return error == null || error.getCode() == 0; + } + + public static class LogicalPoolInfo { + private int logicalPoolID; + private String logicalPoolName; + private int physicalPoolID; + private String physicalPoolName; + private int type; + private long createTime; + private String redundanceAndPlaceMentPolicy; + private String userPolicy; + private int allocateStatus; + private long capacity; + private long usedSize; + private long allocatedSize; + private long rawUsedSize; + private long rawWalUsedSize; + private long quota; + private int ioPriority; + + public int getLogicalPoolID() { + return logicalPoolID; + } + + public void setLogicalPoolID(int logicalPoolID) { + this.logicalPoolID = logicalPoolID; + } + + public String getLogicalPoolName() { + return logicalPoolName; + } + + public void setLogicalPoolName(String logicalPoolName) { + this.logicalPoolName = logicalPoolName; + } + + public int getPhysicalPoolID() { + return physicalPoolID; + } + + public void setPhysicalPoolID(int physicalPoolID) { + this.physicalPoolID = physicalPoolID; + } + + + public String getPhysicalPoolName() { + return physicalPoolName; + } + + public void setPhysicalPoolName(String physicalPoolName) { + this.physicalPoolName = physicalPoolName; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + public String getRedundanceAndPlaceMentPolicy() { + return redundanceAndPlaceMentPolicy; + } + + public void setRedundanceAndPlaceMentPolicy(String redundanceAndPlaceMentPolicy) { + this.redundanceAndPlaceMentPolicy = redundanceAndPlaceMentPolicy; + } + + public String getUserPolicy() { + return userPolicy; + } + + public void setUserPolicy(String userPolicy) { + this.userPolicy = userPolicy; + } + + public int getAllocateStatus() { + return allocateStatus; + } + + public void setAllocateStatus(int allocateStatus) { + this.allocateStatus = allocateStatus; + } + + public long getCapacity() { + return capacity; + } + + public void setCapacity(long capacity) { + this.capacity = capacity; + } + + public long getUsedSize() { + return usedSize; + } + + public void setUsedSize(long usedSize) { + this.usedSize = usedSize; + } + + public long getAllocatedSize() { + return allocatedSize; + } + + public void setAllocatedSize(long allocatedSize) { + this.allocatedSize = allocatedSize; + } + + public long getRawUsedSize() { + return rawUsedSize; + } + + public void setRawUsedSize(long rawUsedSize) { + this.rawUsedSize = rawUsedSize; + } + + public long getRawWalUsedSize() { + return rawWalUsedSize; + } + + public void setRawWalUsedSize(long rawWalUsedSize) { + this.rawWalUsedSize = rawWalUsedSize; + } + + public long getQuota() { + return quota; + } + + public void setQuota(long quota) { + this.quota = quota; + } + + public int getIoPriority() { + return ioPriority; + } + + public void setIoPriority(int ioPriority) { + this.ioPriority = ioPriority; + } + } +} diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsMdsBase.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsMdsBase.java index 80d3f96e7d..ecdd3d65e1 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsMdsBase.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsMdsBase.java @@ -3,7 +3,6 @@ import org.springframework.beans.factory.annotation.Autowire; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Configurable; -import org.zstack.cbd.MdsInfo; import org.zstack.core.db.DatabaseFacade; import org.zstack.header.core.Completion; import org.zstack.header.core.ReturnValueCompletion; diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsPrimaryStorageMdsBase.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsPrimaryStorageMdsBase.java index 25bbcec820..cdcef665eb 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsPrimaryStorageMdsBase.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsPrimaryStorageMdsBase.java @@ -1,8 +1,6 @@ package org.zstack.storage.zbs; import org.springframework.beans.factory.annotation.Autowired; -import org.zstack.cbd.MdsInfo; -import org.zstack.cbd.MdsStatus; import org.zstack.compute.host.HostGlobalConfig; import org.zstack.core.CoreGlobalProperty; import org.zstack.core.Platform; diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java index b41d219a02..fd6446f6bc 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java @@ -4,7 +4,6 @@ import org.springframework.beans.factory.annotation.Autowire; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Configurable; -import org.zstack.cbd.*; import org.zstack.cbd.kvm.CbdHeartbeatVolumeTO; import org.zstack.cbd.kvm.CbdVolumeTo; import org.zstack.compute.host.HostGlobalConfig; @@ -58,7 +57,6 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; -import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -354,7 +352,7 @@ public String getIdentity() { public void connect(String cfg, String url, ReturnValueCompletion completion) { AddonInfo newAddonInfo = new AddonInfo(); Config current = JSONObjectUtil.toObject(cfg, Config.class); - List mdsInfos = parseMdsInfos(current.getMdsUrls()); + List mdsInfos = MdsInfo.valueOf(current.getMdsUrls()); newAddonInfo.setMdsInfos(mdsInfos); final List mdsList = CollectionUtils.transformToList(newAddonInfo.getMdsInfos(), ZbsPrimaryStorageMdsBase::new); @@ -1137,7 +1135,7 @@ public String validateConfig(String config) throws ApiMessageInterceptionExcepti throw new ApiMessageInterceptionException(argerr("ensure at least one MDS is configured")); } - List newMdsInfos = parseMdsInfos(current.getMdsUrls()); + List newMdsInfos = MdsInfo.valueOf(current.getMdsUrls()); List duplicateMdsInfos = newMdsInfos.stream().collect(Collectors.groupingBy(MdsInfo::getAddr)) .values().stream().filter(addr -> addr.size() > 1).flatMap(List::stream).collect(Collectors.toList()); if (!duplicateMdsInfos.isEmpty()) { @@ -1146,7 +1144,7 @@ public String validateConfig(String config) throws ApiMessageInterceptionExcepti )); } - List oldMdsInfos = parseMdsInfos(old.getMdsUrls()); + List oldMdsInfos = MdsInfo.valueOf(old.getMdsUrls()); List changedMdsInfos = newMdsInfos.stream().filter(n -> oldMdsInfos.stream().noneMatch(o -> o.equals(n))).collect(Collectors.toList()); if (!changedMdsInfos.isEmpty() && !CoreGlobalProperty.UNIT_TEST_ON) { List mdsList = CollectionUtils.transformToList(changedMdsInfos, ZbsPrimaryStorageMdsBase::new); @@ -1202,18 +1200,6 @@ private void reloadDbInfo() { .collect(Collectors.toMap(LogicalPoolInfo::getLogicalPoolName, LogicalPoolInfo::getPhysicalPoolName) ); } - private List parseMdsInfos(List mdsUrls) { - return mdsUrls.stream().map(mdsUrl -> { - MdsUri uri = new MdsUri(mdsUrl); - MdsInfo mdsInfo = new MdsInfo(); - mdsInfo.setUsername(uri.getUsername()); - mdsInfo.setPassword(uri.getPassword()); - mdsInfo.setPort(uri.getSshPort()); - mdsInfo.setAddr(uri.getHostname()); - return mdsInfo; - }).collect(Collectors.toList()); - } - protected String getPhysicalPoolName(String logicalPoolName) { if (physicalPoolByLogicalPool.containsKey(logicalPoolName)) { return physicalPoolByLogicalPool.get(logicalPoolName); @@ -1898,4 +1884,11 @@ public ZbsStorageController(ExternalPrimaryStorageVO self) { this.self = self; this.reloadDbInfo(); } + + public ZbsStorageController(String config) { + this.self = new ExternalPrimaryStorageVO(); + this.self.setConfig(config); + this.config = StringUtils.isEmpty(self.getConfig()) ? new Config() : JSONObjectUtil.toObject(self.getConfig(), Config.class); + this.addonInfo = new AddonInfo(); + } } diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageFactory.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageFactory.java index df9fb479a2..0602c4dea8 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageFactory.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageFactory.java @@ -3,6 +3,7 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.zstack.core.ansible.SshFileMd5Checker; import org.zstack.core.cloudbus.CloudBus; import org.zstack.core.db.Q; import org.zstack.core.trash.StorageTrash; @@ -18,8 +19,13 @@ import org.zstack.header.volume.VolumeProtocol; import org.zstack.header.volume.VolumeVO; import org.zstack.header.volume.VolumeVO_; +import org.zstack.utils.ShellResult; +import org.zstack.utils.ShellUtils; import org.zstack.utils.Utils; +import org.zstack.utils.gson.JSONObjectUtil; import org.zstack.utils.logging.CLogger; +import org.zstack.utils.ssh.Ssh; +import org.zstack.utils.ssh.SshResult; import java.util.LinkedHashMap; import java.util.List; @@ -52,7 +58,53 @@ public PrimaryStorageNodeSvc buildNodeSvc(ExternalPrimaryStorageVO vo) { @Override public void discover(String url, String config, ReturnValueCompletion completion) { - completion.fail(operr("zbs not support discover yet")); + AddonInfo addonInfo = new AddonInfo(); + + Config conf = JSONObjectUtil.toObject(config, Config.class); + + if (CollectionUtils.isEmpty(conf.getMdsUrls())) { + completion.fail(operr("mdsUrls cannot be null or empty")); + return; + } + + String errInfo = ""; + for (MdsInfo mdsInfo : MdsInfo.valueOf(conf.getMdsUrls())) { + Ssh ssh = new Ssh(); + ssh.setUsername(mdsInfo.getUsername()) + .setPassword(mdsInfo.getPassword()).setPort(mdsInfo.getPort()) + .setHostname(mdsInfo.getAddr()) + .setTimeout(5); + try { + ssh.sudoCommand("/usr/bin/zbs list logical-pool --format json"); + SshResult ret = ssh.run(); + if (ret.getReturnCode() != 0) { + errInfo += String.format("failed to list logical pools from MDS[%s], because %s\n", mdsInfo.getAddr(), ret.getStderr()); + continue; + } + + ssh.reset(); + + String poolStr = ret.getStdout(); + ZbsListPoolResult result = JSONObjectUtil.toObject(poolStr, ZbsListPoolResult.class); + if (!result.isSuccess()) { + errInfo += String.format("failed to list logical pools from MDS[%s], because %s\n", mdsInfo.getAddr(), result.getError().getMessage()); + continue; + } + + for (ZbsListPoolResult.Result poolRet : result.getResult()) { + if (poolRet.getStatusCode() == 0) { + poolRet.getLogicalPoolInfos().forEach(it -> + addonInfo.addLogicalPoolInfo(LogicalPoolInfo.valueOf(it))); + } + } + completion.success(JSONObjectUtil.rehashObject(addonInfo, LinkedHashMap.class)); + return; + } finally { + ssh.close(); + } + } + + completion.fail(operr("unable to discover logical pools from all MDSs, details: %s", errInfo)); } public void setPreferBackupStorageTypes(List preferBackupStorageTypes) { diff --git a/test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsPrimaryStorageCase.groovy b/test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsPrimaryStorageCase.groovy index af306654ed..b546772215 100644 --- a/test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsPrimaryStorageCase.groovy +++ b/test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsPrimaryStorageCase.groovy @@ -11,7 +11,7 @@ import org.zstack.header.storage.primary.PrimaryStorageCapacityVO_ import org.zstack.header.storage.primary.PrimaryStorageHostRefVO import org.zstack.header.storage.primary.PrimaryStorageHostRefVO_ import org.zstack.header.storage.primary.PrimaryStorageStatus -import org.zstack.cbd.MdsUri +import org.zstack.storage.zbs.MdsUri import org.zstack.sdk.* import org.zstack.storage.addon.primary.ExternalPrimaryStorageSystemTags import org.zstack.storage.primary.PrimaryStorageGlobalConfig From a5436296b01e3fd864e70f224dded07076e5fa47 Mon Sep 17 00:00:00 2001 From: J M Date: Tue, 16 Dec 2025 22:47:41 +0800 Subject: [PATCH 40/48] [storage]: support multi pool heartbeat volume Resolves: ZSTAC-80625 Change-Id: I796e6c6d626e637578746c6861796f7479717663 --- .../primary/HeartbeatVolumeTopology.java | 26 +++++++ .../addon/primary/PrimaryStorageNodeSvc.java | 4 +- .../org/zstack/cbd/kvm/KvmCbdCommands.java | 4 +- .../org/zstack/cbd/kvm/KvmCbdNodeServer.java | 20 ++--- .../zstack/expon/ExponStorageController.java | 13 +++- .../primary/ExternalStorageFencerType.java | 1 + .../zstack/iscsi/kvm/KvmIscsiNodeServer.java | 9 ++- .../kvm/KvmSetupSelfFencerExtensionPoint.java | 10 +++ .../xinfini/XInfiniStorageController.java | 14 +++- .../storage/zbs/ZbsStorageController.java | 75 ++++++++++++------- .../addon/primary/ExternalPrimaryStorage.java | 9 ++- 11 files changed, 133 insertions(+), 52 deletions(-) create mode 100644 header/src/main/java/org/zstack/header/storage/addon/primary/HeartbeatVolumeTopology.java 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/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/plugin/cbd/src/main/java/org/zstack/cbd/kvm/KvmCbdCommands.java b/plugin/cbd/src/main/java/org/zstack/cbd/kvm/KvmCbdCommands.java index 8ff948fc8c..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 @@ -3,6 +3,7 @@ import org.zstack.kvm.KVMAgentCommands; import java.util.List; +import java.util.Map; /** * @author Xingwei Yu @@ -21,8 +22,7 @@ public static class AgentRsp { 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 8c3e60e68f..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 @@ -15,7 +15,6 @@ import org.zstack.header.core.ReturnValueCompletion; import org.zstack.header.core.workflow.*; import org.zstack.header.errorcode.ErrorCode; -import org.zstack.header.errorcode.OperationFailureException; import org.zstack.header.host.HostConstant; import org.zstack.header.host.HostInventory; import org.zstack.header.host.HostVO; @@ -35,8 +34,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; -import static org.zstack.core.Platform.argerr; import static org.zstack.core.Platform.operr; /** @@ -76,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() { @@ -104,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(); } @@ -136,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(); 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 2528ddeb27..8092ce34d6 100644 --- a/plugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java +++ b/plugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java @@ -625,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())); @@ -662,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 @@ -704,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); @@ -730,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) { 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 7c0e17cd17..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 @@ -15,6 +15,7 @@ public class ExternalStorageFencerType { 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/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/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/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java b/plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java index 92224dc1e4..4fb920421a 100644 --- a/plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java +++ b/plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java @@ -414,7 +414,7 @@ public void deployClient(HostInventory h, Completion 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())); @@ -431,7 +431,10 @@ public synchronized void activateHeartbeatVolume(HostInventory h, ReturnValueCom to.setHostId(apiHelper.queryBdcByIp(h.getManagementIp()).getSpec().getId()); to.setHeartbeatRequiredSpace(SizeUnit.MEGABYTE.toByte(1)); to.setCoveringPaths(Collections.singletonList(getVhostSocketDir())); - comp.success(to); + + HeartbeatVolumeTopology topology = new HeartbeatVolumeTopology(); + topology.setHeartbeatVolumeByCoveringPaths(Collections.singletonMap(getVhostSocketDir(), to)); + comp.success(topology); } @Override @@ -460,7 +463,7 @@ public void deactivateHeartbeatVolume(HostInventory h, Completion comp) { } @Override - public HeartbeatVolumeTO getHeartbeatVolumeActiveInfo(HostInventory h) { + public HeartbeatVolumeTopology getHeartbeatVolumeActiveInfo(HostInventory h) { VolumeModule heartbeatVol = apiHelper.queryVolumeByName(iscsiHeartbeatVolumeName); if (heartbeatVol == null) { throw new RuntimeException("heartbeat volume not found"); @@ -477,7 +480,10 @@ public HeartbeatVolumeTO getHeartbeatVolumeActiveInfo(HostInventory h) { to.setHostId(apiHelper.queryBdcByIp(h.getManagementIp()).getSpec().getId()); to.setHeartbeatRequiredSpace(SizeUnit.MEGABYTE.toByte(1)); to.setCoveringPaths(Collections.singletonList(getVhostSocketDir())); - return to; + + HeartbeatVolumeTopology topology = new HeartbeatVolumeTopology(); + topology.setHeartbeatVolumeByCoveringPaths(Collections.singletonMap(getVhostSocketDir(), to)); + return topology; } private VolumeModule getVolumeModule(BaseVolumeInfo vol) { diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java index fd6446f6bc..38e082da09 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java @@ -292,31 +292,47 @@ public void handle(ErrorCode errCode, Map data) { } @Override - public synchronized void activateHeartbeatVolume(HostInventory h, ReturnValueCompletion comp) { + public synchronized void activateHeartbeatVolume(HostInventory h, ReturnValueCompletion completion) { if (config == null) { reloadDbInfo(); } - CreateVolumeCmd cmd = new CreateVolumeCmd(); - cmd.setLogicalPool(config.getLogicalPoolName()); - cmd.setVolume(ZbsConstants.ZBS_HEARTBEAT_VOLUME_NAME); - cmd.setSize(ZbsConstants.ZBS_HEARTBEAT_VOLUME_SIZE_IN_GIGABYTE); - cmd.setSkipIfExisting(true); + // TODO: split by physical pool not logical pool, handle logical pool deletion + HeartbeatVolumeTopology topology = new HeartbeatVolumeTopology(); + new While<>(config.getPoolNames()).each((poolName, comp) -> { + CreateVolumeCmd cmd = new CreateVolumeCmd(); + cmd.setLogicalPool(poolName); + cmd.setVolume(ZbsConstants.ZBS_HEARTBEAT_VOLUME_NAME); + cmd.setSize(ZbsConstants.ZBS_HEARTBEAT_VOLUME_SIZE_IN_GIGABYTE); + cmd.setSkipIfExisting(true); - httpCall(CREATE_VOLUME_PATH, cmd, CreateVolumeRsp.class, new ReturnValueCompletion(comp) { - @Override - public void success(CreateVolumeRsp returnValue) { - CbdHeartbeatVolumeTO to = new CbdHeartbeatVolumeTO(); - String zbsPath = returnValue.installPath; - to.setInstallPath(ZbsHelper.convertZbsPathToCbdPath(zbsPath, ZbsStorageController.this::getPhysicalPoolName)); - to.setHeartbeatRequiredSpace(SizeUnit.MEGABYTE.toByte(1)); - to.setCoveringPaths(config.getPoolNames()); - comp.success(to); - } + httpCall(CREATE_VOLUME_PATH, cmd, CreateVolumeRsp.class, new ReturnValueCompletion(comp) { + @Override + public void success(CreateVolumeRsp returnValue) { + CbdHeartbeatVolumeTO to = new CbdHeartbeatVolumeTO(); + String zbsPath = returnValue.installPath; + to.setInstallPath(ZbsHelper.convertZbsPathToCbdPath(zbsPath, ZbsStorageController.this::getPhysicalPoolName)); + to.setHeartbeatRequiredSpace(SizeUnit.MEGABYTE.toByte(1)); + to.setCoveringPaths(config.getPoolNames()); + topology.putHeartbeatVolume(poolName, to); + comp.done(); + } + @Override + public void fail(ErrorCode errorCode) { + comp.addError(errorCode); + comp.allDone(); + } + }); + }).run(new WhileDoneCompletion(completion) { @Override - public void fail(ErrorCode errorCode) { - comp.fail(errorCode); + public void done(ErrorCodeList errorCodeList) { + if (!errorCodeList.getCauses().isEmpty()) { + completion.fail(errorCodeList.getCauses().get(0)); + return; + } + + completion.success(topology); } }); } @@ -327,20 +343,27 @@ public void deactivateHeartbeatVolume(HostInventory h, Completion comp) { } @Override - public HeartbeatVolumeTO getHeartbeatVolumeActiveInfo(HostInventory h) { + public HeartbeatVolumeTopology getHeartbeatVolumeActiveInfo(HostInventory h) { if (config == null) { reloadDbInfo(); } - String zbsPath = buildHeartbeatVolumePath(config.getLogicalPoolName()); - String cbdPath = ZbsHelper.convertZbsPathToCbdPath(zbsPath, this::getPhysicalPoolName); + HeartbeatVolumeTopology topology = new HeartbeatVolumeTopology(); + Map map = new HashMap<>(); + for (String poolName : config.getPoolNames()) { + String zbsPath = buildHeartbeatVolumePath(poolName); - CbdHeartbeatVolumeTO to = new CbdHeartbeatVolumeTO(); - to.setInstallPath(cbdPath); - to.setHeartbeatRequiredSpace(SizeUnit.MEGABYTE.toByte(1)); - to.setCoveringPaths(config.getPoolNames()); + String cbdPath = ZbsHelper.convertZbsPathToCbdPath(zbsPath, this::getPhysicalPoolName); + CbdHeartbeatVolumeTO to = new CbdHeartbeatVolumeTO(); + to.setInstallPath(cbdPath); + to.setHeartbeatRequiredSpace(SizeUnit.MEGABYTE.toByte(1)); + to.setCoveringPaths(config.getPoolNames()); + + map.put(poolName, to); + } - return to; + topology.setHeartbeatVolumeByCoveringPaths(map); + return topology; } @Override diff --git a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java index 18fc2af1f1..7202169315 100644 --- a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java +++ b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java @@ -182,6 +182,7 @@ private void handle(APIUpdateExternalPrimaryStorageMsg msg) { externalVO.setDefaultProtocol(msg.getDefaultProtocol()); } boolean needReconnect = false; + String oldConfig = externalVO.getConfig(); if (msg.getConfig() != null) { String config = controller.validateConfig(msg.getConfig()); externalVO.setConfig(config); @@ -200,7 +201,13 @@ public void run(MessageReply reply) { evt.setError(reply.getError()); } else { self = dbf.reload(self); - evt.setInventory(externalVO.toInventory()); + ExternalPrimaryStorageInventory inv = externalVO.toInventory(); + evt.setInventory(inv); + + // TODO: use controller not extension point + for (UpdatePrimaryStorageExtensionPoint ext : pluginRgty.getExtensionList(UpdatePrimaryStorageExtensionPoint.class)) { + ext.afterUpdatePrimaryStorage(inv); + } } bus.publish(evt); From cfb74be1860330924b67c2745f91af1221ab6ae0 Mon Sep 17 00:00:00 2001 From: J M Date: Thu, 18 Dec 2025 14:58:57 +0800 Subject: [PATCH 41/48] [zbs]: support copy volume to another pool Resolves: ZSTAC-80718 Change-Id: I706369637978617661746173786d637069677061 --- .../zstack/storage/zbs/ZbsStorageController.java | 14 ++++++++------ .../addon/primary/ExternalPrimaryStorage.java | 9 ++++++++- .../testlib/ExternalPrimaryStorageSpec.groovy | 7 ++++++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java index 38e082da09..1812808c2a 100644 --- a/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java +++ b/plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java @@ -853,7 +853,9 @@ public void copyVolume(String srcInstallPath, CreateVolumeSpec dst, ReturnValueC CopyCmd cmd = new CopyCmd(); cmd.setPath(srcInstallPath); cmd.setDstVolume(dst.getName()); - cmd.setDstSize(dst.getSize() / (1L << 30)); + if (dst.getAllocatedUrl() != null) { + cmd.setDstPool(getPoolFromVolumePath(dst.getAllocatedUrl())); + } httpCall(COPY_PATH, cmd, CopyRsp.class, new ReturnValueCompletion(comp) { @Override @@ -1536,7 +1538,7 @@ public void setPath(String path) { public static class CopyCmd extends VolumeCommand implements HasThreadContext { private String dstVolume; - private long dstSize; + private String dstPool; public String getDstVolume() { return dstVolume; @@ -1546,12 +1548,12 @@ public void setDstVolume(String dstVolume) { this.dstVolume = dstVolume; } - public long getDstSize() { - return dstSize; + public void setDstPool(String dstPool) { + this.dstPool = dstPool; } - public void setDstSize(long dstSize) { - this.dstSize = dstSize; + public String getDstPool() { + return dstPool; } } diff --git a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java index 7202169315..b650356c7d 100644 --- a/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java +++ b/storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java @@ -779,7 +779,9 @@ private void createImageCacheFromSnapshot(CreateImageCacheFromVolumeSnapshotOnPr ImageCacheInventory inventory; - ImageInventory image = msg.getImageInventory(); + final ImageInventory image = msg.getImageInventory(); + + final String requiredUrlTag = msg.getSystemTag(ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL::isMatch); @Override public void setup() { @@ -792,6 +794,11 @@ public void run(FlowTrigger trigger, Map data) { spec.setName(buildImageName(image.getUuid())); spec.setUuid(msg.getImageInventory().getUuid()); spec.setSize(msg.getImageInventory().getSize()); + if (requiredUrlTag != null) { + String requiredUrl = ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL.getTokenByTag( + requiredUrlTag, ExternalPrimaryStorageSystemTags.REQUIRED_INSTALL_URL_TOKEN); + spec.setAllocatedUrl(requiredUrl); + } controller.copyVolume(msg.getVolumeSnapshot().getPrimaryStorageInstallPath(), spec, new ReturnValueCompletion(trigger) { @Override public void success(VolumeStats dst) { diff --git a/testlib/src/main/java/org/zstack/testlib/ExternalPrimaryStorageSpec.groovy b/testlib/src/main/java/org/zstack/testlib/ExternalPrimaryStorageSpec.groovy index 67092a73bb..ca2b74ea49 100644 --- a/testlib/src/main/java/org/zstack/testlib/ExternalPrimaryStorageSpec.groovy +++ b/testlib/src/main/java/org/zstack/testlib/ExternalPrimaryStorageSpec.groovy @@ -227,7 +227,12 @@ class ExternalPrimaryStorageSpec extends PrimaryStorageSpec { assert zspec != null: "cannot found zbs primary storage[uuid:${cmd.uuid}], check your environment()." def rsp = new ZbsStorageController.CopyRsp() - rsp.setInstallPath(cmd.path.replaceAll("([^/]+)\$", cmd.dstVolume)) + if (cmd.dstPool != null) { + // lpool1 physical pool is pool1 + rsp.installPath = "cbd:${cmd.dstPool.substring(1)}/${cmd.dstPool}/${cmd.dstVolume}" + } else { + rsp.setInstallPath(cmd.path.replaceAll("([^/]+)\$", cmd.dstVolume)) + } rsp.setSize(actualSize) return rsp From 4f7be587a2908ae437ec0c59941936042cb9bf41 Mon Sep 17 00:00:00 2001 From: "hanyu.liang" Date: Tue, 18 Nov 2025 15:30:21 +0800 Subject: [PATCH 42/48] [mevoco]: correct ARM and VMware add-ons not consuming main license quota Resolves: ZSTAC-79237 Change-Id: I646365206a7923767067706e7a6e667a796f686d --- conf/db/upgrade/V5.5.0__schema.sql | 2 ++ .../license/api/server/RequestLicenseCapacityAction.java | 3 +++ .../header/server/LicenseAuthorizedCapacityInventory.java | 8 ++++++++ 3 files changed, 13 insertions(+) diff --git a/conf/db/upgrade/V5.5.0__schema.sql b/conf/db/upgrade/V5.5.0__schema.sql index f6f376c572..9c0de3f591 100644 --- a/conf/db/upgrade/V5.5.0__schema.sql +++ b/conf/db/upgrade/V5.5.0__schema.sql @@ -1,4 +1,6 @@ CALL ADD_COLUMN('VmVfNicVO', 'secondaryPciDeviceUuid', 'VARCHAR(32)', 1, NULL); ALTER TABLE `zstack`.`VmVfNicVO` ADD CONSTRAINT `fkVmVfNicVOSecondaryPciDeviceVO` FOREIGN KEY (`secondaryPciDeviceUuid`) REFERENCES `zstack`.`PciDeviceVO` (`uuid`) ON DELETE SET NULL; +CALL ADD_COLUMN('LicenseAuthorizedCapacityVO', 'resourceInfo', 'text', 1, NULL); + CALL ADD_COLUMN('PciDeviceVO', 'dependentDevices', 'varchar(255)', 1, NULL); diff --git a/sdk/src/main/java/org/zstack/sdk/license/api/server/RequestLicenseCapacityAction.java b/sdk/src/main/java/org/zstack/sdk/license/api/server/RequestLicenseCapacityAction.java index 0f42eedfe4..8e632d9428 100644 --- a/sdk/src/main/java/org/zstack/sdk/license/api/server/RequestLicenseCapacityAction.java +++ b/sdk/src/main/java/org/zstack/sdk/license/api/server/RequestLicenseCapacityAction.java @@ -40,6 +40,9 @@ public Result throwExceptionIfError() { @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String licenseType; + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String resourceInfo; + @Param(required = false) public java.util.List systemTags; diff --git a/sdk/src/main/java/org/zstack/sdk/license/header/server/LicenseAuthorizedCapacityInventory.java b/sdk/src/main/java/org/zstack/sdk/license/header/server/LicenseAuthorizedCapacityInventory.java index cb5184b020..744932d801 100644 --- a/sdk/src/main/java/org/zstack/sdk/license/header/server/LicenseAuthorizedCapacityInventory.java +++ b/sdk/src/main/java/org/zstack/sdk/license/header/server/LicenseAuthorizedCapacityInventory.java @@ -28,6 +28,14 @@ public java.lang.String getResourceUuid() { return this.resourceUuid; } + public java.lang.String resourceInfo; + public void setResourceInfo(java.lang.String resourceInfo) { + this.resourceInfo = resourceInfo; + } + public java.lang.String getResourceInfo() { + return this.resourceInfo; + } + public java.lang.String quotaType; public void setQuotaType(java.lang.String quotaType) { this.quotaType = quotaType; From efb1d9aed5161b11bd15a3770060fb06d4c5f562 Mon Sep 17 00:00:00 2001 From: "hanyu.liang" Date: Mon, 1 Dec 2025 16:56:14 +0800 Subject: [PATCH 43/48] [conf]: support comparing remote and local quota info in RegisterLicenseServer Resolves: ZSTAC-79953 Change-Id: I646379953a7923767067706e7a6e667a796f686d --- conf/errorCodes/license.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/conf/errorCodes/license.xml b/conf/errorCodes/license.xml index fa1db7d837..feaa70a2be 100755 --- a/conf/errorCodes/license.xml +++ b/conf/errorCodes/license.xml @@ -76,6 +76,21 @@ License public key error + + 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 From 1ae8682a020222b540c81f6b30e34850cf15d4fd Mon Sep 17 00:00:00 2001 From: lianghy Date: Wed, 26 Nov 2025 16:36:21 +0800 Subject: [PATCH 44/48] [mevoco]: correct capacity check under addon overuse Fix inaccurate capacity validation caused by incorrect arm addon or vmware addon overuse Resolves: ZSTAC-79237 Change-Id: I646365206a7923767067706e7a6e667a796f686d --- .../header/server/TotalLicenseAuthorizedCapacityView.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sdk/src/main/java/org/zstack/sdk/license/header/server/TotalLicenseAuthorizedCapacityView.java b/sdk/src/main/java/org/zstack/sdk/license/header/server/TotalLicenseAuthorizedCapacityView.java index 7860523e8b..582857bcae 100644 --- a/sdk/src/main/java/org/zstack/sdk/license/header/server/TotalLicenseAuthorizedCapacityView.java +++ b/sdk/src/main/java/org/zstack/sdk/license/header/server/TotalLicenseAuthorizedCapacityView.java @@ -45,4 +45,12 @@ public java.util.List getAddOns() { return this.addOns; } + public java.util.Map extensions; + public void setExtensions(java.util.Map extensions) { + this.extensions = extensions; + } + public java.util.Map getExtensions() { + return this.extensions; + } + } From 93144910af7d9c9e7b768a024b561661f1fa589f Mon Sep 17 00:00:00 2001 From: "hanyu.liang" Date: Tue, 9 Dec 2025 05:01:51 -0500 Subject: [PATCH 45/48] [mevoco]: support retrieving self-usage information in getLicenseInfo Resolves: ZSTAC-80504 Change-Id: I6c6880504661647274666b76786c766a12346b66 --- sdk/src/main/java/SourceClassMap.java | 2 ++ .../header/server/LicenseUsageDetailView.java | 31 +++++++++++++++++++ .../header/server/LicenseUsageView.java | 8 +++++ 3 files changed, 41 insertions(+) create mode 100644 sdk/src/main/java/org/zstack/sdk/license/header/server/LicenseUsageDetailView.java diff --git a/sdk/src/main/java/SourceClassMap.java b/sdk/src/main/java/SourceClassMap.java index 976ae5d4e4..f741eb4d57 100644 --- a/sdk/src/main/java/SourceClassMap.java +++ b/sdk/src/main/java/SourceClassMap.java @@ -504,6 +504,7 @@ public class SourceClassMap { put("org.zstack.license.header.server.LicenseAuthorizedCapacityServerUsageView", "org.zstack.sdk.license.header.server.LicenseAuthorizedCapacityServerUsageView"); put("org.zstack.license.header.server.LicenseAuthorizedCapacityUsageDetailView", "org.zstack.sdk.license.header.server.LicenseAuthorizedCapacityUsageDetailView"); put("org.zstack.license.header.server.LicenseAuthorizedNodeInventory", "org.zstack.sdk.license.header.server.LicenseAuthorizedNodeInventory"); + put("org.zstack.license.header.server.LicenseUsageDetailView", "org.zstack.sdk.license.header.server.LicenseUsageDetailView"); put("org.zstack.license.header.server.LicenseUsageView", "org.zstack.sdk.license.header.server.LicenseUsageView"); put("org.zstack.license.header.server.TotalLicenseAuthorizedCapacityView", "org.zstack.sdk.license.header.server.TotalLicenseAuthorizedCapacityView"); put("org.zstack.log.server.LogCategory", "org.zstack.sdk.LogCategory"); @@ -1622,6 +1623,7 @@ public class SourceClassMap { put("org.zstack.sdk.license.header.server.LicenseAuthorizedCapacityServerUsageView", "org.zstack.license.header.server.LicenseAuthorizedCapacityServerUsageView"); put("org.zstack.sdk.license.header.server.LicenseAuthorizedCapacityUsageDetailView", "org.zstack.license.header.server.LicenseAuthorizedCapacityUsageDetailView"); put("org.zstack.sdk.license.header.server.LicenseAuthorizedNodeInventory", "org.zstack.license.header.server.LicenseAuthorizedNodeInventory"); + put("org.zstack.sdk.license.header.server.LicenseUsageDetailView", "org.zstack.license.header.server.LicenseUsageDetailView"); put("org.zstack.sdk.license.header.server.LicenseUsageView", "org.zstack.license.header.server.LicenseUsageView"); put("org.zstack.sdk.license.header.server.TotalLicenseAuthorizedCapacityView", "org.zstack.license.header.server.TotalLicenseAuthorizedCapacityView"); put("org.zstack.sdk.sns.SNSAliyunSmsEndpointInventory", "org.zstack.sns.SNSAliyunSmsEndpointInventory"); diff --git a/sdk/src/main/java/org/zstack/sdk/license/header/server/LicenseUsageDetailView.java b/sdk/src/main/java/org/zstack/sdk/license/header/server/LicenseUsageDetailView.java new file mode 100644 index 0000000000..53bca0260b --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/license/header/server/LicenseUsageDetailView.java @@ -0,0 +1,31 @@ +package org.zstack.sdk.license.header.server; + + + +public class LicenseUsageDetailView { + + public java.lang.String usedBy; + public void setUsedBy(java.lang.String usedBy) { + this.usedBy = usedBy; + } + public java.lang.String getUsedBy() { + return this.usedBy; + } + + public long usage; + public void setUsage(long usage) { + this.usage = usage; + } + public long getUsage() { + return this.usage; + } + + public java.lang.String resourceInfo; + public void setResourceInfo(java.lang.String resourceInfo) { + this.resourceInfo = resourceInfo; + } + public java.lang.String getResourceInfo() { + return this.resourceInfo; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/license/header/server/LicenseUsageView.java b/sdk/src/main/java/org/zstack/sdk/license/header/server/LicenseUsageView.java index dd713fdddf..d6d3611251 100644 --- a/sdk/src/main/java/org/zstack/sdk/license/header/server/LicenseUsageView.java +++ b/sdk/src/main/java/org/zstack/sdk/license/header/server/LicenseUsageView.java @@ -36,4 +36,12 @@ public long getAvailable() { return this.available; } + public java.util.List usageDetails; + public void setUsageDetails(java.util.List usageDetails) { + this.usageDetails = usageDetails; + } + public java.util.List getUsageDetails() { + return this.usageDetails; + } + } From 30f8a35c8f463d374654aec8cb5909a0f296fe80 Mon Sep 17 00:00:00 2001 From: "lin.ma" Date: Mon, 1 Dec 2025 21:49:24 +0800 Subject: [PATCH 46/48] [hygon]: Hygon CCP Device Passthrough CCP = Cryptographic Co-Processor Resolves: ZSTAC-79099 Change-Id: I746a686d6179677875656c786464676475676370 --- build/deploydb.sh | 26 ++-- .../zstack/compute/host/HostSystemTags.java | 3 + .../org/zstack/compute/vm/VmInstanceBase.java | 9 ++ .../compute/vm/VmInstanceManagerImpl.java | 29 +++-- .../org/zstack/compute/vm/VmSystemTags.java | 4 + conf/db/upgrade/V5.5.0__schema.sql | 52 ++++++++ conf/zstack.xml | 1 + .../org/zstack/header/vm/VmInstanceSpec.java | 9 ++ .../java/org/zstack/kvm/KVMAgentCommands.java | 12 ++ .../src/main/java/org/zstack/kvm/KVMHost.java | 3 + .../scripts/RestDocumentationGenerator.groovy | 1 + sdk/src/main/java/SourceClassMap.java | 6 + .../sdk/GenerateHygonMdevDevicesAction.java | 104 ++++++++++++++++ .../sdk/GenerateHygonMdevDevicesResult.java | 7 ++ .../zstack/sdk/HygonCcpDeviceInventory.java | 112 ++++++++++++++++++ .../java/org/zstack/sdk/HygonDeviceState.java | 6 + .../java/org/zstack/sdk/HygonDeviceType.java | 6 + .../zstack/sdk/QueryHygonDeviceAction.java | 75 ++++++++++++ .../zstack/sdk/QueryHygonDeviceResult.java | 22 ++++ .../sdk/SetVmInstanceHygonMdevAction.java | 104 ++++++++++++++++ .../sdk/SetVmInstanceHygonMdevResult.java | 7 ++ .../sdk/UngenerateHygonMdevDevicesAction.java | 101 ++++++++++++++++ .../sdk/UngenerateHygonMdevDevicesResult.java | 7 ++ .../java/org/zstack/testlib/ApiHelper.groovy | 110 +++++++++++++++++ 24 files changed, 798 insertions(+), 18 deletions(-) create mode 100644 sdk/src/main/java/org/zstack/sdk/GenerateHygonMdevDevicesAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/GenerateHygonMdevDevicesResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/HygonCcpDeviceInventory.java create mode 100644 sdk/src/main/java/org/zstack/sdk/HygonDeviceState.java create mode 100644 sdk/src/main/java/org/zstack/sdk/HygonDeviceType.java create mode 100644 sdk/src/main/java/org/zstack/sdk/QueryHygonDeviceAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/QueryHygonDeviceResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/SetVmInstanceHygonMdevAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/SetVmInstanceHygonMdevResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/UngenerateHygonMdevDevicesAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/UngenerateHygonMdevDevicesResult.java diff --git a/build/deploydb.sh b/build/deploydb.sh index b0d922475b..dc9c5478d2 100755 --- a/build/deploydb.sh +++ b/build/deploydb.sh @@ -27,7 +27,12 @@ else loginCmd="--user=$user --password=$password --host=$host --port=$port" fi -if command -v greatdb &> /dev/null; then +# Detect MySQL version +# Extract major version number from various MySQL/MariaDB/GreatDB output formats +db_version=$(${MYSQL} --version 2>/dev/null | grep -oP '\d+\.\d+\.\d+' | head -1 | cut -d'.' -f1 || echo "5") + +# GreatDB and MySQL 8.0+ require CREATE USER before GRANT +if command -v greatdb &> /dev/null || [ "$db_version" -ge 8 ] 2>/dev/null; then ${MYSQL} ${loginCmd} << EOF set global log_bin_trust_function_creators=1; DROP DATABASE IF EXISTS zstack; @@ -42,16 +47,17 @@ if command -v greatdb &> /dev/null; then grant all privileges on zstack_rest.* to root@'127.0.0.1'; EOF else + # MySQL 5.x: GRANT with IDENTIFIED BY auto-creates users ${MYSQL} ${loginCmd} << EOF - set global log_bin_trust_function_creators=1; - DROP DATABASE IF EXISTS zstack; - CREATE DATABASE zstack; - DROP DATABASE IF EXISTS zstack_rest; - CREATE DATABASE zstack_rest; - grant all privileges on zstack.* to root@'%' identified by "${password}"; - grant all privileges on zstack_rest.* to root@'%' identified by "${password}"; - grant all privileges on zstack.* to root@'127.0.0.1' identified by "${password}"; - grant all privileges on zstack_rest.* to root@'127.0.0.1' identified by "${password}"; + set global log_bin_trust_function_creators=1; + DROP DATABASE IF EXISTS zstack; + CREATE DATABASE zstack; + DROP DATABASE IF EXISTS zstack_rest; + CREATE DATABASE zstack_rest; + grant all privileges on zstack.* to root@'%' identified by "${password}"; + grant all privileges on zstack_rest.* to root@'%' identified by "${password}"; + grant all privileges on zstack.* to root@'127.0.0.1' identified by "${password}"; + grant all privileges on zstack_rest.* to root@'127.0.0.1' identified by "${password}"; EOF fi diff --git a/compute/src/main/java/org/zstack/compute/host/HostSystemTags.java b/compute/src/main/java/org/zstack/compute/host/HostSystemTags.java index 8de3693633..f5a061c378 100755 --- a/compute/src/main/java/org/zstack/compute/host/HostSystemTags.java +++ b/compute/src/main/java/org/zstack/compute/host/HostSystemTags.java @@ -109,4 +109,7 @@ public class HostSystemTags { public static String DEPLOY_MODE_TOKEN = "deployMode"; public static PatternedSystemTag DEPLOY_MODE = new PatternedSystemTag(String.format("deployMode::{%s}", DEPLOY_MODE_TOKEN), HostVO.class); + + public static String HYGON_MDEV_MAX_QEMU_NUM_TOKEN = "hygonMdevMaxQemuNum"; + public static PatternedSystemTag HYGON_MDEV_MAX_QEMU_NUM = new PatternedSystemTag(String.format("hygonMdevMaxQemuNum::{%s}", HYGON_MDEV_MAX_QEMU_NUM_TOKEN), HostVO.class); } diff --git a/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java b/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java index 1c4834f937..68c50b7947 100755 --- a/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java +++ b/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java @@ -7368,6 +7368,10 @@ public DiskOfferingVO call(DiskOfferingVO arg) { getTokenByResourceUuid(self.getUuid(), VmSystemTags.CONSOLE_PASSWORD_TOKEN)); spec.setUsbRedirect(Boolean.parseBoolean(VmSystemTags.USB_REDIRECT.getTokenByResourceUuid(self.getUuid(), VmSystemTags.USB_REDIRECT_TOKEN))); spec.setEnableSecurityElement(Boolean.parseBoolean(VmSystemTags.SECURITY_ELEMENT_ENABLE.getTokenByResourceUuid(self.getUuid(), VmSystemTags.SECURITY_ELEMENT_ENABLE_TOKEN))); + String hygonToken = VmSystemTags.HYGON_SECURITY_ELEMENT_ENABLE.getTokenByResourceUuid(self.getUuid(), VmSystemTags.HYGON_SECURITY_ELEMENT_ENABLE_TOKEN); + if (StringUtils.isNotBlank(hygonToken) && "true".equalsIgnoreCase(hygonToken)) { + spec.setEnableHygonSecurityElement(Boolean.TRUE); + } if (struct.getStrategy() == VmCreationStrategy.CreateStopped || struct.getStrategy() == VmCreationStrategy.CreatedPaused) { spec.setCreatePaused(true); } @@ -7852,12 +7856,17 @@ public String call(VmNicInventory arg) { } spec.setCurrentVmOperation(operation); + selectBootOrder(spec); spec.setConsolePassword(VmSystemTags.CONSOLE_PASSWORD. getTokenByResourceUuid(self.getUuid(), VmSystemTags.CONSOLE_PASSWORD_TOKEN)); spec.setVDIMonitorNumber(VmSystemTags.VDI_MONITOR_NUMBER.getTokenByResourceUuid(self.getUuid(), VmSystemTags.VDI_MONITOR_NUMBER_TOKEN)); spec.setUsbRedirect(Boolean.parseBoolean(VmSystemTags.USB_REDIRECT.getTokenByResourceUuid(self.getUuid(), VmSystemTags.USB_REDIRECT_TOKEN))); spec.setEnableSecurityElement(Boolean.parseBoolean(VmSystemTags.SECURITY_ELEMENT_ENABLE.getTokenByResourceUuid(self.getUuid(), VmSystemTags.SECURITY_ELEMENT_ENABLE_TOKEN))); + String hygonToken = VmSystemTags.HYGON_SECURITY_ELEMENT_ENABLE.getTokenByResourceUuid(self.getUuid(), VmSystemTags.HYGON_SECURITY_ELEMENT_ENABLE_TOKEN); + if (StringUtils.isNotBlank(hygonToken) && "true".equalsIgnoreCase(hygonToken)) { + spec.setEnableHygonSecurityElement(Boolean.TRUE); + } for (BuildVmSpecExtensionPoint ext : pluginRgty.getExtensionList(BuildVmSpecExtensionPoint.class)) { ext.afterBuildVmSpec(spec); diff --git a/compute/src/main/java/org/zstack/compute/vm/VmInstanceManagerImpl.java b/compute/src/main/java/org/zstack/compute/vm/VmInstanceManagerImpl.java index 8ed1ba2e94..db203212e8 100755 --- a/compute/src/main/java/org/zstack/compute/vm/VmInstanceManagerImpl.java +++ b/compute/src/main/java/org/zstack/compute/vm/VmInstanceManagerImpl.java @@ -2078,18 +2078,18 @@ private void validateL3NetworkAttachSecurityGroup(String l3Uuid, List se VmSystemTags.L3_NETWORK_SECURITY_GROUP_UUIDS_REF.installValidator(validator); } - private void installSeDeviceValidator() { - VmSystemTags.SECURITY_ELEMENT_ENABLE.installValidator(new SystemTagValidator() { + private void installBooleanTagValidator(PatternedSystemTag tag, String tokenName, String tagDescription) { + tag.installValidator(new SystemTagValidator() { @Override public void validateSystemTag(String resourceUuid, Class resourceType, String systemTag) { - String SecurityElementEnableTokenByTag = null; - if (VmSystemTags.SECURITY_ELEMENT_ENABLE.isMatch(systemTag)) { - SecurityElementEnableTokenByTag = VmSystemTags.SECURITY_ELEMENT_ENABLE.getTokenByTag(systemTag, VmSystemTags.SECURITY_ELEMENT_ENABLE_TOKEN); + String tokenValue = null; + if (tag.isMatch(systemTag)) { + tokenValue = tag.getTokenByTag(systemTag, tokenName); } else { - throw new OperationFailureException(argerr("invalid securityElementEnable[%s], %s is not securityElementEnable tag", systemTag, SecurityElementEnableTokenByTag)); + throw new OperationFailureException(argerr("invalid %s tag[%s]", tagDescription, systemTag)); } - if (!isBoolean(SecurityElementEnableTokenByTag)) { - throw new OperationFailureException(argerr("invalid securityElementEnable[%s], %s is not boolean class", systemTag, SecurityElementEnableTokenByTag)); + if (!isBoolean(tokenValue)) { + throw new OperationFailureException(argerr("invalid %s[%s], value [%s] is not boolean", tagDescription, systemTag, tokenValue)); } } private boolean isBoolean(String param) { @@ -2098,6 +2098,18 @@ private boolean isBoolean(String param) { }); } + private void installSeDeviceValidator() { + installBooleanTagValidator(VmSystemTags.SECURITY_ELEMENT_ENABLE, + VmSystemTags.SECURITY_ELEMENT_ENABLE_TOKEN, + "securityElementEnable"); + } + + private void installHygonSeDeviceValidator() { + installBooleanTagValidator(VmSystemTags.HYGON_SECURITY_ELEMENT_ENABLE, + VmSystemTags.HYGON_SECURITY_ELEMENT_ENABLE_TOKEN, + "hygonSecurityElementEnable"); + } + private void installSystemTagValidator() { installHostnameValidator(); installUserdataValidator(); @@ -2107,6 +2119,7 @@ private void installSystemTagValidator() { installUsbRedirectValidator(); installL3NetworkSecurityGroupValidator(); installSeDeviceValidator(); + installHygonSeDeviceValidator(); new StaticIpOperator().installStaticIpValidator(); } private void installUsbRedirectValidator() { diff --git a/compute/src/main/java/org/zstack/compute/vm/VmSystemTags.java b/compute/src/main/java/org/zstack/compute/vm/VmSystemTags.java index 21c9668175..713c64890e 100755 --- a/compute/src/main/java/org/zstack/compute/vm/VmSystemTags.java +++ b/compute/src/main/java/org/zstack/compute/vm/VmSystemTags.java @@ -99,6 +99,10 @@ public class VmSystemTags { public static String SECURITY_ELEMENT_ENABLE_TOKEN = "securityElementEnable"; public static PatternedSystemTag SECURITY_ELEMENT_ENABLE = new PatternedSystemTag(String.format("securityElementEnable::{%s}", SECURITY_ELEMENT_ENABLE_TOKEN),VmInstanceVO.class); + // set hygonSecurityElementEnable::true to enable hygon se redirect + public static String HYGON_SECURITY_ELEMENT_ENABLE_TOKEN = "hygonSecurityElementEnable"; + public static PatternedSystemTag HYGON_SECURITY_ELEMENT_ENABLE = new PatternedSystemTag(String.format("hygonSecurityElementEnable::{%s}", HYGON_SECURITY_ELEMENT_ENABLE_TOKEN),VmInstanceVO.class); + // set rdpEnable::true to enable RDP tag public static String RDP_ENABLE_TOKEN = "RDPEnable"; public static PatternedSystemTag RDP_ENABLE = new PatternedSystemTag(String.format("RDPEnable::{%s}",RDP_ENABLE_TOKEN),VmInstanceVO.class); diff --git a/conf/db/upgrade/V5.5.0__schema.sql b/conf/db/upgrade/V5.5.0__schema.sql index a0bad3311c..cc9ca4ddda 100644 --- a/conf/db/upgrade/V5.5.0__schema.sql +++ b/conf/db/upgrade/V5.5.0__schema.sql @@ -69,3 +69,55 @@ DELIMITER ; CALL UpdateVolumeInstallPathForZbs(); ALTER TABLE `zstack`.`ExternalPrimaryStorageVO` MODIFY `addonInfo` TEXT DEFAULT NULL; + +-- ----------------------------------- +-- BEGIN OF HYGON CCP DEVICE VIRTUALIZATION +-- ----------------------------------- +CREATE TABLE IF NOT EXISTS `zstack`.`HygonCcpDeviceVO` ( + `uuid` varchar(32) NOT NULL UNIQUE COMMENT 'uuid', + `name` varchar(255) NOT NULL, + `description` text DEFAULT NULL, + `hostUuid` varchar(32) NOT NULL, + `pciBdf` varchar(32) NOT NULL, + `deviceType` varchar(32) NOT NULL, + `deviceId` varchar(32) NOT NULL, + `driverStatus` varchar(32) NOT NULL, + `isMasterPsp` tinyint(1) DEFAULT 0, + `vendorIdx` INT DEFAULT NULL, + `state` varchar(32) NOT NULL, + `lastOpDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP, + `createDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + PRIMARY KEY (`uuid`), + INDEX `idxHygonCCPDeviceVOhostUuid` (`hostUuid`), + INDEX `idxHygonCCPDeviceVOdeviceType` (`deviceType`), + INDEX `idxHygonCCPDeviceVOpciBdf` (`pciBdf`), + CONSTRAINT `fkHygonCCPDeviceVOHostEO` FOREIGN KEY (`hostUuid`) REFERENCES `zstack`.`HostEO` (`uuid`) ON DELETE CASCADE + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `zstack`.`HygonCcpMdevVO` ( + `uuid` varchar(32) NOT NULL UNIQUE, + `name` varchar(128) NOT NULL, + `description` text DEFAULT NULL, + `hostUuid` varchar(32) NOT NULL, + `ccpDeviceUuid` varchar(32) NOT NULL, + `mdevUuid` varchar(64) NOT NULL UNIQUE, + `vendorIdx` INT DEFAULT NULL, + `useFlag` tinyint(1) NOT NULL DEFAULT 0, + `vmInstanceUuid` varchar(32) DEFAULT NULL, + `status` varchar(32) NOT NULL, + `state` varchar(32) NOT NULL, + `lastOpDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP, + `createDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + PRIMARY KEY (`uuid`), + INDEX `idxHygonCcpMdevVOhostUuid` (`hostUuid`), + INDEX `idxHygonCcpMdevVOccpDeviceUuid` (`ccpDeviceUuid`), + INDEX `idxHygonCcpMdevVOmdevUuid` (`mdevUuid`), + INDEX `idxHygonCcpMdevVOvmInstanceUuid` (`vmInstanceUuid`), + INDEX `idxHygonCcpMdevVOuseFlag` (`useFlag`), + CONSTRAINT `fkHygonCcpMdevVOHostEO` FOREIGN KEY (`hostUuid`) REFERENCES `zstack`.`HostEO` (`uuid`) ON DELETE CASCADE, + CONSTRAINT `fkHygonCcpMdevVOHygonCCPDeviceVO` FOREIGN KEY (`ccpDeviceUuid`) REFERENCES `zstack`.`HygonCcpDeviceVO` (`uuid`) ON DELETE CASCADE, + CONSTRAINT `fkHygonCcpMdevVOVmInstanceEO` FOREIGN KEY (`vmInstanceUuid`) REFERENCES `zstack`.`VmInstanceEO` (`uuid`) ON DELETE SET NULL + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- --------------------------------- +-- END OF HYGON CCP DEVICE VIRTUALIZATION +-- --------------------------------- 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/vm/VmInstanceSpec.java b/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java index c182acd19c..7007c592ae 100755 --- a/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java +++ b/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java @@ -353,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 @@ -461,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; } 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 f15d44d9ce..606a572b25 100755 --- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java +++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java @@ -2317,6 +2317,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; } @@ -2520,6 +2523,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; } 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 423f982082..bf29073a46 100755 --- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java +++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java @@ -4521,6 +4521,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"); diff --git a/rest/src/main/resources/scripts/RestDocumentationGenerator.groovy b/rest/src/main/resources/scripts/RestDocumentationGenerator.groovy index 3bad534aa2..c11a35e40a 100755 --- a/rest/src/main/resources/scripts/RestDocumentationGenerator.groovy +++ b/rest/src/main/resources/scripts/RestDocumentationGenerator.groovy @@ -832,6 +832,7 @@ class RestDocumentationGenerator implements DocumentGenerator { && md.globalConfig.valueRange == "{true, false}") if (validatorString != null || !useBooleanValidator) { logger.info("valueRange of ${mdPath} is not latest") + logger.info("valueRange = ${md.globalConfig.valueRange} validatorString = ${validatorString}") flag = false } } diff --git a/sdk/src/main/java/SourceClassMap.java b/sdk/src/main/java/SourceClassMap.java index f741eb4d57..665630290f 100644 --- a/sdk/src/main/java/SourceClassMap.java +++ b/sdk/src/main/java/SourceClassMap.java @@ -445,6 +445,9 @@ public class SourceClassMap { put("org.zstack.header.zwatch.AuditDataV2", "org.zstack.sdk.AuditDataV2"); put("org.zstack.hybrid.account.HybridAccountInventory", "org.zstack.sdk.HybridAccountInventory"); put("org.zstack.hybrid.core.HybridType", "org.zstack.sdk.HybridType"); + put("org.zstack.hygon.HygonCcpDeviceInventory", "org.zstack.sdk.HygonCcpDeviceInventory"); + put("org.zstack.hygon.HygonDeviceState", "org.zstack.sdk.HygonDeviceState"); + put("org.zstack.hygon.HygonDeviceType", "org.zstack.sdk.HygonDeviceType"); put("org.zstack.iam2.api.APIGetIAM2VirtualIDAPIPermissionMsg$APIPermissionStruct", "org.zstack.sdk.iam2.api.APIPermissionStruct"); put("org.zstack.iam2.api.APIGetIAM2VirtualIDAPIPermissionReply$Permission", "org.zstack.sdk.iam2.api.Permission"); put("org.zstack.iam2.api.Attribute", "org.zstack.sdk.iam2.api.Attribute"); @@ -1104,6 +1107,9 @@ public class SourceClassMap { put("org.zstack.sdk.HybridEipAddressInventory", "org.zstack.header.hybrid.network.eip.HybridEipAddressInventory"); put("org.zstack.sdk.HybridEipStatus", "org.zstack.header.hybrid.network.eip.HybridEipStatus"); put("org.zstack.sdk.HybridType", "org.zstack.hybrid.core.HybridType"); + put("org.zstack.sdk.HygonCcpDeviceInventory", "org.zstack.hygon.HygonCcpDeviceInventory"); + put("org.zstack.sdk.HygonDeviceState", "org.zstack.hygon.HygonDeviceState"); + put("org.zstack.sdk.HygonDeviceType", "org.zstack.hygon.HygonDeviceType"); put("org.zstack.sdk.HypervisorVersionState", "org.zstack.kvm.hypervisor.datatype.HypervisorVersionState"); put("org.zstack.sdk.IPsecConnectionInventory", "org.zstack.ipsec.IPsecConnectionInventory"); put("org.zstack.sdk.IPsecL3NetworkRefInventory", "org.zstack.ipsec.IPsecL3NetworkRefInventory"); diff --git a/sdk/src/main/java/org/zstack/sdk/GenerateHygonMdevDevicesAction.java b/sdk/src/main/java/org/zstack/sdk/GenerateHygonMdevDevicesAction.java new file mode 100644 index 0000000000..32bf219601 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/GenerateHygonMdevDevicesAction.java @@ -0,0 +1,104 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class GenerateHygonMdevDevicesAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.GenerateHygonMdevDevicesResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String hostUuid; + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, numberRange = {1L,1024L}, noTrim = false) + public java.lang.Integer maxQemuNum; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.GenerateHygonMdevDevicesResult value = res.getResult(org.zstack.sdk.GenerateHygonMdevDevicesResult.class); + ret.value = value == null ? new org.zstack.sdk.GenerateHygonMdevDevicesResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "PUT"; + info.path = "/hygon-devices/{hostUuid}/actions"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "generateHygonMdevDevices"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/GenerateHygonMdevDevicesResult.java b/sdk/src/main/java/org/zstack/sdk/GenerateHygonMdevDevicesResult.java new file mode 100644 index 0000000000..e8ee3052e9 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/GenerateHygonMdevDevicesResult.java @@ -0,0 +1,7 @@ +package org.zstack.sdk; + + + +public class GenerateHygonMdevDevicesResult { + +} diff --git a/sdk/src/main/java/org/zstack/sdk/HygonCcpDeviceInventory.java b/sdk/src/main/java/org/zstack/sdk/HygonCcpDeviceInventory.java new file mode 100644 index 0000000000..fead1fac8f --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/HygonCcpDeviceInventory.java @@ -0,0 +1,112 @@ +package org.zstack.sdk; + +import org.zstack.sdk.HygonDeviceType; +import org.zstack.sdk.HygonDeviceState; + +public class HygonCcpDeviceInventory { + + public java.lang.String uuid; + public void setUuid(java.lang.String uuid) { + this.uuid = uuid; + } + public java.lang.String getUuid() { + return this.uuid; + } + + public java.lang.String name; + public void setName(java.lang.String name) { + this.name = name; + } + public java.lang.String getName() { + return this.name; + } + + public java.lang.String description; + public void setDescription(java.lang.String description) { + this.description = description; + } + public java.lang.String getDescription() { + return this.description; + } + + public java.lang.String hostUuid; + public void setHostUuid(java.lang.String hostUuid) { + this.hostUuid = hostUuid; + } + public java.lang.String getHostUuid() { + return this.hostUuid; + } + + public java.lang.String pciBdf; + public void setPciBdf(java.lang.String pciBdf) { + this.pciBdf = pciBdf; + } + public java.lang.String getPciBdf() { + return this.pciBdf; + } + + public HygonDeviceType deviceType; + public void setDeviceType(HygonDeviceType deviceType) { + this.deviceType = deviceType; + } + public HygonDeviceType getDeviceType() { + return this.deviceType; + } + + public java.lang.String deviceId; + public void setDeviceId(java.lang.String deviceId) { + this.deviceId = deviceId; + } + public java.lang.String getDeviceId() { + return this.deviceId; + } + + public java.lang.String driverStatus; + public void setDriverStatus(java.lang.String driverStatus) { + this.driverStatus = driverStatus; + } + public java.lang.String getDriverStatus() { + return this.driverStatus; + } + + public java.lang.Boolean isMasterPsp; + public void setIsMasterPsp(java.lang.Boolean isMasterPsp) { + this.isMasterPsp = isMasterPsp; + } + public java.lang.Boolean getIsMasterPsp() { + return this.isMasterPsp; + } + + public java.lang.Integer vendorIdx; + public void setVendorIdx(java.lang.Integer vendorIdx) { + this.vendorIdx = vendorIdx; + } + public java.lang.Integer getVendorIdx() { + return this.vendorIdx; + } + + public HygonDeviceState state; + public void setState(HygonDeviceState state) { + this.state = state; + } + public HygonDeviceState getState() { + return this.state; + } + + public java.sql.Timestamp createDate; + public void setCreateDate(java.sql.Timestamp createDate) { + this.createDate = createDate; + } + public java.sql.Timestamp getCreateDate() { + return this.createDate; + } + + public java.sql.Timestamp lastOpDate; + public void setLastOpDate(java.sql.Timestamp lastOpDate) { + this.lastOpDate = lastOpDate; + } + public java.sql.Timestamp getLastOpDate() { + return this.lastOpDate; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/HygonDeviceState.java b/sdk/src/main/java/org/zstack/sdk/HygonDeviceState.java new file mode 100644 index 0000000000..3e50b7c458 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/HygonDeviceState.java @@ -0,0 +1,6 @@ +package org.zstack.sdk; + +public enum HygonDeviceState { + Enabled, + Disabled, +} diff --git a/sdk/src/main/java/org/zstack/sdk/HygonDeviceType.java b/sdk/src/main/java/org/zstack/sdk/HygonDeviceType.java new file mode 100644 index 0000000000..2784ddf741 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/HygonDeviceType.java @@ -0,0 +1,6 @@ +package org.zstack.sdk; + +public enum HygonDeviceType { + NTBCCP, + PSPCCP, +} diff --git a/sdk/src/main/java/org/zstack/sdk/QueryHygonDeviceAction.java b/sdk/src/main/java/org/zstack/sdk/QueryHygonDeviceAction.java new file mode 100644 index 0000000000..e7526e87cd --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/QueryHygonDeviceAction.java @@ -0,0 +1,75 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class QueryHygonDeviceAction extends QueryAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.QueryHygonDeviceResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.QueryHygonDeviceResult value = res.getResult(org.zstack.sdk.QueryHygonDeviceResult.class); + ret.value = value == null ? new org.zstack.sdk.QueryHygonDeviceResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "GET"; + info.path = "/hygon-devices"; + info.needSession = true; + info.needPoll = false; + info.parameterName = ""; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/QueryHygonDeviceResult.java b/sdk/src/main/java/org/zstack/sdk/QueryHygonDeviceResult.java new file mode 100644 index 0000000000..7ec08b4948 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/QueryHygonDeviceResult.java @@ -0,0 +1,22 @@ +package org.zstack.sdk; + + + +public class QueryHygonDeviceResult { + public java.util.List inventories; + public void setInventories(java.util.List inventories) { + this.inventories = inventories; + } + public java.util.List getInventories() { + return this.inventories; + } + + public java.lang.Long total; + public void setTotal(java.lang.Long total) { + this.total = total; + } + public java.lang.Long getTotal() { + return this.total; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/SetVmInstanceHygonMdevAction.java b/sdk/src/main/java/org/zstack/sdk/SetVmInstanceHygonMdevAction.java new file mode 100644 index 0000000000..2e28156ae6 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/SetVmInstanceHygonMdevAction.java @@ -0,0 +1,104 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class SetVmInstanceHygonMdevAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.SetVmInstanceHygonMdevResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String uuid; + + @Param(required = true, validValues = {"true","false"}, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String hygonSecurityElementEnable; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.SetVmInstanceHygonMdevResult value = res.getResult(org.zstack.sdk.SetVmInstanceHygonMdevResult.class); + ret.value = value == null ? new org.zstack.sdk.SetVmInstanceHygonMdevResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "POST"; + info.path = "/vm-instances/{uuid}/hygon-mdev"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "params"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/SetVmInstanceHygonMdevResult.java b/sdk/src/main/java/org/zstack/sdk/SetVmInstanceHygonMdevResult.java new file mode 100644 index 0000000000..03b0c8ee04 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/SetVmInstanceHygonMdevResult.java @@ -0,0 +1,7 @@ +package org.zstack.sdk; + + + +public class SetVmInstanceHygonMdevResult { + +} diff --git a/sdk/src/main/java/org/zstack/sdk/UngenerateHygonMdevDevicesAction.java b/sdk/src/main/java/org/zstack/sdk/UngenerateHygonMdevDevicesAction.java new file mode 100644 index 0000000000..bb355602a1 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/UngenerateHygonMdevDevicesAction.java @@ -0,0 +1,101 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class UngenerateHygonMdevDevicesAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.UngenerateHygonMdevDevicesResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String hostUuid; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.UngenerateHygonMdevDevicesResult value = res.getResult(org.zstack.sdk.UngenerateHygonMdevDevicesResult.class); + ret.value = value == null ? new org.zstack.sdk.UngenerateHygonMdevDevicesResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "PUT"; + info.path = "/hygon-devices/{hostUuid}/actions"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "ungenerateHygonMdevDevices"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/UngenerateHygonMdevDevicesResult.java b/sdk/src/main/java/org/zstack/sdk/UngenerateHygonMdevDevicesResult.java new file mode 100644 index 0000000000..cd83aa57ea --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/UngenerateHygonMdevDevicesResult.java @@ -0,0 +1,7 @@ +package org.zstack.sdk; + + + +public class UngenerateHygonMdevDevicesResult { + +} diff --git a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy index 1fb130443c..deae4ea042 100644 --- a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy +++ b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy @@ -19997,6 +19997,33 @@ abstract class ApiHelper { } + def generateHygonMdevDevices(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.GenerateHygonMdevDevicesAction.class) Closure c) { + def a = new org.zstack.sdk.GenerateHygonMdevDevicesAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def generateMdevDevices(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.GenerateMdevDevicesAction.class) Closure c) { def a = new org.zstack.sdk.GenerateMdevDevicesAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -31239,6 +31266,35 @@ abstract class ApiHelper { } + def queryHygonDevice(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryHygonDeviceAction.class) Closure c) { + def a = new org.zstack.sdk.QueryHygonDeviceAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + a.conditions = a.conditions.collect { it.toString() } + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def queryIAM2LdapBinding(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryIAM2LdapBindingAction.class) Closure c) { def a = new org.zstack.sdk.QueryIAM2LdapBindingAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -39471,6 +39527,33 @@ abstract class ApiHelper { } + def setVmInstanceHygonMdev(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.SetVmInstanceHygonMdevAction.class) Closure c) { + def a = new org.zstack.sdk.SetVmInstanceHygonMdevAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def setVmMonitorNumber(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.SetVmMonitorNumberAction.class) Closure c) { def a = new org.zstack.sdk.SetVmMonitorNumberAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -41442,6 +41525,33 @@ abstract class ApiHelper { } + def ungenerateHygonMdevDevices(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UngenerateHygonMdevDevicesAction.class) Closure c) { + def a = new org.zstack.sdk.UngenerateHygonMdevDevicesAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def ungenerateMdevDevices(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UngenerateMdevDevicesAction.class) Closure c) { def a = new org.zstack.sdk.UngenerateMdevDevicesAction() a.sessionId = Test.currentEnvSpec?.session?.uuid From d30cc1c70757d55c549508800d18da9f0f571a82 Mon Sep 17 00:00:00 2001 From: zhangjianjun Date: Mon, 17 Nov 2025 18:37:27 +0800 Subject: [PATCH 47/48] [sdnHa]: add ha for sdn controller 1. add nfv inst group framework 2. add ha for sdn controller Resolves: ZSTAC-79204 Change-Id: I766b696461657977696c6b676d636f6f62637467 Signed-off-by: zhangjianjun --- build/pom.xml | 10 + .../SysComponentMemUsageExtensionPoint.java | 17 + .../compute/vm/VmNicQosConfigBackend.java | 9 + conf/db/upgrade/V5.5.0__schema.sql | 350 ++++++++++++ .../l3/L3NetworkUpdateExtensionPoint.java | 5 - .../l3/SdnControllerDisableDHCPMsg.java | 46 ++ .../l3/SdnControllerDisableDHCPReply.java | 6 + .../l3/SdnControllerEnableDHCPMsg.java | 26 + .../l3/SdnControllerEnableDHCPReply.java | 6 + .../l3/SdnControllerUpdateDHCPMsg.java | 37 ++ .../l3/SdnControllerUpdateDHCPReply.java | 6 + .../network/service/SdnControllerDhcp.java | 10 +- .../network/l2/L2NetworkApiInterceptor.java | 75 ++- .../zstack/network/l2/L2NoVlanNetwork.java | 57 +- .../org/zstack/network/l3/L3BasicNetwork.java | 122 ++-- .../network/l3/L3NetworkManagerImpl.java | 39 +- .../network/l3/NormalIpRangeFactory.java | 44 +- .../zstack/network/service/DhcpExtension.java | 61 +- .../zstack/appliancevm/ApplianceVmBase.java | 10 +- .../appliancevm/ApplianceVmFacadeImpl.java | 1 + .../appliancevm/ApplianceVmHaStatus.java | 3 +- .../ApplianceVmInventoryDoc_zh_cn.groovy | 24 + .../ApplianceVmSubTypeFactory.java | 2 + .../network/service/flat/FlatDhcpBackend.java | 27 +- .../java/org/zstack/kvm/KVMAgentCommands.java | 77 ++- .../main/java/org/zstack/kvm/KVMConstant.java | 4 + .../java/org/zstack/kvm/KVMGlobalConfig.java | 5 + .../src/main/java/org/zstack/kvm/KVMHost.java | 21 + .../SdnControllerApiInterceptor.java | 71 --- .../sdnController/SdnControllerBase.java | 42 ++ .../SdnControllerManagerImpl.java | 7 + .../h3cVcfc/H3cVcfcSdnController.java | 22 + .../header/SyncSdnControllerDataMsg.java | 22 + .../header/SyncSdnControllerDataReply.java | 7 + .../controller/SugonSdnController.java | 25 +- .../service/virtualrouter/VirtualRouter.java | 2 +- sdk/src/main/java/SourceClassMap.java | 26 + .../zstack/sdk/AddL3NetworkToGroupAction.java | 110 ++++ .../zstack/sdk/AddL3NetworkToGroupResult.java | 7 + .../sdk/AttachNfvInstToGroupAction.java | 104 ++++ .../sdk/AttachNfvInstToGroupResult.java | 14 + ...ChangeNfvInstGroupOperationModeAction.java | 104 ++++ ...ChangeNfvInstGroupOperationModeResult.java | 14 + .../org/zstack/sdk/CreateNfvInstAction.java | 122 ++++ .../zstack/sdk/CreateNfvInstGroupAction.java | 152 +++++ .../zstack/sdk/CreateNfvInstGroupResult.java | 14 + .../sdk/CreateNfvInstOfferingAction.java | 137 +++++ .../org/zstack/sdk/CreateNfvInstResult.java | 14 + .../zstack/sdk/DeleteNfvInstGroupAction.java | 104 ++++ .../zstack/sdk/DeleteNfvInstGroupResult.java | 7 + .../sdk/DetachNfvInstFromGroupAction.java | 104 ++++ .../sdk/DetachNfvInstFromGroupResult.java | 14 + .../main/java/org/zstack/sdk/FuncType.java | 5 + .../main/java/org/zstack/sdk/InstType.java | 7 + .../org/zstack/sdk/NfvInstClusterStatus.java | 12 + .../sdk/NfvInstGroupConfigTaskInventory.java | 71 +++ .../org/zstack/sdk/NfvInstGroupInventory.java | 210 +++++++ .../NfvInstGroupL3NetworkRefInventory.java | 71 +++ .../sdk/NfvInstGroupMonitorIpInventory.java | 47 ++ ...fvInstGroupNetworkServiceRefInventory.java | 55 ++ .../zstack/sdk/NfvInstGroupOperationMode.java | 6 + .../org/zstack/sdk/NfvInstGroupStatus.java | 9 + .../java/org/zstack/sdk/NfvInstInventory.java | 55 ++ .../zstack/sdk/NfvInstOfferingInventory.java | 31 ++ .../zstack/sdk/OvnControllerInventory.java | 15 + .../sdk/OvnControllerVmInstanceInventory.java | 18 +- .../sdk/ProvisionNfvInstConfigAction.java | 101 ++++ .../sdk/ProvisionNfvInstConfigResult.java | 14 + .../sdk/ProvisionNfvInstGroupAction.java | 101 ++++ .../sdk/ProvisionNfvInstGroupResult.java | 14 + .../org/zstack/sdk/QueryNfvInstAction.java | 75 +++ .../zstack/sdk/QueryNfvInstGroupAction.java | 75 +++ .../zstack/sdk/QueryNfvInstGroupResult.java | 22 + .../sdk/QueryNfvInstOfferingAction.java | 75 +++ .../sdk/QueryNfvInstOfferingResult.java | 22 + .../org/zstack/sdk/QueryNfvInstResult.java | 22 + .../zstack/sdk/QueryOvnControllerAction.java | 75 +++ .../zstack/sdk/QueryOvnControllerResult.java | 22 + .../QueryOvnControllerVmInstanceAction.java | 75 +++ .../QueryOvnControllerVmInstanceResult.java | 22 + .../zstack/sdk/ReconnectNfvInstAction.java | 101 ++++ .../zstack/sdk/ReconnectNfvInstResult.java | 14 + .../zstack/sdk/SyncNfvInstGroupAction.java | 101 ++++ .../zstack/sdk/SyncNfvInstGroupResult.java | 14 + .../zstack/sdk/UpdateNfvInstGroupAction.java | 107 ++++ .../zstack/sdk/UpdateNfvInstGroupResult.java | 14 + .../UpdateNfvInstProvisionConfigAction.java | 101 ++++ .../UpdateNfvInstProvisionConfigResult.java | 14 + .../java/org/zstack/testlib/ApiHelper.groovy | 523 ++++++++++++++++++ .../org/zstack/testlib/KVMSimulator.groovy | 16 + .../java/org/zstack/testlib/VipSpec.groovy | 57 ++ .../java/org/zstack/testlib/ZoneSpec.groovy | 9 + 92 files changed, 4482 insertions(+), 261 deletions(-) create mode 100644 compute/src/main/java/org/zstack/compute/allocator/SysComponentMemUsageExtensionPoint.java delete mode 100644 header/src/main/java/org/zstack/header/network/l3/L3NetworkUpdateExtensionPoint.java create mode 100644 header/src/main/java/org/zstack/header/network/l3/SdnControllerDisableDHCPMsg.java create mode 100644 header/src/main/java/org/zstack/header/network/l3/SdnControllerDisableDHCPReply.java create mode 100644 header/src/main/java/org/zstack/header/network/l3/SdnControllerEnableDHCPMsg.java create mode 100644 header/src/main/java/org/zstack/header/network/l3/SdnControllerEnableDHCPReply.java create mode 100644 header/src/main/java/org/zstack/header/network/l3/SdnControllerUpdateDHCPMsg.java create mode 100644 header/src/main/java/org/zstack/header/network/l3/SdnControllerUpdateDHCPReply.java create mode 100644 plugin/sdnController/src/main/java/org/zstack/sdnController/header/SyncSdnControllerDataMsg.java create mode 100644 plugin/sdnController/src/main/java/org/zstack/sdnController/header/SyncSdnControllerDataReply.java create mode 100644 sdk/src/main/java/org/zstack/sdk/AddL3NetworkToGroupAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/AddL3NetworkToGroupResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/AttachNfvInstToGroupAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/AttachNfvInstToGroupResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/ChangeNfvInstGroupOperationModeAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/ChangeNfvInstGroupOperationModeResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/CreateNfvInstAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/CreateNfvInstGroupAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/CreateNfvInstGroupResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/CreateNfvInstOfferingAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/CreateNfvInstResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/DeleteNfvInstGroupAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/DeleteNfvInstGroupResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/DetachNfvInstFromGroupAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/DetachNfvInstFromGroupResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/FuncType.java create mode 100644 sdk/src/main/java/org/zstack/sdk/InstType.java create mode 100644 sdk/src/main/java/org/zstack/sdk/NfvInstClusterStatus.java create mode 100644 sdk/src/main/java/org/zstack/sdk/NfvInstGroupConfigTaskInventory.java create mode 100644 sdk/src/main/java/org/zstack/sdk/NfvInstGroupInventory.java create mode 100644 sdk/src/main/java/org/zstack/sdk/NfvInstGroupL3NetworkRefInventory.java create mode 100644 sdk/src/main/java/org/zstack/sdk/NfvInstGroupMonitorIpInventory.java create mode 100644 sdk/src/main/java/org/zstack/sdk/NfvInstGroupNetworkServiceRefInventory.java create mode 100644 sdk/src/main/java/org/zstack/sdk/NfvInstGroupOperationMode.java create mode 100644 sdk/src/main/java/org/zstack/sdk/NfvInstGroupStatus.java create mode 100644 sdk/src/main/java/org/zstack/sdk/NfvInstInventory.java create mode 100644 sdk/src/main/java/org/zstack/sdk/NfvInstOfferingInventory.java create mode 100644 sdk/src/main/java/org/zstack/sdk/OvnControllerInventory.java create mode 100644 sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstConfigAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstConfigResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstGroupAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstGroupResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/QueryNfvInstAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/QueryNfvInstGroupAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/QueryNfvInstGroupResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/QueryNfvInstOfferingAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/QueryNfvInstOfferingResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/QueryNfvInstResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/QueryOvnControllerAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/QueryOvnControllerResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/QueryOvnControllerVmInstanceAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/QueryOvnControllerVmInstanceResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/ReconnectNfvInstAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/ReconnectNfvInstResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/SyncNfvInstGroupAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/SyncNfvInstGroupResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/UpdateNfvInstGroupAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/UpdateNfvInstGroupResult.java create mode 100644 sdk/src/main/java/org/zstack/sdk/UpdateNfvInstProvisionConfigAction.java create mode 100644 sdk/src/main/java/org/zstack/sdk/UpdateNfvInstProvisionConfigResult.java create mode 100644 testlib/src/main/java/org/zstack/testlib/VipSpec.groovy diff --git a/build/pom.xml b/build/pom.xml index 504841e00b..c2eb9f2cbb 100755 --- a/build/pom.xml +++ b/build/pom.xml @@ -495,6 +495,16 @@ vpc ${project.version} + + org.zstack + nfvInstGroup + ${project.version} + + + org.zstack + nfvInst + ${project.version} + org.zstack diff --git a/compute/src/main/java/org/zstack/compute/allocator/SysComponentMemUsageExtensionPoint.java b/compute/src/main/java/org/zstack/compute/allocator/SysComponentMemUsageExtensionPoint.java new file mode 100644 index 0000000000..8503295269 --- /dev/null +++ b/compute/src/main/java/org/zstack/compute/allocator/SysComponentMemUsageExtensionPoint.java @@ -0,0 +1,17 @@ +package org.zstack.compute.allocator; + +public interface SysComponentMemUsageExtensionPoint { + /** + * Retrieves the amount of huge page memory used by the system component (in byte). + * + * @return the number of byte of huge page memory in use + */ + long getHugePageMemoryUsage(String hostUuid); + + /** + * Retrieves the amount of normal memory used by the system component (in byte). + * + * @return the number of byte of normal memory in use + */ + long getNormalMemoryUsage(String hostUuid); +} diff --git a/compute/src/main/java/org/zstack/compute/vm/VmNicQosConfigBackend.java b/compute/src/main/java/org/zstack/compute/vm/VmNicQosConfigBackend.java index 422a4fa9d7..e00e4b0496 100644 --- a/compute/src/main/java/org/zstack/compute/vm/VmNicQosConfigBackend.java +++ b/compute/src/main/java/org/zstack/compute/vm/VmNicQosConfigBackend.java @@ -1,11 +1,20 @@ package org.zstack.compute.vm; +import java.util.List; + public interface VmNicQosConfigBackend { String getVmInstanceType(); void addNicQos(String vmUuid, String vmNicUuid, Long outboundBandwidth, Long inboundBandwidth); void deleteNicQos(String vmUuid, String vmNicUuid,String direction); VmNicQosStruct getNicQos(String vmUuid, String vmNicUuid); + /** + * Batch version: return QoS struct for provided NIC UUIDs in the same order. + */ + default List getNicQosBatch(List vmNicUuids) { + throw new UnsupportedOperationException("getNicQosBatch is not supported"); + } + void addVmQos(String vmUuid, Long outboundBandwidth, Long inboundBandwidth); void deleteVmQos(String vmUuid, String direction); VmNicQosStruct getVmQos(String vmUuid); diff --git a/conf/db/upgrade/V5.5.0__schema.sql b/conf/db/upgrade/V5.5.0__schema.sql index cc9ca4ddda..e76e26d5d7 100644 --- a/conf/db/upgrade/V5.5.0__schema.sql +++ b/conf/db/upgrade/V5.5.0__schema.sql @@ -121,3 +121,353 @@ CREATE TABLE IF NOT EXISTS `zstack`.`HygonCcpMdevVO` ( -- --------------------------------- -- END OF HYGON CCP DEVICE VIRTUALIZATION -- --------------------------------- + +CREATE TABLE IF NOT EXISTS `zstack`.`NfvInstOfferingVO` ( + `uuid` varchar(32) NOT NULL UNIQUE, + `managementNetworkUuid` varchar(32) NOT NULL, + `imageUuid` varchar(32) NOT NULL, + `zoneUuid` varchar(32) NOT NULL, + PRIMARY KEY (`uuid`), + CONSTRAINT fkNfvInstOfferingVOL3NetworkEO FOREIGN KEY (managementNetworkUuid) REFERENCES `zstack`.`L3NetworkEO` (uuid) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `zstack`.`NfvInstGroupVO` ( + `uuid` VARCHAR(32) NOT NULL UNIQUE, + `name` VARCHAR(255) NOT NULL, + `description` VARCHAR(2048) DEFAULT NULL, + `nfvInstOfferingUuid` VARCHAR(32) DEFAULT NULL, + `instType` VARCHAR(64) NOT NULL, + `funcType` VARCHAR(64) NOT NULL, + `configVersion` int unsigned DEFAULT 0, + `netOsDistro` VARCHAR(128) DEFAULT NULL, + `baseOsDistro` VARCHAR(128) DEFAULT NULL, + `status` VARCHAR(32) DEFAULT 'Initializing', + `statusDetail` VARCHAR(255) DEFAULT NULL, + `operationMode` VARCHAR(32) DEFAULT 'Normal', + `vipUuid` VARCHAR(32) DEFAULT NULL, + `ipv6VipUuid` VARCHAR(32) DEFAULT NULL, + `primaryStorageUuid` VARCHAR(32) DEFAULT NULL, + `primaryStoragePoolUuid` VARCHAR(32) DEFAULT NULL, + `clusterUuid` VARCHAR(32) DEFAULT NULL, + `zoneUuid` VARCHAR(32) DEFAULT NULL, + `lastOpDate` timestamp ON UPDATE CURRENT_TIMESTAMP, + `createDate` timestamp, + PRIMARY KEY (`uuid`), + CONSTRAINT `fkNfvInstGroupVONfvInstOfferingVO` FOREIGN KEY (`nfvInstOfferingUuid`) REFERENCES `zstack`.`NfvInstOfferingVO` (uuid) ON DELETE SET NULL, + CONSTRAINT `fkNfvInstGroupVOPrimaryStorageEO` FOREIGN KEY (`primaryStorageUuid`) REFERENCES `zstack`.`PrimaryStorageEO` (uuid) ON DELETE SET NULL, + CONSTRAINT `fkNfvInstGroupVOClusterEO` FOREIGN KEY (`clusterUuid`) REFERENCES `zstack`.`ClusterEO` (uuid) ON DELETE SET NULL, + CONSTRAINT `fkNfvInstGroupVOZoneEO` FOREIGN KEY (`zoneUuid`) REFERENCES `zstack`.`ZoneEO` (uuid) ON DELETE SET NULL, + KEY `idx_nfv_inst_group_status_mode` (`status`, `operationMode`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `zstack`.`NfvInstGroupMonitorIpVO` ( + `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT, + `nfvInstGroupUuid` varchar(32) NOT NULL, + `monitorIp` varchar(255) NOT NULL, + `createDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + `lastOpDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + CONSTRAINT fkNfvInstGroupMonitorIpVONfvInstGroupVO FOREIGN KEY (nfvInstGroupUuid) REFERENCES NfvInstGroupVO (uuid) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `zstack`.`NfvInstGroupNetworkServiceRefVO` ( + `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT, + `nfvInstGroupUuid` varchar(32) NOT NULL, + `networkServiceName` VARCHAR(255) NOT NULL, + `networkServiceUuid` varchar(32) NOT NULL, + `createDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + `lastOpDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + CONSTRAINT fkNfvInstGroupNetworkServiceRefVONfvInstGroupVO FOREIGN KEY (nfvInstGroupUuid) REFERENCES NfvInstGroupVO (uuid) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `zstack`.`NfvInstGroupL3NetworkRefVO` ( + `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT, + `nfvInstGroupUuid` varchar(32) NOT NULL, + `networkServiceUuid` VARCHAR(32) NOT NULL, + `l3NetworkUuid` varchar(32) NOT NULL, + `type` varchar(255) NOT NULL, + `createDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + `lastOpDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + CONSTRAINT fkNfvInstGroupL3NetworkRefVONfvInstGroupVO FOREIGN KEY (nfvInstGroupUuid) REFERENCES NfvInstGroupVO (uuid) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `zstack`.`NfvInstVO` ( + `uuid` varchar(32) NOT NULL UNIQUE, + `nfvInstGroupUuid` varchar(32) NOT NULL, + `configVersion` int unsigned NOT NULL DEFAULT 0, + `netOsDistro` VARCHAR(128) NOT NULL, + `baseOsDistro` VARCHAR(128) NOT NULL, + `clusterStatus` VARCHAR(32) DEFAULT 'Unknown', + `statusDetail` VARCHAR(255) DEFAULT NULL, + PRIMARY KEY (`uuid`), + CONSTRAINT fkNfvInstVONfvInstGroupVO FOREIGN KEY (nfvInstGroupUuid) REFERENCES NfvInstGroupVO (uuid) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `zstack`.`NfvInstMetaDataVO` ( + `uuid` varchar(32) NOT NULL UNIQUE, + `agentVersion` varchar(32) DEFAULT NULL, + `netOsVersion` varchar(32) DEFAULT NULL, + `baseOsVersion` varchar(32) DEFAULT NULL, + `kernelVersion` varchar(256) DEFAULT NULL, + PRIMARY KEY (`uuid`), + CONSTRAINT `fkNfvInstMetadataVONfvInstVO` FOREIGN KEY (`uuid`) REFERENCES `NfvInstVO` (`uuid`) ON UPDATE RESTRICT ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `zstack`.`NfvInstGroupConfigTaskVO` ( + `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT, + `nfvInstGroupUuid` varchar(32) NOT NULL, + `configVersion` int unsigned DEFAULT 0, + `serviceUuid` varchar(32) NOT NULL, + `taskName` VARCHAR(255) NOT NULL, + `path` VARCHAR(255) NOT NULL, + `taskData` text DEFAULT NULL, + `checkStatus` BOOLEAN DEFAULT FALSE, + PRIMARY KEY (`id`), + CONSTRAINT fkNfvInstGroupConfigTaskVONfvInstGroupVO FOREIGN KEY (nfvInstGroupUuid) REFERENCES NfvInstGroupVO (uuid) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CALL ADD_COLUMN('OvnControllerVmInstanceVO', 'nbClusterStatus', 'VARCHAR(32)', 1, 'Unknown'); +CALL ADD_COLUMN('OvnControllerVmInstanceVO', 'sbClusterStatus', 'VARCHAR(32)', 1, 'Unknown'); + +-- ======================================== +-- Upgrade OvnControllerVmOfferingVO and OvnControllerVmInstanceVO hierarchy +-- Only execute if NOT already upgraded +-- ======================================== + +DELIMITER $$ + +DROP PROCEDURE IF EXISTS upgrade_ovn_controller_to_nfv_inst$$ + +CREATE PROCEDURE upgrade_ovn_controller_to_nfv_inst() +BEGIN + DECLARE already_upgraded INT DEFAULT 0; + DECLARE has_management_network_column INT DEFAULT 0; + DECLARE offering_count INT DEFAULT 0; + DECLARE offering_migrated_count INT DEFAULT 0; + DECLARE instance_in_nfv_inst_count INT DEFAULT 0; + DECLARE instance_in_nfv_group_count INT DEFAULT 0; + + -- Check if upgrade has already been done by checking any of these conditions: + -- a. OvnControllerVmOfferingVO no longer has managementNetworkUuid column + SELECT COUNT(*) INTO has_management_network_column + FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = 'zstack' + AND TABLE_NAME = 'OvnControllerVmOfferingVO' + AND COLUMN_NAME = 'managementNetworkUuid'; + + IF has_management_network_column = 0 THEN + SET already_upgraded = 1; + END IF; + + -- b. Check if OvnControllerVmOfferingVO records exist in NfvInstOfferingVO + IF already_upgraded = 0 THEN + SELECT COUNT(*) INTO offering_count FROM OvnControllerVmOfferingVO; + + IF offering_count > 0 THEN + SELECT COUNT(*) INTO offering_migrated_count + FROM OvnControllerVmOfferingVO ovo + INNER JOIN NfvInstOfferingVO nivo ON ovo.uuid = nivo.uuid; + + IF offering_migrated_count = offering_count THEN + SET already_upgraded = 1; + END IF; + END IF; + END IF; + + -- c. Check if OvnControllerVmInstanceVO records exist in NfvInstVO + IF already_upgraded = 0 THEN + SELECT COUNT(*) INTO instance_in_nfv_inst_count + FROM OvnControllerVmInstanceVO ovi + INNER JOIN NfvInstVO niv ON ovi.uuid = niv.uuid; + + IF instance_in_nfv_inst_count > 0 THEN + SET already_upgraded = 1; + END IF; + END IF; + + -- d. Check if NfvInstGroupVO created for OvnControllerVmInstanceVO + IF already_upgraded = 0 THEN + SELECT COUNT(*) INTO instance_in_nfv_group_count + FROM OvnControllerVmInstanceVO ovi + INNER JOIN NfvInstVO niv ON ovi.uuid = niv.uuid + INNER JOIN NfvInstGroupVO nig ON niv.nfvInstGroupUuid = nig.uuid + WHERE nig.funcType = 'OVN_SDN_CONTROLLER'; + + IF instance_in_nfv_group_count > 0 THEN + SET already_upgraded = 1; + END IF; + END IF; + + -- If any condition is met, skip the upgrade + IF already_upgraded = 1 THEN + SELECT 'Upgrade already completed, skipping OVN Controller to NFV Instance migration' AS message; + ELSE + -- ======================================== + -- Step 1: Create NfvInstOfferingVO records for existing OvnControllerVmOfferingVO + -- This must be done BEFORE dropping columns to preserve data + -- ======================================== + INSERT INTO NfvInstOfferingVO (uuid, managementNetworkUuid, imageUuid, zoneUuid) + SELECT + ovo.uuid, + ovo.managementNetworkUuid, + ovo.imageUuid, + ovo.zoneUuid + FROM OvnControllerVmOfferingVO ovo + WHERE NOT EXISTS ( + SELECT 1 FROM NfvInstOfferingVO nivo WHERE nivo.uuid = ovo.uuid + ); + + -- ======================================== + -- Step 2: Now safe to drop foreign key from OvnControllerVmOfferingVO + -- (Columns will be dropped after procedure execution) + -- ======================================== + IF has_management_network_column > 0 THEN + -- Check if foreign key exists before dropping + IF EXISTS ( + SELECT 1 FROM information_schema.TABLE_CONSTRAINTS + WHERE TABLE_SCHEMA = 'zstack' + AND TABLE_NAME = 'OvnControllerVmOfferingVO' + AND CONSTRAINT_NAME = 'fkOvnControllerVmOfferingVOL3NetworkEO' + ) THEN + ALTER TABLE OvnControllerVmOfferingVO DROP FOREIGN KEY fkOvnControllerVmOfferingVOL3NetworkEO; + END IF; + END IF; + + -- ======================================== + -- Step 3: Create NfvInstGroupVO for each OvnControllerVmInstanceVO + -- ======================================== + + -- First, create a temporary table to store the mapping between instance UUID and generated group UUID + CREATE TEMPORARY TABLE IF NOT EXISTS temp_ovn_inst_group_mapping ( + inst_uuid VARCHAR(32) NOT NULL PRIMARY KEY, + group_uuid VARCHAR(32) NOT NULL, + group_name VARCHAR(255) NOT NULL + ); + + -- Generate random UUIDs for each OVN instance and store the mapping + INSERT INTO temp_ovn_inst_group_mapping (inst_uuid, group_uuid, group_name) + SELECT + ovn.uuid AS inst_uuid, + REPLACE(UUID(), '-', '') AS group_uuid, + LEFT(CONCAT('OVN-Controller-Group-', vm.name), 255) AS group_name + FROM OvnControllerVmInstanceVO ovn + INNER JOIN VmInstanceVO vm ON ovn.uuid = vm.uuid + WHERE NOT EXISTS ( + SELECT 1 FROM NfvInstGroupVO nfv_grp WHERE nfv_grp.uuid = ovn.uuid + ); + + -- Insert ResourceVO records for each NfvInstGroup + INSERT INTO ResourceVO (uuid, resourceName, resourceType, concreteResourceType) + SELECT + mapping.group_uuid AS uuid, + mapping.group_name AS resourceName, + 'NfvInstGroupVO' AS resourceType, + 'org.zstack.network.service.nfvinstgroup.NfvInstGroupVO' AS concreteResourceType + FROM temp_ovn_inst_group_mapping mapping + WHERE NOT EXISTS ( + SELECT 1 FROM ResourceVO res WHERE res.uuid = mapping.group_uuid + ); + + -- Insert NfvInstGroupVO records + INSERT INTO NfvInstGroupVO ( + uuid, + name, + description, + nfvInstOfferingUuid, + instType, + funcType, + configVersion, + netOsDistro, + baseOsDistro, + status, + operationMode, + vipUuid, + primaryStorageUuid, + clusterUuid, + zoneUuid, + createDate, + lastOpDate + ) + SELECT + mapping.group_uuid AS group_uuid, -- group uuid: randomly generated + mapping.group_name AS name, -- group name (limit to 255 chars) + CONCAT('Auto-created group for OVN controller ', vm.name) AS description, + ovn_off.uuid AS offering_uuid, -- nfvInstOfferingUuid + 'KVM' AS inst_type, -- instType + 'OVN_SDN_CONTROLLER' AS func_type, -- funcType + 0 AS config_version, -- configVersion + 'euler' AS net_os_distro, -- netOsDistro + 'euler' AS base_os_distro, -- baseOsDistro + 'Initializing' AS status, -- status + 'Normal' AS operation_mode, -- operationMode + NULL AS vip_uuid, -- vipUuid (will be set later if needed) + vol.primaryStorageUuid AS ps_uuid, -- primaryStorageUuid (from VolumeVO via rootVolumeUuid) + vm.clusterUuid AS cluster_uuid, -- clusterUuid + vm.zoneUuid AS zone_uuid, -- zoneUuid + vm.createDate AS create_date, -- createDate + vm.lastOpDate AS last_op_date -- lastOpDate + FROM temp_ovn_inst_group_mapping mapping + INNER JOIN OvnControllerVmInstanceVO ovn ON mapping.inst_uuid = ovn.uuid + INNER JOIN VmInstanceVO vm ON ovn.uuid = vm.uuid + LEFT JOIN VolumeVO vol ON vm.rootVolumeUuid = vol.uuid + LEFT JOIN OvnControllerVmOfferingVO ovn_off ON vm.instanceOfferingUuid = ovn_off.uuid + WHERE NOT EXISTS ( + SELECT 1 FROM NfvInstGroupVO nfv_grp WHERE nfv_grp.uuid = mapping.group_uuid + ); + + -- ======================================== + -- Step 4: Create NfvInstVO records for each OvnControllerVmInstanceVO + -- ======================================== + INSERT INTO NfvInstVO ( + uuid, + nfvInstGroupUuid, + configVersion, + netOsDistro, + baseOsDistro, + clusterStatus, + statusDetail + ) + SELECT + ovn.uuid AS inst_uuid, + mapping.group_uuid AS group_uuid, -- link to the group we created (using mapping) + 0 AS config_version, -- configVersion + 'euler' AS net_os_distro, -- netOsDistro (required field) + 'euler' AS base_os_distro, -- baseOsDistro (required field) + 'Unknown' AS cluster_status, -- clusterStatus + NULL AS status_detail -- statusDetail + FROM OvnControllerVmInstanceVO ovn + INNER JOIN temp_ovn_inst_group_mapping mapping ON ovn.uuid = mapping.inst_uuid + WHERE NOT EXISTS ( + SELECT 1 FROM NfvInstVO nfv WHERE nfv.uuid = ovn.uuid + ); + + -- Clean up temporary table + DROP TEMPORARY TABLE IF EXISTS temp_ovn_inst_group_mapping; + + SELECT 'OVN Controller to NFV Instance migration completed successfully' AS message; + + -- Drop columns after data migration (if not already dropped) + CALL DROP_COLUMN('OvnControllerVmOfferingVO', 'managementNetworkUuid'); + CALL DROP_COLUMN('OvnControllerVmOfferingVO', 'imageUuid'); + CALL DROP_COLUMN('OvnControllerVmOfferingVO', 'zoneUuid'); + END IF; +END$$ + +DELIMITER ; + +-- Execute the upgrade procedure +CALL upgrade_ovn_controller_to_nfv_inst(); + +-- Drop the procedure after execution +DROP PROCEDURE IF EXISTS upgrade_ovn_controller_to_nfv_inst; + +CREATE TABLE IF NOT EXISTS `OvnControllerVO` ( + `uuid` varchar(32) NOT NULL UNIQUE, + `remoteOvn` tinyint(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +INSERT IGNORE INTO OvnControllerVO (uuid, remoteOvn) +SELECT uuid, 0 FROM SdnControllerVO where vendorType = 'Ovn'; 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/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/ApplianceVmFacadeImpl.java b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmFacadeImpl.java index 871479f13a..4f760dde45 100755 --- a/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmFacadeImpl.java +++ b/plugin/applianceVm/src/main/java/org/zstack/appliancevm/ApplianceVmFacadeImpl.java @@ -648,6 +648,7 @@ 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); 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/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/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/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java b/plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java index 606a572b25..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; @@ -2309,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; @@ -2888,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 { @@ -4880,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<>(); } @@ -4895,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 f8a224c315..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"; 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 bf29073a46..c82a8ba8ae 100755 --- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java +++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java @@ -4366,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()); diff --git a/plugin/sdnController/src/main/java/org/zstack/sdnController/SdnControllerApiInterceptor.java b/plugin/sdnController/src/main/java/org/zstack/sdnController/SdnControllerApiInterceptor.java index 741a99cdb7..a9caed4b7e 100644 --- a/plugin/sdnController/src/main/java/org/zstack/sdnController/SdnControllerApiInterceptor.java +++ b/plugin/sdnController/src/main/java/org/zstack/sdnController/SdnControllerApiInterceptor.java @@ -15,9 +15,6 @@ import org.zstack.header.network.l3.L3NetworkVO; import org.zstack.header.network.l3.L3NetworkVO_; import org.zstack.header.network.sdncontroller.*; -import org.zstack.header.vm.APIAttachL3NetworkToVmMsg; -import org.zstack.header.vm.APIChangeVmNicNetworkMsg; -import org.zstack.header.vm.VmInstanceVO; import org.zstack.header.vm.VmNicVO; import org.zstack.network.l2.vxlan.vxlanNetwork.VxlanNetworkVO; import org.zstack.network.l2.vxlan.vxlanNetwork.VxlanNetworkVO_; @@ -61,8 +58,6 @@ public List getMessageClassToIntercept() { ret.add(APIAddVmNicToSecurityGroupMsg.class); ret.add(APISetVmNicSecurityGroupMsg.class); ret.add(APIAddSecurityGroupRuleMsg.class); - ret.add(APIAttachL3NetworkToVmMsg.class); - ret.add(APIChangeVmNicNetworkMsg.class); ret.add(APIPullSdnControllerTenantMsg.class); return ret; @@ -87,8 +82,6 @@ public APIMessage intercept(APIMessage msg) throws ApiMessageInterceptionExcepti validate((APISetVmNicSecurityGroupMsg) msg); } else if (msg instanceof APIAddSecurityGroupRuleMsg) { validate((APIAddSecurityGroupRuleMsg) msg); - } else if (msg instanceof APIChangeVmNicNetworkMsg) { - validate((APIChangeVmNicNetworkMsg) msg); } else if (msg instanceof APIPullSdnControllerTenantMsg) { validate((APIPullSdnControllerTenantMsg) msg); } else if (msg instanceof APIChangeSdnControllerMsg) { @@ -100,70 +93,6 @@ public APIMessage intercept(APIMessage msg) throws ApiMessageInterceptionExcepti return msg; } - private void validate(APIAttachL3NetworkToVmMsg msg) { - String sdnControlerUuid = L3NetworkHelper.getSdnControllerUuidFromL3Uuid(msg.getL3NetworkUuid()); - if (sdnControlerUuid == null) { - return; - } - - SdnControllerVO controllerVO = dbf.findByUuid(sdnControlerUuid, SdnControllerVO.class); - if (controllerVO == null) { - throw new ApiMessageInterceptionException(argerr("could not attach l3network to vm, " + - "because sdn controller[uuid:%s] is not find", sdnControlerUuid)); - } - - if (SdnControllerConstant.H3C_VCFC_CONTROLLER.equals(controllerVO.getVendorType()) && - SdnControllerConstant.H3C_VCFC_VENDOR_VERSION_V2.equals(controllerVO.getVendorVersion())) { - validateH3cTenantStatus(msg.getL3NetworkUuid(), sdnControlerUuid); - return; - } - - if (SdnControllerConstant.H3C_VCFC_CONTROLLER.equals(controllerVO.getVendorType())) { - return; - } - - VmInstanceVO vmVo = dbf.findByUuid(msg.getVmInstanceUuid(), VmInstanceVO.class); - boolean found = false; - for (SdnControllerHostRefVO ref : controllerVO.getHostRefVOS()) { - if (ref.getHostUuid().equals(vmVo.getHostUuid())) { - found = true; - break; - } - } - if (!found) { - throw new ApiMessageInterceptionException(argerr("could not attach l3network to vm, " + - "because host[uuid:%s] of vm is not attached to sdn controller[uuid:%s]", - vmVo.getHostUuid(), sdnControlerUuid)); - } - } - - private void validate(APIChangeVmNicNetworkMsg msg) { - String sdnControlerUuid = L3NetworkHelper.getSdnControllerUuidFromL3Uuid(msg.getDestL3NetworkUuid()); - if (sdnControlerUuid == null) { - return; - } - - SdnControllerVO controllerVO = dbf.findByUuid(sdnControlerUuid, SdnControllerVO.class); - if (controllerVO == null) { - throw new ApiMessageInterceptionException(argerr("could not change vmnic to l3network[uuid:%s], " + - "because sdn controller[uuid:%s] is not find", msg.getDestL3NetworkUuid(), sdnControlerUuid)); - } - - VmInstanceVO vmVo = dbf.findByUuid(msg.getVmInstanceUuid(), VmInstanceVO.class); - boolean found = false; - for (SdnControllerHostRefVO ref : controllerVO.getHostRefVOS()) { - if (ref.getHostUuid().equals(vmVo.getHostUuid())) { - found = true; - break; - } - } - if (!found) { - throw new ApiMessageInterceptionException(argerr("could not change vmnic to l3network[uuid:%s], " + - "because host[uuid:%s] of vm is not attached to sdn controller[uuid:%s]", - msg.getDestL3NetworkUuid(), vmVo.getHostUuid(), sdnControlerUuid)); - } - } - private void validate(APISetVmNicSecurityGroupMsg msg) { VmNicVO nicVO = dbf.findByUuid(msg.getVmNicUuid(), VmNicVO.class); String nicControllerUuid = L3NetworkHelper.getSdnControllerUuidFromL3Uuid(nicVO.getL3NetworkUuid()); diff --git a/plugin/sdnController/src/main/java/org/zstack/sdnController/SdnControllerBase.java b/plugin/sdnController/src/main/java/org/zstack/sdnController/SdnControllerBase.java index f4733f6a83..a193fded62 100644 --- a/plugin/sdnController/src/main/java/org/zstack/sdnController/SdnControllerBase.java +++ b/plugin/sdnController/src/main/java/org/zstack/sdnController/SdnControllerBase.java @@ -126,12 +126,54 @@ public void handleMessage(SdnControllerMessage msg) { handle((PullSdnControllerTenantMsg) msg); } else if (msg instanceof ReconnectSdnControllerMsg) { handle((ReconnectSdnControllerMsg) msg); + } else if (msg instanceof SyncSdnControllerDataMsg) { + handle((SyncSdnControllerDataMsg) msg); } else { SdnController controller = getSdnController(); controller.handleMessage(msg); } } + private void handle(SyncSdnControllerDataMsg msg) { + SyncSdnControllerDataReply reply = new SyncSdnControllerDataReply(); + // Run a sync chain that only syncs data, without touching connection status + thdf.chainSubmit(new ChainTask(reply) { + @Override + public String getSyncSignature() { + return getSdnControllerSignature(); + } + + @Override + public void run(SyncTaskChain chain) { + FlowChain flowChain = sdnMgr.getSyncChain(self); + flowChain.getData().put(SDN_CONTROLLER_UUID, self.getUuid()); + flowChain.setName(String.format("sync-sdn-controller-data-%s-%s", self.getUuid(), self.getName())); + + // Start the chain; flows in factory-provided chain should perform data sync operations + flowChain.done(new FlowDoneHandler(msg) { + @Override + public void handle(Map data) { + bus.reply(msg, reply); + chain.next(); + } + }).error(new FlowErrorHandler(msg) { + @Override + public void handle(ErrorCode errCode, Map data) { + SyncSdnControllerDataReply r = new SyncSdnControllerDataReply(); + r.setError(errCode); + bus.reply(msg, r); + chain.next(); + } + }).start(); + } + + @Override + public String getName() { + return String.format("sync-sdn-controller-data-%s", self.getUuid()); + } + }); + } + public void changeSdnControllerStatus(SdnControllerStatus status) { if (status == self.getStatus()) { return; diff --git a/plugin/sdnController/src/main/java/org/zstack/sdnController/SdnControllerManagerImpl.java b/plugin/sdnController/src/main/java/org/zstack/sdnController/SdnControllerManagerImpl.java index c9e939b63f..35bb7badea 100644 --- a/plugin/sdnController/src/main/java/org/zstack/sdnController/SdnControllerManagerImpl.java +++ b/plugin/sdnController/src/main/java/org/zstack/sdnController/SdnControllerManagerImpl.java @@ -637,6 +637,13 @@ public void preInstantiateVmResource(VmInstanceSpec spec, Completion completion) @Override public void preReleaseVmResource(VmInstanceSpec spec, Completion completion) { + // create/start/reboot vm failed, code will go here VmInstantiateResourcePreFlow.rollack() + // vm change image failed, + if (VmInstanceConstant.VmOperation.NewCreate != spec.getCurrentVmOperation()) { + completion.success(); + return; + } + if (spec.getL3Networks() == null || spec.getL3Networks().isEmpty()) { completion.success(); return; diff --git a/plugin/sdnController/src/main/java/org/zstack/sdnController/h3cVcfc/H3cVcfcSdnController.java b/plugin/sdnController/src/main/java/org/zstack/sdnController/h3cVcfc/H3cVcfcSdnController.java index f9afed355d..9ac04a5f08 100644 --- a/plugin/sdnController/src/main/java/org/zstack/sdnController/h3cVcfc/H3cVcfcSdnController.java +++ b/plugin/sdnController/src/main/java/org/zstack/sdnController/h3cVcfc/H3cVcfcSdnController.java @@ -15,6 +15,7 @@ import org.zstack.header.message.Message; import org.zstack.header.network.l2.APICreateL2NetworkMsg; import org.zstack.header.network.l2.L2NetworkInventory; +import org.zstack.header.network.l3.*; import org.zstack.header.network.sdncontroller.*; import org.zstack.header.rest.RESTFacade; import org.zstack.network.l2.vxlan.vxlanNetwork.L2VxlanNetworkInventory; @@ -221,6 +222,12 @@ public void handle(ErrorCode errCode, Map data) { public void handleMessage(SdnControllerMessage msg) { if (msg instanceof SdnControllerPingMsg) { handle((SdnControllerPingMsg)msg); + } else if (msg instanceof SdnControllerEnableDHCPMsg) { + handle((SdnControllerEnableDHCPMsg) msg); + } else if (msg instanceof SdnControllerDisableDHCPMsg) { + handle((SdnControllerDisableDHCPMsg) msg); + } else if (msg instanceof SdnControllerUpdateDHCPMsg) { + handle((SdnControllerUpdateDHCPMsg) msg); } else { bus.dealWithUnknownMessage((Message) msg); } @@ -499,6 +506,21 @@ public void getH3cControllerToken(Completion completion) { } } + void handle(SdnControllerEnableDHCPMsg msg) { + SdnControllerEnableDHCPReply reply = new SdnControllerEnableDHCPReply(); + bus.reply(msg, reply); + } + + void handle(SdnControllerDisableDHCPMsg msg) { + SdnControllerDisableDHCPReply reply = new SdnControllerDisableDHCPReply(); + bus.reply(msg, reply); + } + + void handle(SdnControllerUpdateDHCPMsg msg) { + SdnControllerUpdateDHCPReply reply = new SdnControllerUpdateDHCPReply(); + bus.reply(msg, reply); + } + void handle(SdnControllerPingMsg msg) { SdnControllerPingReply reply = new SdnControllerPingReply(); diff --git a/plugin/sdnController/src/main/java/org/zstack/sdnController/header/SyncSdnControllerDataMsg.java b/plugin/sdnController/src/main/java/org/zstack/sdnController/header/SyncSdnControllerDataMsg.java new file mode 100644 index 0000000000..299d71867d --- /dev/null +++ b/plugin/sdnController/src/main/java/org/zstack/sdnController/header/SyncSdnControllerDataMsg.java @@ -0,0 +1,22 @@ +package org.zstack.sdnController.header; + +import org.zstack.header.message.NeedReplyMessage; +import org.zstack.header.network.sdncontroller.SdnControllerMessage; + +public class SyncSdnControllerDataMsg extends NeedReplyMessage implements SdnControllerMessage { + private String controllerUuid; + + public String getControllerUuid() { + return controllerUuid; + } + + public void setControllerUuid(String controllerUuid) { + this.controllerUuid = controllerUuid; + } + + @Override + public String getSdnControllerUuid() { + return controllerUuid; + } +} + diff --git a/plugin/sdnController/src/main/java/org/zstack/sdnController/header/SyncSdnControllerDataReply.java b/plugin/sdnController/src/main/java/org/zstack/sdnController/header/SyncSdnControllerDataReply.java new file mode 100644 index 0000000000..eec719bfb5 --- /dev/null +++ b/plugin/sdnController/src/main/java/org/zstack/sdnController/header/SyncSdnControllerDataReply.java @@ -0,0 +1,7 @@ +package org.zstack.sdnController.header; + +import org.zstack.header.message.MessageReply; + +public class SyncSdnControllerDataReply extends MessageReply { +} + diff --git a/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/SugonSdnController.java b/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/SugonSdnController.java index 45a68537e3..ebcf1433be 100644 --- a/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/SugonSdnController.java +++ b/plugin/sugonSdnController/src/main/java/org/zstack/sugonSdnController/controller/SugonSdnController.java @@ -56,7 +56,30 @@ public SugonSdnController(SdnControllerVO vo) { @Override public void handleMessage(SdnControllerMessage msg) { - bus.dealWithUnknownMessage((Message) msg); + if (msg instanceof SdnControllerEnableDHCPMsg) { + handMessage((SdnControllerEnableDHCPMsg) msg); + } else if (msg instanceof SdnControllerDisableDHCPMsg) { + handMessage((SdnControllerDisableDHCPMsg) msg); + } else if (msg instanceof SdnControllerUpdateDHCPMsg) { + handMessage((SdnControllerUpdateDHCPMsg) msg); + } else { + bus.dealWithUnknownMessage((Message) msg); + } + } + + void handMessage(SdnControllerEnableDHCPMsg msg) { + SdnControllerEnableDHCPReply reply = new SdnControllerEnableDHCPReply(); + bus.reply(msg, reply); + } + + void handMessage(SdnControllerDisableDHCPMsg msg) { + SdnControllerDisableDHCPReply reply = new SdnControllerDisableDHCPReply(); + bus.reply(msg, reply); + } + + void handMessage(SdnControllerUpdateDHCPMsg msg) { + SdnControllerUpdateDHCPReply reply = new SdnControllerUpdateDHCPReply(); + bus.reply(msg, reply); } @Override diff --git a/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouter.java b/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouter.java index 32a4448b68..427a32cb6c 100755 --- a/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouter.java +++ b/plugin/virtualRouterProvider/src/main/java/org/zstack/network/service/virtualrouter/VirtualRouter.java @@ -141,7 +141,7 @@ protected FlowChain getProvisionConfigChain() { } @Override - protected List createAfterConnectNewCreatedVirtualRouterFlows() { + protected List createAfterConnectNewCreatedFlows() { List flows = new ArrayList<>(); flows.add(new TrackVirtualRouterVmFlow()); return flows; diff --git a/sdk/src/main/java/SourceClassMap.java b/sdk/src/main/java/SourceClassMap.java index 665630290f..4bbd9238f9 100644 --- a/sdk/src/main/java/SourceClassMap.java +++ b/sdk/src/main/java/SourceClassMap.java @@ -555,6 +555,7 @@ public class SourceClassMap { put("org.zstack.network.l2.vxlan.vxlanNetwork.L2VxlanNetworkInventory", "org.zstack.sdk.L2VxlanNetworkInventory"); put("org.zstack.network.l2.vxlan.vxlanNetworkPool.L2VxlanNetworkPoolInventory", "org.zstack.sdk.L2VxlanNetworkPoolInventory"); put("org.zstack.network.l2.vxlan.vxlanNetworkPool.VniRangeInventory", "org.zstack.sdk.VniRangeInventory"); + put("org.zstack.network.ovn.OvnControllerInventory", "org.zstack.sdk.OvnControllerInventory"); put("org.zstack.network.ovn.OvnControllerVmInstanceInventory", "org.zstack.sdk.OvnControllerVmInstanceInventory"); put("org.zstack.network.ovn.OvnControllerVmOfferingInventory", "org.zstack.sdk.OvnControllerVmOfferingInventory"); put("org.zstack.network.securitygroup.SecurityGroupIngressRuleTO", "org.zstack.sdk.SecurityGroupIngressRuleTO"); @@ -564,6 +565,14 @@ public class SourceClassMap { put("org.zstack.network.securitygroup.VmNicSecurityPolicyInventory", "org.zstack.sdk.VmNicSecurityPolicyInventory"); put("org.zstack.network.service.eip.EipInventory", "org.zstack.sdk.EipInventory"); put("org.zstack.network.service.flat.IpStatisticData", "org.zstack.sdk.IpStatisticData"); + put("org.zstack.network.service.header.nfvinstgroup.NfvInstClusterStatus", "org.zstack.sdk.NfvInstClusterStatus"); + put("org.zstack.network.service.header.nfvinstgroup.NfvInstGroupConfigTaskInventory", "org.zstack.sdk.NfvInstGroupConfigTaskInventory"); + put("org.zstack.network.service.header.nfvinstgroup.NfvInstGroupConstants$FuncType", "org.zstack.sdk.FuncType"); + put("org.zstack.network.service.header.nfvinstgroup.NfvInstGroupConstants$InstType", "org.zstack.sdk.InstType"); + put("org.zstack.network.service.header.nfvinstgroup.NfvInstGroupOperationMode", "org.zstack.sdk.NfvInstGroupOperationMode"); + put("org.zstack.network.service.header.nfvinstgroup.NfvInstGroupStatus", "org.zstack.sdk.NfvInstGroupStatus"); + put("org.zstack.network.service.header.nfvinstgroup.NfvInstInventory", "org.zstack.sdk.NfvInstInventory"); + put("org.zstack.network.service.header.nfvinstgroup.NfvInstOfferingInventory", "org.zstack.sdk.NfvInstOfferingInventory"); put("org.zstack.network.service.lb.APIChangeAccessControlListServerGroupEvent$LoadBalancerListerAcl", "org.zstack.sdk.LoadBalancerListerAcl"); put("org.zstack.network.service.lb.CertificateInventory", "org.zstack.sdk.CertificateInventory"); put("org.zstack.network.service.lb.LoadBalancerInventory", "org.zstack.sdk.LoadBalancerInventory"); @@ -575,6 +584,10 @@ public class SourceClassMap { put("org.zstack.network.service.lb.LoadBalancerServerGroupInventory", "org.zstack.sdk.LoadBalancerServerGroupInventory"); put("org.zstack.network.service.lb.LoadBalancerServerGroupServerIpInventory", "org.zstack.sdk.LoadBalancerServerGroupServerIpInventory"); put("org.zstack.network.service.lb.LoadBalancerServerGroupVmNicRefInventory", "org.zstack.sdk.LoadBalancerServerGroupVmNicRefInventory"); + put("org.zstack.network.service.nfvinstgroup.NfvInstGroupInventory", "org.zstack.sdk.NfvInstGroupInventory"); + put("org.zstack.network.service.nfvinstgroup.NfvInstGroupL3NetworkRefInventory", "org.zstack.sdk.NfvInstGroupL3NetworkRefInventory"); + put("org.zstack.network.service.nfvinstgroup.NfvInstGroupMonitorIpInventory", "org.zstack.sdk.NfvInstGroupMonitorIpInventory"); + put("org.zstack.network.service.nfvinstgroup.NfvInstGroupNetworkServiceRefInventory", "org.zstack.sdk.NfvInstGroupNetworkServiceRefInventory"); put("org.zstack.network.service.portforwarding.PortForwardingRuleInventory", "org.zstack.sdk.PortForwardingRuleInventory"); put("org.zstack.network.service.slb.SlbGroupInventory", "org.zstack.sdk.SlbGroupInventory"); put("org.zstack.network.service.slb.SlbGroupL3NetworkRefInventory", "org.zstack.sdk.SlbGroupL3NetworkRefInventory"); @@ -1063,6 +1076,7 @@ public class SourceClassMap { put("org.zstack.sdk.FlowCounter", "org.zstack.header.flowMeter.FlowCounter"); put("org.zstack.sdk.FlowMeterInventory", "org.zstack.header.flowMeter.FlowMeterInventory"); put("org.zstack.sdk.FreeIpInventory", "org.zstack.header.network.l3.FreeIpInventory"); + put("org.zstack.sdk.FuncType", "org.zstack.network.service.header.nfvinstgroup.NfvInstGroupConstants$FuncType"); put("org.zstack.sdk.GarbageCollectorInventory", "org.zstack.core.gc.GarbageCollectorInventory"); put("org.zstack.sdk.GlobalConfigInventory", "org.zstack.core.config.GlobalConfigInventory"); put("org.zstack.sdk.GlobalConfigOptions", "org.zstack.core.config.GlobalConfigOptions"); @@ -1131,6 +1145,7 @@ public class SourceClassMap { put("org.zstack.sdk.InfoSecSecretResourcePoolInventory", "org.zstack.crypto.securitymachine.thirdparty.infoSec.InfoSecSecretResourcePoolInventory"); put("org.zstack.sdk.InfoSecSecurityMachineInventory", "org.zstack.crypto.securitymachine.thirdparty.infoSec.InfoSecSecurityMachineInventory"); put("org.zstack.sdk.InputType", "org.zstack.abstraction.OptionType$InputType"); + put("org.zstack.sdk.InstType", "org.zstack.network.service.header.nfvinstgroup.NfvInstGroupConstants$InstType"); put("org.zstack.sdk.InstallPathRecycleInventory", "org.zstack.header.core.trash.InstallPathRecycleInventory"); put("org.zstack.sdk.InstanceOfferingInventory", "org.zstack.header.configuration.InstanceOfferingInventory"); put("org.zstack.sdk.InvocationRecord", "org.zstack.guesttools.InvocationRecord"); @@ -1253,6 +1268,16 @@ public class SourceClassMap { put("org.zstack.sdk.NetworkRouterFlowMeterRefInventory", "org.zstack.header.flowMeter.NetworkRouterFlowMeterRefInventory"); put("org.zstack.sdk.NetworkServiceL3NetworkRefInventory", "org.zstack.header.network.service.NetworkServiceL3NetworkRefInventory"); put("org.zstack.sdk.NetworkServiceProviderInventory", "org.zstack.header.network.service.NetworkServiceProviderInventory"); + put("org.zstack.sdk.NfvInstClusterStatus", "org.zstack.network.service.header.nfvinstgroup.NfvInstClusterStatus"); + put("org.zstack.sdk.NfvInstGroupConfigTaskInventory", "org.zstack.network.service.header.nfvinstgroup.NfvInstGroupConfigTaskInventory"); + put("org.zstack.sdk.NfvInstGroupInventory", "org.zstack.network.service.nfvinstgroup.NfvInstGroupInventory"); + put("org.zstack.sdk.NfvInstGroupL3NetworkRefInventory", "org.zstack.network.service.nfvinstgroup.NfvInstGroupL3NetworkRefInventory"); + put("org.zstack.sdk.NfvInstGroupMonitorIpInventory", "org.zstack.network.service.nfvinstgroup.NfvInstGroupMonitorIpInventory"); + put("org.zstack.sdk.NfvInstGroupNetworkServiceRefInventory", "org.zstack.network.service.nfvinstgroup.NfvInstGroupNetworkServiceRefInventory"); + put("org.zstack.sdk.NfvInstGroupOperationMode", "org.zstack.network.service.header.nfvinstgroup.NfvInstGroupOperationMode"); + put("org.zstack.sdk.NfvInstGroupStatus", "org.zstack.network.service.header.nfvinstgroup.NfvInstGroupStatus"); + put("org.zstack.sdk.NfvInstInventory", "org.zstack.network.service.header.nfvinstgroup.NfvInstInventory"); + put("org.zstack.sdk.NfvInstOfferingInventory", "org.zstack.network.service.header.nfvinstgroup.NfvInstOfferingInventory"); put("org.zstack.sdk.NginxRedirectRule", "org.zstack.ai.NginxRedirectRule"); put("org.zstack.sdk.NicTO", "org.zstack.kvm.KVMAgentCommands$NicTO"); put("org.zstack.sdk.NormalIpRangeInventory", "org.zstack.header.network.l3.NormalIpRangeInventory"); @@ -1279,6 +1304,7 @@ public class SourceClassMap { put("org.zstack.sdk.OvfOSInfo", "org.zstack.ovf.datatype.OvfOSInfo"); put("org.zstack.sdk.OvfSystemInfo", "org.zstack.ovf.datatype.OvfSystemInfo"); put("org.zstack.sdk.OvfVolumeInfo", "org.zstack.ovf.datatype.OvfVolumeInfo"); + put("org.zstack.sdk.OvnControllerInventory", "org.zstack.network.ovn.OvnControllerInventory"); put("org.zstack.sdk.OvnControllerVmInstanceInventory", "org.zstack.network.ovn.OvnControllerVmInstanceInventory"); put("org.zstack.sdk.OvnControllerVmOfferingInventory", "org.zstack.network.ovn.OvnControllerVmOfferingInventory"); put("org.zstack.sdk.PacketsForwardType", "org.zstack.vpcfirewall.entity.PacketsForwardType"); diff --git a/sdk/src/main/java/org/zstack/sdk/AddL3NetworkToGroupAction.java b/sdk/src/main/java/org/zstack/sdk/AddL3NetworkToGroupAction.java new file mode 100644 index 0000000000..6debe67663 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/AddL3NetworkToGroupAction.java @@ -0,0 +1,110 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class AddL3NetworkToGroupAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.AddL3NetworkToGroupResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String nfvInstGroupUuid; + + @Param(required = true, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String networkServiceUuid; + + @Param(required = true, nonempty = true, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String frontEndL3NetworkUuid; + + @Param(required = true, nonempty = true, nullElements = false, emptyString = true, noTrim = false) + public java.util.List backendL3NetworkUuids; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.AddL3NetworkToGroupResult value = res.getResult(org.zstack.sdk.AddL3NetworkToGroupResult.class); + ret.value = value == null ? new org.zstack.sdk.AddL3NetworkToGroupResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "POST"; + info.path = "/nfvinstgroup/group/{nfvInstGroupUuid}/service/{networkServiceUuid}"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "params"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/AddL3NetworkToGroupResult.java b/sdk/src/main/java/org/zstack/sdk/AddL3NetworkToGroupResult.java new file mode 100644 index 0000000000..1978cd77ee --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/AddL3NetworkToGroupResult.java @@ -0,0 +1,7 @@ +package org.zstack.sdk; + + + +public class AddL3NetworkToGroupResult { + +} diff --git a/sdk/src/main/java/org/zstack/sdk/AttachNfvInstToGroupAction.java b/sdk/src/main/java/org/zstack/sdk/AttachNfvInstToGroupAction.java new file mode 100644 index 0000000000..fd8e59ca2d --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/AttachNfvInstToGroupAction.java @@ -0,0 +1,104 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class AttachNfvInstToGroupAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.AttachNfvInstToGroupResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String groupUuid; + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String nfvInstUuid; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.AttachNfvInstToGroupResult value = res.getResult(org.zstack.sdk.AttachNfvInstToGroupResult.class); + ret.value = value == null ? new org.zstack.sdk.AttachNfvInstToGroupResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "PUT"; + info.path = "/nfvinstgroup/group/{groupUuid}/instances/{nfvInstUuid}/actions"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "attachNfvInstToGroup"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/AttachNfvInstToGroupResult.java b/sdk/src/main/java/org/zstack/sdk/AttachNfvInstToGroupResult.java new file mode 100644 index 0000000000..06f1ad1a31 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/AttachNfvInstToGroupResult.java @@ -0,0 +1,14 @@ +package org.zstack.sdk; + +import org.zstack.sdk.NfvInstGroupInventory; + +public class AttachNfvInstToGroupResult { + public NfvInstGroupInventory inventory; + public void setInventory(NfvInstGroupInventory inventory) { + this.inventory = inventory; + } + public NfvInstGroupInventory getInventory() { + return this.inventory; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/ChangeNfvInstGroupOperationModeAction.java b/sdk/src/main/java/org/zstack/sdk/ChangeNfvInstGroupOperationModeAction.java new file mode 100644 index 0000000000..216987116a --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/ChangeNfvInstGroupOperationModeAction.java @@ -0,0 +1,104 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class ChangeNfvInstGroupOperationModeAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.ChangeNfvInstGroupOperationModeResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String uuid; + + @Param(required = true, validValues = {"Normal","Maintenance"}, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String operationMode; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.ChangeNfvInstGroupOperationModeResult value = res.getResult(org.zstack.sdk.ChangeNfvInstGroupOperationModeResult.class); + ret.value = value == null ? new org.zstack.sdk.ChangeNfvInstGroupOperationModeResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "PUT"; + info.path = "/nfvinstgroup/group/{uuid}/actions"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "changeNfvInstGroupOperationMode"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/ChangeNfvInstGroupOperationModeResult.java b/sdk/src/main/java/org/zstack/sdk/ChangeNfvInstGroupOperationModeResult.java new file mode 100644 index 0000000000..8547853342 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/ChangeNfvInstGroupOperationModeResult.java @@ -0,0 +1,14 @@ +package org.zstack.sdk; + +import org.zstack.sdk.NfvInstGroupInventory; + +public class ChangeNfvInstGroupOperationModeResult { + public NfvInstGroupInventory inventory; + public void setInventory(NfvInstGroupInventory inventory) { + this.inventory = inventory; + } + public NfvInstGroupInventory getInventory() { + return this.inventory; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/CreateNfvInstAction.java b/sdk/src/main/java/org/zstack/sdk/CreateNfvInstAction.java new file mode 100644 index 0000000000..c120ee97ec --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/CreateNfvInstAction.java @@ -0,0 +1,122 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class CreateNfvInstAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.CreateNfvInstResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String name; + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String nfvInstGroupUuid; + + @Param(required = false, maxLength = 2048, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String description; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String zoneUuid; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String clusterUuid; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String hostUuid; + + @Param(required = false) + public java.lang.String resourceUuid; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.util.List tagUuids; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.CreateNfvInstResult value = res.getResult(org.zstack.sdk.CreateNfvInstResult.class); + ret.value = value == null ? new org.zstack.sdk.CreateNfvInstResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "POST"; + info.path = "/nfvinstgroup/inst"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "params"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/CreateNfvInstGroupAction.java b/sdk/src/main/java/org/zstack/sdk/CreateNfvInstGroupAction.java new file mode 100644 index 0000000000..3055d319f1 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/CreateNfvInstGroupAction.java @@ -0,0 +1,152 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class CreateNfvInstGroupAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.CreateNfvInstGroupResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String name; + + @Param(required = false, maxLength = 2048, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String description; + + @Param(required = true, validValues = {"KVM"}, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String instType; + + @Param(required = true, validValues = {"DEDICATED_SLB","OVN_SDN_CONTROLLER"}, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String funcType; + + @Param(required = false, nonempty = true, nullElements = false, emptyString = true, noTrim = false) + public java.util.List monitorIps; + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String nfvInstOfferingUuid; + + @Param(required = false, nonempty = true, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String frontEndL3NetworkUuid; + + @Param(required = false, nonempty = true, nullElements = false, emptyString = true, noTrim = false) + public java.util.List backendL3NetworkUuids; + + @Param(required = false, maxLength = 128, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String netOsDistro; + + @Param(required = false, maxLength = 128, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String baseOsDistro; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String vipUuid; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String ipv6VipUuid; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String primaryStorageUuid; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String primaryStoragePoolUuid; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String clusterUuid; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String zoneUuid; + + @Param(required = false) + public java.lang.String resourceUuid; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.util.List tagUuids; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.CreateNfvInstGroupResult value = res.getResult(org.zstack.sdk.CreateNfvInstGroupResult.class); + ret.value = value == null ? new org.zstack.sdk.CreateNfvInstGroupResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "POST"; + info.path = "/nfvinstgroup/group"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "params"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/CreateNfvInstGroupResult.java b/sdk/src/main/java/org/zstack/sdk/CreateNfvInstGroupResult.java new file mode 100644 index 0000000000..906a877947 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/CreateNfvInstGroupResult.java @@ -0,0 +1,14 @@ +package org.zstack.sdk; + +import org.zstack.sdk.NfvInstGroupInventory; + +public class CreateNfvInstGroupResult { + public NfvInstGroupInventory inventory; + public void setInventory(NfvInstGroupInventory inventory) { + this.inventory = inventory; + } + public NfvInstGroupInventory getInventory() { + return this.inventory; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/CreateNfvInstOfferingAction.java b/sdk/src/main/java/org/zstack/sdk/CreateNfvInstOfferingAction.java new file mode 100644 index 0000000000..33267766ff --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/CreateNfvInstOfferingAction.java @@ -0,0 +1,137 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class CreateNfvInstOfferingAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.CreateInstanceOfferingResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String zoneUuid; + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String managementNetworkUuid; + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String imageUuid; + + @Param(required = true, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String name; + + @Param(required = false, maxLength = 2048, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String description; + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, numberRange = {1L,1024L}, noTrim = false) + public int cpuNum = 0; + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, numberRange = {1L,9223372036854775807L}, numberRangeUnit = {"byte", "bytes"}, noTrim = false) + public long memorySize = 0L; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, numberRange = {0L,9223372036854775807L}, numberRangeUnit = {"byte", "bytes"}, noTrim = false) + public long reservedMemorySize = 0L; + + @Param(required = false) + public java.lang.String allocatorStrategy; + + @Param(required = false) + public int sortKey = 0; + + @Param(required = false) + public java.lang.String type; + + @Param(required = false) + public java.lang.String resourceUuid; + + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.util.List tagUuids; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.CreateInstanceOfferingResult value = res.getResult(org.zstack.sdk.CreateInstanceOfferingResult.class); + ret.value = value == null ? new org.zstack.sdk.CreateInstanceOfferingResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "POST"; + info.path = "/instance-offerings/nfvinst"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "params"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/CreateNfvInstResult.java b/sdk/src/main/java/org/zstack/sdk/CreateNfvInstResult.java new file mode 100644 index 0000000000..adf8ae3f1a --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/CreateNfvInstResult.java @@ -0,0 +1,14 @@ +package org.zstack.sdk; + +import org.zstack.sdk.NfvInstInventory; + +public class CreateNfvInstResult { + public NfvInstInventory inventory; + public void setInventory(NfvInstInventory inventory) { + this.inventory = inventory; + } + public NfvInstInventory getInventory() { + return this.inventory; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/DeleteNfvInstGroupAction.java b/sdk/src/main/java/org/zstack/sdk/DeleteNfvInstGroupAction.java new file mode 100644 index 0000000000..87d07827ae --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/DeleteNfvInstGroupAction.java @@ -0,0 +1,104 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class DeleteNfvInstGroupAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.DeleteNfvInstGroupResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String uuid; + + @Param(required = false) + public java.lang.String deleteMode = "Permissive"; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.DeleteNfvInstGroupResult value = res.getResult(org.zstack.sdk.DeleteNfvInstGroupResult.class); + ret.value = value == null ? new org.zstack.sdk.DeleteNfvInstGroupResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "DELETE"; + info.path = "/nfvinstgroup/group/{uuid}"; + info.needSession = true; + info.needPoll = true; + info.parameterName = ""; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/DeleteNfvInstGroupResult.java b/sdk/src/main/java/org/zstack/sdk/DeleteNfvInstGroupResult.java new file mode 100644 index 0000000000..f453cb866a --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/DeleteNfvInstGroupResult.java @@ -0,0 +1,7 @@ +package org.zstack.sdk; + + + +public class DeleteNfvInstGroupResult { + +} diff --git a/sdk/src/main/java/org/zstack/sdk/DetachNfvInstFromGroupAction.java b/sdk/src/main/java/org/zstack/sdk/DetachNfvInstFromGroupAction.java new file mode 100644 index 0000000000..06a5eaebc7 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/DetachNfvInstFromGroupAction.java @@ -0,0 +1,104 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class DetachNfvInstFromGroupAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.DetachNfvInstFromGroupResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String groupUuid; + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String nfvInstUuid; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.DetachNfvInstFromGroupResult value = res.getResult(org.zstack.sdk.DetachNfvInstFromGroupResult.class); + ret.value = value == null ? new org.zstack.sdk.DetachNfvInstFromGroupResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "PUT"; + info.path = "/nfvinstgroup/group/{groupUuid}/instances/{nfvInstUuid}/actions"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "detachNfvInstFromGroup"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/DetachNfvInstFromGroupResult.java b/sdk/src/main/java/org/zstack/sdk/DetachNfvInstFromGroupResult.java new file mode 100644 index 0000000000..677e458513 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/DetachNfvInstFromGroupResult.java @@ -0,0 +1,14 @@ +package org.zstack.sdk; + +import org.zstack.sdk.NfvInstGroupInventory; + +public class DetachNfvInstFromGroupResult { + public NfvInstGroupInventory inventory; + public void setInventory(NfvInstGroupInventory inventory) { + this.inventory = inventory; + } + public NfvInstGroupInventory getInventory() { + return this.inventory; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/FuncType.java b/sdk/src/main/java/org/zstack/sdk/FuncType.java new file mode 100644 index 0000000000..51c1cd4f5d --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/FuncType.java @@ -0,0 +1,5 @@ +package org.zstack.sdk; + +public enum FuncType { + OVN_SDN_CONTROLLER, +} diff --git a/sdk/src/main/java/org/zstack/sdk/InstType.java b/sdk/src/main/java/org/zstack/sdk/InstType.java new file mode 100644 index 0000000000..401d988a3b --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/InstType.java @@ -0,0 +1,7 @@ +package org.zstack.sdk; + +public enum InstType { + KVM, + CONTAINER, + HOST, +} diff --git a/sdk/src/main/java/org/zstack/sdk/NfvInstClusterStatus.java b/sdk/src/main/java/org/zstack/sdk/NfvInstClusterStatus.java new file mode 100644 index 0000000000..f096486270 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/NfvInstClusterStatus.java @@ -0,0 +1,12 @@ +package org.zstack.sdk; + +public enum NfvInstClusterStatus { + Follower, + Candidate, + Leader, + Joining, + Leaving, + Unknown, + Available, + Unavailable, +} diff --git a/sdk/src/main/java/org/zstack/sdk/NfvInstGroupConfigTaskInventory.java b/sdk/src/main/java/org/zstack/sdk/NfvInstGroupConfigTaskInventory.java new file mode 100644 index 0000000000..eb1ef267ed --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/NfvInstGroupConfigTaskInventory.java @@ -0,0 +1,71 @@ +package org.zstack.sdk; + + + +public class NfvInstGroupConfigTaskInventory { + + public long id; + public void setId(long id) { + this.id = id; + } + public long getId() { + return this.id; + } + + public java.lang.String nfvInstGroupUuid; + public void setNfvInstGroupUuid(java.lang.String nfvInstGroupUuid) { + this.nfvInstGroupUuid = nfvInstGroupUuid; + } + public java.lang.String getNfvInstGroupUuid() { + return this.nfvInstGroupUuid; + } + + public int configVersion; + public void setConfigVersion(int configVersion) { + this.configVersion = configVersion; + } + public int getConfigVersion() { + return this.configVersion; + } + + public java.lang.String serviceUuid; + public void setServiceUuid(java.lang.String serviceUuid) { + this.serviceUuid = serviceUuid; + } + public java.lang.String getServiceUuid() { + return this.serviceUuid; + } + + public java.lang.String taskName; + public void setTaskName(java.lang.String taskName) { + this.taskName = taskName; + } + public java.lang.String getTaskName() { + return this.taskName; + } + + public java.lang.String taskData; + public void setTaskData(java.lang.String taskData) { + this.taskData = taskData; + } + public java.lang.String getTaskData() { + return this.taskData; + } + + public java.lang.String path; + public void setPath(java.lang.String path) { + this.path = path; + } + public java.lang.String getPath() { + return this.path; + } + + public boolean checkStatus; + public void setCheckStatus(boolean checkStatus) { + this.checkStatus = checkStatus; + } + public boolean getCheckStatus() { + return this.checkStatus; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/NfvInstGroupInventory.java b/sdk/src/main/java/org/zstack/sdk/NfvInstGroupInventory.java new file mode 100644 index 0000000000..ff44f5c5e3 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/NfvInstGroupInventory.java @@ -0,0 +1,210 @@ +package org.zstack.sdk; + +import org.zstack.sdk.InstType; +import org.zstack.sdk.FuncType; +import org.zstack.sdk.NfvInstGroupStatus; +import org.zstack.sdk.NfvInstGroupOperationMode; + +public class NfvInstGroupInventory { + + public java.lang.String name; + public void setName(java.lang.String name) { + this.name = name; + } + public java.lang.String getName() { + return this.name; + } + + public java.lang.String uuid; + public void setUuid(java.lang.String uuid) { + this.uuid = uuid; + } + public java.lang.String getUuid() { + return this.uuid; + } + + public java.lang.String description; + public void setDescription(java.lang.String description) { + this.description = description; + } + public java.lang.String getDescription() { + return this.description; + } + + public java.lang.String nfvInstOfferingUuid; + public void setNfvInstOfferingUuid(java.lang.String nfvInstOfferingUuid) { + this.nfvInstOfferingUuid = nfvInstOfferingUuid; + } + public java.lang.String getNfvInstOfferingUuid() { + return this.nfvInstOfferingUuid; + } + + public InstType instType; + public void setInstType(InstType instType) { + this.instType = instType; + } + public InstType getInstType() { + return this.instType; + } + + public FuncType funcType; + public void setFuncType(FuncType funcType) { + this.funcType = funcType; + } + public FuncType getFuncType() { + return this.funcType; + } + + public int configVersion; + public void setConfigVersion(int configVersion) { + this.configVersion = configVersion; + } + public int getConfigVersion() { + return this.configVersion; + } + + public java.lang.String netOsDistro; + public void setNetOsDistro(java.lang.String netOsDistro) { + this.netOsDistro = netOsDistro; + } + public java.lang.String getNetOsDistro() { + return this.netOsDistro; + } + + public java.lang.String baseOsDistro; + public void setBaseOsDistro(java.lang.String baseOsDistro) { + this.baseOsDistro = baseOsDistro; + } + public java.lang.String getBaseOsDistro() { + return this.baseOsDistro; + } + + public NfvInstGroupStatus status; + public void setStatus(NfvInstGroupStatus status) { + this.status = status; + } + public NfvInstGroupStatus getStatus() { + return this.status; + } + + public java.lang.String statusDetail; + public void setStatusDetail(java.lang.String statusDetail) { + this.statusDetail = statusDetail; + } + public java.lang.String getStatusDetail() { + return this.statusDetail; + } + + public NfvInstGroupOperationMode operationMode; + public void setOperationMode(NfvInstGroupOperationMode operationMode) { + this.operationMode = operationMode; + } + public NfvInstGroupOperationMode getOperationMode() { + return this.operationMode; + } + + public java.sql.Timestamp createDate; + public void setCreateDate(java.sql.Timestamp createDate) { + this.createDate = createDate; + } + public java.sql.Timestamp getCreateDate() { + return this.createDate; + } + + public java.sql.Timestamp lastOpDate; + public void setLastOpDate(java.sql.Timestamp lastOpDate) { + this.lastOpDate = lastOpDate; + } + public java.sql.Timestamp getLastOpDate() { + return this.lastOpDate; + } + + public java.util.List instances; + public void setInstances(java.util.List instances) { + this.instances = instances; + } + public java.util.List getInstances() { + return this.instances; + } + + public java.util.List monitors; + public void setMonitors(java.util.List monitors) { + this.monitors = monitors; + } + public java.util.List getMonitors() { + return this.monitors; + } + + public java.util.List services; + public void setServices(java.util.List services) { + this.services = services; + } + public java.util.List getServices() { + return this.services; + } + + public java.util.List configTasks; + public void setConfigTasks(java.util.List configTasks) { + this.configTasks = configTasks; + } + public java.util.List getConfigTasks() { + return this.configTasks; + } + + public java.util.List l3Networks; + public void setL3Networks(java.util.List l3Networks) { + this.l3Networks = l3Networks; + } + public java.util.List getL3Networks() { + return this.l3Networks; + } + + public java.lang.String vipUuid; + public void setVipUuid(java.lang.String vipUuid) { + this.vipUuid = vipUuid; + } + public java.lang.String getVipUuid() { + return this.vipUuid; + } + + public java.lang.String ipv6VipUuid; + public void setIpv6VipUuid(java.lang.String ipv6VipUuid) { + this.ipv6VipUuid = ipv6VipUuid; + } + public java.lang.String getIpv6VipUuid() { + return this.ipv6VipUuid; + } + + public java.lang.String primaryStorageUuid; + public void setPrimaryStorageUuid(java.lang.String primaryStorageUuid) { + this.primaryStorageUuid = primaryStorageUuid; + } + public java.lang.String getPrimaryStorageUuid() { + return this.primaryStorageUuid; + } + + public java.lang.String primaryStoragePoolUuid; + public void setPrimaryStoragePoolUuid(java.lang.String primaryStoragePoolUuid) { + this.primaryStoragePoolUuid = primaryStoragePoolUuid; + } + public java.lang.String getPrimaryStoragePoolUuid() { + return this.primaryStoragePoolUuid; + } + + public java.lang.String clusterUuid; + public void setClusterUuid(java.lang.String clusterUuid) { + this.clusterUuid = clusterUuid; + } + public java.lang.String getClusterUuid() { + return this.clusterUuid; + } + + public java.lang.String zoneUuid; + public void setZoneUuid(java.lang.String zoneUuid) { + this.zoneUuid = zoneUuid; + } + public java.lang.String getZoneUuid() { + return this.zoneUuid; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/NfvInstGroupL3NetworkRefInventory.java b/sdk/src/main/java/org/zstack/sdk/NfvInstGroupL3NetworkRefInventory.java new file mode 100644 index 0000000000..803c948a30 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/NfvInstGroupL3NetworkRefInventory.java @@ -0,0 +1,71 @@ +package org.zstack.sdk; + + + +public class NfvInstGroupL3NetworkRefInventory { + + public java.lang.String nfvInstGroupUuid; + public void setNfvInstGroupUuid(java.lang.String nfvInstGroupUuid) { + this.nfvInstGroupUuid = nfvInstGroupUuid; + } + public java.lang.String getNfvInstGroupUuid() { + return this.nfvInstGroupUuid; + } + + public java.lang.String networkServiceUuid; + public void setNetworkServiceUuid(java.lang.String networkServiceUuid) { + this.networkServiceUuid = networkServiceUuid; + } + public java.lang.String getNetworkServiceUuid() { + return this.networkServiceUuid; + } + + public java.lang.String l3NetworkUuid; + public void setL3NetworkUuid(java.lang.String l3NetworkUuid) { + this.l3NetworkUuid = l3NetworkUuid; + } + public java.lang.String getL3NetworkUuid() { + return this.l3NetworkUuid; + } + + public java.lang.String l3NetworkCategory; + public void setL3NetworkCategory(java.lang.String l3NetworkCategory) { + this.l3NetworkCategory = l3NetworkCategory; + } + public java.lang.String getL3NetworkCategory() { + return this.l3NetworkCategory; + } + + public java.lang.String l3NetworkType; + public void setL3NetworkType(java.lang.String l3NetworkType) { + this.l3NetworkType = l3NetworkType; + } + public java.lang.String getL3NetworkType() { + return this.l3NetworkType; + } + + public java.lang.String type; + public void setType(java.lang.String type) { + this.type = type; + } + public java.lang.String getType() { + return this.type; + } + + public java.sql.Timestamp createDate; + public void setCreateDate(java.sql.Timestamp createDate) { + this.createDate = createDate; + } + public java.sql.Timestamp getCreateDate() { + return this.createDate; + } + + public java.sql.Timestamp lastOpDate; + public void setLastOpDate(java.sql.Timestamp lastOpDate) { + this.lastOpDate = lastOpDate; + } + public java.sql.Timestamp getLastOpDate() { + return this.lastOpDate; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/NfvInstGroupMonitorIpInventory.java b/sdk/src/main/java/org/zstack/sdk/NfvInstGroupMonitorIpInventory.java new file mode 100644 index 0000000000..d6fe52906a --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/NfvInstGroupMonitorIpInventory.java @@ -0,0 +1,47 @@ +package org.zstack.sdk; + + + +public class NfvInstGroupMonitorIpInventory { + + public java.lang.Long id; + public void setId(java.lang.Long id) { + this.id = id; + } + public java.lang.Long getId() { + return this.id; + } + + public java.lang.String nfvInstGroupUuid; + public void setNfvInstGroupUuid(java.lang.String nfvInstGroupUuid) { + this.nfvInstGroupUuid = nfvInstGroupUuid; + } + public java.lang.String getNfvInstGroupUuid() { + return this.nfvInstGroupUuid; + } + + public java.lang.String monitorIp; + public void setMonitorIp(java.lang.String monitorIp) { + this.monitorIp = monitorIp; + } + public java.lang.String getMonitorIp() { + return this.monitorIp; + } + + public java.sql.Timestamp createDate; + public void setCreateDate(java.sql.Timestamp createDate) { + this.createDate = createDate; + } + public java.sql.Timestamp getCreateDate() { + return this.createDate; + } + + public java.sql.Timestamp lastOpDate; + public void setLastOpDate(java.sql.Timestamp lastOpDate) { + this.lastOpDate = lastOpDate; + } + public java.sql.Timestamp getLastOpDate() { + return this.lastOpDate; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/NfvInstGroupNetworkServiceRefInventory.java b/sdk/src/main/java/org/zstack/sdk/NfvInstGroupNetworkServiceRefInventory.java new file mode 100644 index 0000000000..43b5a53c68 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/NfvInstGroupNetworkServiceRefInventory.java @@ -0,0 +1,55 @@ +package org.zstack.sdk; + + + +public class NfvInstGroupNetworkServiceRefInventory { + + public java.lang.Long id; + public void setId(java.lang.Long id) { + this.id = id; + } + public java.lang.Long getId() { + return this.id; + } + + public java.lang.String nfvInstGroupUuid; + public void setNfvInstGroupUuid(java.lang.String nfvInstGroupUuid) { + this.nfvInstGroupUuid = nfvInstGroupUuid; + } + public java.lang.String getNfvInstGroupUuid() { + return this.nfvInstGroupUuid; + } + + public java.lang.String networkServiceName; + public void setNetworkServiceName(java.lang.String networkServiceName) { + this.networkServiceName = networkServiceName; + } + public java.lang.String getNetworkServiceName() { + return this.networkServiceName; + } + + public java.lang.String networkServiceUuid; + public void setNetworkServiceUuid(java.lang.String networkServiceUuid) { + this.networkServiceUuid = networkServiceUuid; + } + public java.lang.String getNetworkServiceUuid() { + return this.networkServiceUuid; + } + + public java.sql.Timestamp createDate; + public void setCreateDate(java.sql.Timestamp createDate) { + this.createDate = createDate; + } + public java.sql.Timestamp getCreateDate() { + return this.createDate; + } + + public java.sql.Timestamp lastOpDate; + public void setLastOpDate(java.sql.Timestamp lastOpDate) { + this.lastOpDate = lastOpDate; + } + public java.sql.Timestamp getLastOpDate() { + return this.lastOpDate; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/NfvInstGroupOperationMode.java b/sdk/src/main/java/org/zstack/sdk/NfvInstGroupOperationMode.java new file mode 100644 index 0000000000..1c692e49f1 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/NfvInstGroupOperationMode.java @@ -0,0 +1,6 @@ +package org.zstack.sdk; + +public enum NfvInstGroupOperationMode { + Normal, + Maintenance, +} diff --git a/sdk/src/main/java/org/zstack/sdk/NfvInstGroupStatus.java b/sdk/src/main/java/org/zstack/sdk/NfvInstGroupStatus.java new file mode 100644 index 0000000000..fc9c165afa --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/NfvInstGroupStatus.java @@ -0,0 +1,9 @@ +package org.zstack.sdk; + +public enum NfvInstGroupStatus { + Initializing, + Healthy, + Degraded, + Operating, + Unavailable, +} diff --git a/sdk/src/main/java/org/zstack/sdk/NfvInstInventory.java b/sdk/src/main/java/org/zstack/sdk/NfvInstInventory.java new file mode 100644 index 0000000000..d84863093a --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/NfvInstInventory.java @@ -0,0 +1,55 @@ +package org.zstack.sdk; + + + +public class NfvInstInventory extends org.zstack.sdk.ApplianceVmInventory { + + public int configVersion; + public void setConfigVersion(int configVersion) { + this.configVersion = configVersion; + } + public int getConfigVersion() { + return this.configVersion; + } + + public java.lang.String nfvInstGroupUuid; + public void setNfvInstGroupUuid(java.lang.String nfvInstGroupUuid) { + this.nfvInstGroupUuid = nfvInstGroupUuid; + } + public java.lang.String getNfvInstGroupUuid() { + return this.nfvInstGroupUuid; + } + + public java.lang.String netOsDistro; + public void setNetOsDistro(java.lang.String netOsDistro) { + this.netOsDistro = netOsDistro; + } + public java.lang.String getNetOsDistro() { + return this.netOsDistro; + } + + public java.lang.String baseOsDistro; + public void setBaseOsDistro(java.lang.String baseOsDistro) { + this.baseOsDistro = baseOsDistro; + } + public java.lang.String getBaseOsDistro() { + return this.baseOsDistro; + } + + public java.lang.String clusterStatus; + public void setClusterStatus(java.lang.String clusterStatus) { + this.clusterStatus = clusterStatus; + } + public java.lang.String getClusterStatus() { + return this.clusterStatus; + } + + public java.lang.String statusDetail; + public void setStatusDetail(java.lang.String statusDetail) { + this.statusDetail = statusDetail; + } + public java.lang.String getStatusDetail() { + return this.statusDetail; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/NfvInstOfferingInventory.java b/sdk/src/main/java/org/zstack/sdk/NfvInstOfferingInventory.java new file mode 100644 index 0000000000..42f92383fa --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/NfvInstOfferingInventory.java @@ -0,0 +1,31 @@ +package org.zstack.sdk; + + + +public class NfvInstOfferingInventory extends org.zstack.sdk.InstanceOfferingInventory { + + public java.lang.String managementNetworkUuid; + public void setManagementNetworkUuid(java.lang.String managementNetworkUuid) { + this.managementNetworkUuid = managementNetworkUuid; + } + public java.lang.String getManagementNetworkUuid() { + return this.managementNetworkUuid; + } + + public java.lang.String zoneUuid; + public void setZoneUuid(java.lang.String zoneUuid) { + this.zoneUuid = zoneUuid; + } + public java.lang.String getZoneUuid() { + return this.zoneUuid; + } + + public java.lang.String imageUuid; + public void setImageUuid(java.lang.String imageUuid) { + this.imageUuid = imageUuid; + } + public java.lang.String getImageUuid() { + return this.imageUuid; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/OvnControllerInventory.java b/sdk/src/main/java/org/zstack/sdk/OvnControllerInventory.java new file mode 100644 index 0000000000..7b5a4d9504 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/OvnControllerInventory.java @@ -0,0 +1,15 @@ +package org.zstack.sdk; + + + +public class OvnControllerInventory extends org.zstack.sdk.SdnControllerInventory { + + public boolean remoteOvn; + public void setRemoteOvn(boolean remoteOvn) { + this.remoteOvn = remoteOvn; + } + public boolean getRemoteOvn() { + return this.remoteOvn; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/OvnControllerVmInstanceInventory.java b/sdk/src/main/java/org/zstack/sdk/OvnControllerVmInstanceInventory.java index 3a68e782b2..dcee2e7aaf 100644 --- a/sdk/src/main/java/org/zstack/sdk/OvnControllerVmInstanceInventory.java +++ b/sdk/src/main/java/org/zstack/sdk/OvnControllerVmInstanceInventory.java @@ -1,8 +1,24 @@ package org.zstack.sdk; +import org.zstack.sdk.NfvInstClusterStatus; +import org.zstack.sdk.NfvInstClusterStatus; +public class OvnControllerVmInstanceInventory extends org.zstack.sdk.NfvInstInventory { -public class OvnControllerVmInstanceInventory extends org.zstack.sdk.ApplianceVmInventory { + public NfvInstClusterStatus nbClusterStatus; + public void setNbClusterStatus(NfvInstClusterStatus nbClusterStatus) { + this.nbClusterStatus = nbClusterStatus; + } + public NfvInstClusterStatus getNbClusterStatus() { + return this.nbClusterStatus; + } + public NfvInstClusterStatus sbClusterStatus; + public void setSbClusterStatus(NfvInstClusterStatus sbClusterStatus) { + this.sbClusterStatus = sbClusterStatus; + } + public NfvInstClusterStatus getSbClusterStatus() { + return this.sbClusterStatus; + } } diff --git a/sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstConfigAction.java b/sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstConfigAction.java new file mode 100644 index 0000000000..700bce6a76 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstConfigAction.java @@ -0,0 +1,101 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class ProvisionNfvInstConfigAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.ProvisionNfvInstConfigResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String vmInstanceUuid; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.ProvisionNfvInstConfigResult value = res.getResult(org.zstack.sdk.ProvisionNfvInstConfigResult.class); + ret.value = value == null ? new org.zstack.sdk.ProvisionNfvInstConfigResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "PUT"; + info.path = "/vm-instances/appliances/nfvinst/{vmInstanceUuid}/provision"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "provisionNfvInstConfig"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstConfigResult.java b/sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstConfigResult.java new file mode 100644 index 0000000000..273aa07417 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstConfigResult.java @@ -0,0 +1,14 @@ +package org.zstack.sdk; + +import org.zstack.sdk.ApplianceVmInventory; + +public class ProvisionNfvInstConfigResult { + public ApplianceVmInventory inventory; + public void setInventory(ApplianceVmInventory inventory) { + this.inventory = inventory; + } + public ApplianceVmInventory getInventory() { + return this.inventory; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstGroupAction.java b/sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstGroupAction.java new file mode 100644 index 0000000000..c26afa190f --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstGroupAction.java @@ -0,0 +1,101 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class ProvisionNfvInstGroupAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.ProvisionNfvInstGroupResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String uuid; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.ProvisionNfvInstGroupResult value = res.getResult(org.zstack.sdk.ProvisionNfvInstGroupResult.class); + ret.value = value == null ? new org.zstack.sdk.ProvisionNfvInstGroupResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "PUT"; + info.path = "/nfvinstgroup/group/{uuid}/actions"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "provisionNfvInstGroup"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstGroupResult.java b/sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstGroupResult.java new file mode 100644 index 0000000000..c73096795c --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/ProvisionNfvInstGroupResult.java @@ -0,0 +1,14 @@ +package org.zstack.sdk; + +import org.zstack.sdk.NfvInstGroupInventory; + +public class ProvisionNfvInstGroupResult { + public NfvInstGroupInventory inventory; + public void setInventory(NfvInstGroupInventory inventory) { + this.inventory = inventory; + } + public NfvInstGroupInventory getInventory() { + return this.inventory; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/QueryNfvInstAction.java b/sdk/src/main/java/org/zstack/sdk/QueryNfvInstAction.java new file mode 100644 index 0000000000..99f1c66b11 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/QueryNfvInstAction.java @@ -0,0 +1,75 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class QueryNfvInstAction extends QueryAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.QueryNfvInstResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.QueryNfvInstResult value = res.getResult(org.zstack.sdk.QueryNfvInstResult.class); + ret.value = value == null ? new org.zstack.sdk.QueryNfvInstResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "GET"; + info.path = "/vm-instances/appliances/nfvinst"; + info.needSession = true; + info.needPoll = false; + info.parameterName = ""; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/QueryNfvInstGroupAction.java b/sdk/src/main/java/org/zstack/sdk/QueryNfvInstGroupAction.java new file mode 100644 index 0000000000..a04db2a92d --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/QueryNfvInstGroupAction.java @@ -0,0 +1,75 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class QueryNfvInstGroupAction extends QueryAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.QueryNfvInstGroupResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.QueryNfvInstGroupResult value = res.getResult(org.zstack.sdk.QueryNfvInstGroupResult.class); + ret.value = value == null ? new org.zstack.sdk.QueryNfvInstGroupResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "GET"; + info.path = "/nfvinstgroup/group"; + info.needSession = true; + info.needPoll = false; + info.parameterName = ""; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/QueryNfvInstGroupResult.java b/sdk/src/main/java/org/zstack/sdk/QueryNfvInstGroupResult.java new file mode 100644 index 0000000000..25fa3ebffa --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/QueryNfvInstGroupResult.java @@ -0,0 +1,22 @@ +package org.zstack.sdk; + + + +public class QueryNfvInstGroupResult { + public java.util.List inventories; + public void setInventories(java.util.List inventories) { + this.inventories = inventories; + } + public java.util.List getInventories() { + return this.inventories; + } + + public java.lang.Long total; + public void setTotal(java.lang.Long total) { + this.total = total; + } + public java.lang.Long getTotal() { + return this.total; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/QueryNfvInstOfferingAction.java b/sdk/src/main/java/org/zstack/sdk/QueryNfvInstOfferingAction.java new file mode 100644 index 0000000000..da56a1e225 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/QueryNfvInstOfferingAction.java @@ -0,0 +1,75 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class QueryNfvInstOfferingAction extends QueryAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.QueryNfvInstOfferingResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.QueryNfvInstOfferingResult value = res.getResult(org.zstack.sdk.QueryNfvInstOfferingResult.class); + ret.value = value == null ? new org.zstack.sdk.QueryNfvInstOfferingResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "GET"; + info.path = "/instance-offerings/nfvinst"; + info.needSession = true; + info.needPoll = false; + info.parameterName = ""; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/QueryNfvInstOfferingResult.java b/sdk/src/main/java/org/zstack/sdk/QueryNfvInstOfferingResult.java new file mode 100644 index 0000000000..544d8b36ed --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/QueryNfvInstOfferingResult.java @@ -0,0 +1,22 @@ +package org.zstack.sdk; + + + +public class QueryNfvInstOfferingResult { + public java.util.List inventories; + public void setInventories(java.util.List inventories) { + this.inventories = inventories; + } + public java.util.List getInventories() { + return this.inventories; + } + + public java.lang.Long total; + public void setTotal(java.lang.Long total) { + this.total = total; + } + public java.lang.Long getTotal() { + return this.total; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/QueryNfvInstResult.java b/sdk/src/main/java/org/zstack/sdk/QueryNfvInstResult.java new file mode 100644 index 0000000000..361b8130fa --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/QueryNfvInstResult.java @@ -0,0 +1,22 @@ +package org.zstack.sdk; + + + +public class QueryNfvInstResult { + public java.util.List inventories; + public void setInventories(java.util.List inventories) { + this.inventories = inventories; + } + public java.util.List getInventories() { + return this.inventories; + } + + public java.lang.Long total; + public void setTotal(java.lang.Long total) { + this.total = total; + } + public java.lang.Long getTotal() { + return this.total; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/QueryOvnControllerAction.java b/sdk/src/main/java/org/zstack/sdk/QueryOvnControllerAction.java new file mode 100644 index 0000000000..8ced685f21 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/QueryOvnControllerAction.java @@ -0,0 +1,75 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class QueryOvnControllerAction extends QueryAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.QueryOvnControllerResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.QueryOvnControllerResult value = res.getResult(org.zstack.sdk.QueryOvnControllerResult.class); + ret.value = value == null ? new org.zstack.sdk.QueryOvnControllerResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "GET"; + info.path = "/ovn-controllers"; + info.needSession = true; + info.needPoll = false; + info.parameterName = ""; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/QueryOvnControllerResult.java b/sdk/src/main/java/org/zstack/sdk/QueryOvnControllerResult.java new file mode 100644 index 0000000000..f146fb9042 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/QueryOvnControllerResult.java @@ -0,0 +1,22 @@ +package org.zstack.sdk; + + + +public class QueryOvnControllerResult { + public java.util.List inventories; + public void setInventories(java.util.List inventories) { + this.inventories = inventories; + } + public java.util.List getInventories() { + return this.inventories; + } + + public java.lang.Long total; + public void setTotal(java.lang.Long total) { + this.total = total; + } + public java.lang.Long getTotal() { + return this.total; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/QueryOvnControllerVmInstanceAction.java b/sdk/src/main/java/org/zstack/sdk/QueryOvnControllerVmInstanceAction.java new file mode 100644 index 0000000000..46e2d887fb --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/QueryOvnControllerVmInstanceAction.java @@ -0,0 +1,75 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class QueryOvnControllerVmInstanceAction extends QueryAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.QueryOvnControllerVmInstanceResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.QueryOvnControllerVmInstanceResult value = res.getResult(org.zstack.sdk.QueryOvnControllerVmInstanceResult.class); + ret.value = value == null ? new org.zstack.sdk.QueryOvnControllerVmInstanceResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "GET"; + info.path = "/vm-instances/appliances/ovn-controller"; + info.needSession = true; + info.needPoll = false; + info.parameterName = ""; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/QueryOvnControllerVmInstanceResult.java b/sdk/src/main/java/org/zstack/sdk/QueryOvnControllerVmInstanceResult.java new file mode 100644 index 0000000000..f0051c0e6b --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/QueryOvnControllerVmInstanceResult.java @@ -0,0 +1,22 @@ +package org.zstack.sdk; + + + +public class QueryOvnControllerVmInstanceResult { + public java.util.List inventories; + public void setInventories(java.util.List inventories) { + this.inventories = inventories; + } + public java.util.List getInventories() { + return this.inventories; + } + + public java.lang.Long total; + public void setTotal(java.lang.Long total) { + this.total = total; + } + public java.lang.Long getTotal() { + return this.total; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/ReconnectNfvInstAction.java b/sdk/src/main/java/org/zstack/sdk/ReconnectNfvInstAction.java new file mode 100644 index 0000000000..47379eb43d --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/ReconnectNfvInstAction.java @@ -0,0 +1,101 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class ReconnectNfvInstAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.ReconnectNfvInstResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String vmInstanceUuid; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.ReconnectNfvInstResult value = res.getResult(org.zstack.sdk.ReconnectNfvInstResult.class); + ret.value = value == null ? new org.zstack.sdk.ReconnectNfvInstResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "PUT"; + info.path = "/vm-instances/appliances/nfvinst/{vmInstanceUuid}/actions"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "reconnectNfvInst"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/ReconnectNfvInstResult.java b/sdk/src/main/java/org/zstack/sdk/ReconnectNfvInstResult.java new file mode 100644 index 0000000000..74b0f10a6b --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/ReconnectNfvInstResult.java @@ -0,0 +1,14 @@ +package org.zstack.sdk; + +import org.zstack.sdk.ApplianceVmInventory; + +public class ReconnectNfvInstResult { + public ApplianceVmInventory inventory; + public void setInventory(ApplianceVmInventory inventory) { + this.inventory = inventory; + } + public ApplianceVmInventory getInventory() { + return this.inventory; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/SyncNfvInstGroupAction.java b/sdk/src/main/java/org/zstack/sdk/SyncNfvInstGroupAction.java new file mode 100644 index 0000000000..0b6504ba3a --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/SyncNfvInstGroupAction.java @@ -0,0 +1,101 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class SyncNfvInstGroupAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.SyncNfvInstGroupResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String uuid; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.SyncNfvInstGroupResult value = res.getResult(org.zstack.sdk.SyncNfvInstGroupResult.class); + ret.value = value == null ? new org.zstack.sdk.SyncNfvInstGroupResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "PUT"; + info.path = "/nfvinstgroup/group/{uuid}/actions"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "syncNfvInstGroup"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/SyncNfvInstGroupResult.java b/sdk/src/main/java/org/zstack/sdk/SyncNfvInstGroupResult.java new file mode 100644 index 0000000000..3bf973cbc9 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/SyncNfvInstGroupResult.java @@ -0,0 +1,14 @@ +package org.zstack.sdk; + +import org.zstack.sdk.NfvInstGroupInventory; + +public class SyncNfvInstGroupResult { + public NfvInstGroupInventory inventory; + public void setInventory(NfvInstGroupInventory inventory) { + this.inventory = inventory; + } + public NfvInstGroupInventory getInventory() { + return this.inventory; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/UpdateNfvInstGroupAction.java b/sdk/src/main/java/org/zstack/sdk/UpdateNfvInstGroupAction.java new file mode 100644 index 0000000000..a6bd5fbcf6 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/UpdateNfvInstGroupAction.java @@ -0,0 +1,107 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class UpdateNfvInstGroupAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.UpdateNfvInstGroupResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String uuid; + + @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String name; + + @Param(required = false, maxLength = 2048, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String description; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.UpdateNfvInstGroupResult value = res.getResult(org.zstack.sdk.UpdateNfvInstGroupResult.class); + ret.value = value == null ? new org.zstack.sdk.UpdateNfvInstGroupResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "PUT"; + info.path = "/nfvinstgroup/group/{uuid}/actions"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "updateNfvInstGroup"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/UpdateNfvInstGroupResult.java b/sdk/src/main/java/org/zstack/sdk/UpdateNfvInstGroupResult.java new file mode 100644 index 0000000000..b58ee147be --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/UpdateNfvInstGroupResult.java @@ -0,0 +1,14 @@ +package org.zstack.sdk; + +import org.zstack.sdk.NfvInstGroupInventory; + +public class UpdateNfvInstGroupResult { + public NfvInstGroupInventory inventory; + public void setInventory(NfvInstGroupInventory inventory) { + this.inventory = inventory; + } + public NfvInstGroupInventory getInventory() { + return this.inventory; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/UpdateNfvInstProvisionConfigAction.java b/sdk/src/main/java/org/zstack/sdk/UpdateNfvInstProvisionConfigAction.java new file mode 100644 index 0000000000..c89a64d662 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/UpdateNfvInstProvisionConfigAction.java @@ -0,0 +1,101 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class UpdateNfvInstProvisionConfigAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.UpdateNfvInstProvisionConfigResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s]", error.code, error.description, error.details) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String vmInstanceUuid; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.UpdateNfvInstProvisionConfigResult value = res.getResult(org.zstack.sdk.UpdateNfvInstProvisionConfigResult.class); + ret.value = value == null ? new org.zstack.sdk.UpdateNfvInstProvisionConfigResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "PUT"; + info.path = "/vm-instances/appliances/nfvinst/{vmInstanceUuid}/provision/update"; + info.needSession = true; + info.needPoll = true; + info.parameterName = "updateNfvInstProvisionConfig"; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/UpdateNfvInstProvisionConfigResult.java b/sdk/src/main/java/org/zstack/sdk/UpdateNfvInstProvisionConfigResult.java new file mode 100644 index 0000000000..466ab13f06 --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/UpdateNfvInstProvisionConfigResult.java @@ -0,0 +1,14 @@ +package org.zstack.sdk; + +import org.zstack.sdk.ApplianceVmInventory; + +public class UpdateNfvInstProvisionConfigResult { + public ApplianceVmInventory inventory; + public void setInventory(ApplianceVmInventory inventory) { + this.inventory = inventory; + } + public ApplianceVmInventory getInventory() { + return this.inventory; + } + +} diff --git a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy index deae4ea042..745e26949e 100644 --- a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy +++ b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy @@ -1853,6 +1853,33 @@ abstract class ApiHelper { } + def addL3NetworkToGroup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.AddL3NetworkToGroupAction.class) Closure c) { + def a = new org.zstack.sdk.AddL3NetworkToGroupAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def addLdapServer(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.AddLdapServerAction.class) Closure c) { def a = new org.zstack.sdk.AddLdapServerAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -3986,6 +4013,33 @@ abstract class ApiHelper { } + def attachNfvInstToGroup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.AttachNfvInstToGroupAction.class) Closure c) { + def a = new org.zstack.sdk.AttachNfvInstToGroupAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def attachNicToBonding(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.AttachNicToBondingAction.class) Closure c) { def a = new org.zstack.sdk.AttachNicToBondingAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -5957,6 +6011,33 @@ abstract class ApiHelper { } + def changeNfvInstGroupOperationMode(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ChangeNfvInstGroupOperationModeAction.class) Closure c) { + def a = new org.zstack.sdk.ChangeNfvInstGroupOperationModeAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def changePortForwardingRuleState(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ChangePortForwardingRuleStateAction.class) Closure c) { def a = new org.zstack.sdk.ChangePortForwardingRuleStateAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -10331,6 +10412,87 @@ abstract class ApiHelper { } + def createNfvInst(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.CreateNfvInstAction.class) Closure c) { + def a = new org.zstack.sdk.CreateNfvInstAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + + def createNfvInstGroup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.CreateNfvInstGroupAction.class) Closure c) { + def a = new org.zstack.sdk.CreateNfvInstGroupAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + + def createNfvInstOffering(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.CreateNfvInstOfferingAction.class) Closure c) { + def a = new org.zstack.sdk.CreateNfvInstOfferingAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def createOAuthClient(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.CreateOAuthClientAction.class) Closure c) { def a = new org.zstack.sdk.CreateOAuthClientAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -15677,6 +15839,33 @@ abstract class ApiHelper { } + def deleteNfvInstGroup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.DeleteNfvInstGroupAction.class) Closure c) { + def a = new org.zstack.sdk.DeleteNfvInstGroupAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def deleteNicQos(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.DeleteNicQosAction.class) Closure c) { def a = new org.zstack.sdk.DeleteNicQosAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -18647,6 +18836,33 @@ abstract class ApiHelper { } + def detachNfvInstFromGroup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.DetachNfvInstFromGroupAction.class) Closure c) { + def a = new org.zstack.sdk.DetachNfvInstFromGroupAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def detachNicFromBonding(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.DetachNicFromBondingAction.class) Closure c) { def a = new org.zstack.sdk.DetachNicFromBondingAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -27854,6 +28070,60 @@ abstract class ApiHelper { } + def provisionNfvInstConfig(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ProvisionNfvInstConfigAction.class) Closure c) { + def a = new org.zstack.sdk.ProvisionNfvInstConfigAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + + def provisionNfvInstGroup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ProvisionNfvInstGroupAction.class) Closure c) { + def a = new org.zstack.sdk.ProvisionNfvInstGroupAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def provisionSlbInstance(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ProvisionSlbInstanceAction.class) Closure c) { def a = new org.zstack.sdk.ProvisionSlbInstanceAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -32919,6 +33189,93 @@ abstract class ApiHelper { } + def queryNfvInst(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryNfvInstAction.class) Closure c) { + def a = new org.zstack.sdk.QueryNfvInstAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + a.conditions = a.conditions.collect { it.toString() } + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + + def queryNfvInstGroup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryNfvInstGroupAction.class) Closure c) { + def a = new org.zstack.sdk.QueryNfvInstGroupAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + a.conditions = a.conditions.collect { it.toString() } + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + + def queryNfvInstOffering(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryNfvInstOfferingAction.class) Closure c) { + def a = new org.zstack.sdk.QueryNfvInstOfferingAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + a.conditions = a.conditions.collect { it.toString() } + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def queryNvmeLun(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryNvmeLunAction.class) Closure c) { def a = new org.zstack.sdk.QueryNvmeLunAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -33035,6 +33392,64 @@ abstract class ApiHelper { } + def queryOvnController(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryOvnControllerAction.class) Closure c) { + def a = new org.zstack.sdk.QueryOvnControllerAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + a.conditions = a.conditions.collect { it.toString() } + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + + def queryOvnControllerVmInstance(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryOvnControllerVmInstanceAction.class) Closure c) { + def a = new org.zstack.sdk.QueryOvnControllerVmInstanceAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + a.conditions = a.conditions.collect { it.toString() } + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def queryPciDevice(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryPciDeviceAction.class) Closure c) { def a = new org.zstack.sdk.QueryPciDeviceAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -36692,6 +37107,33 @@ abstract class ApiHelper { } + def reconnectNfvInst(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ReconnectNfvInstAction.class) Closure c) { + def a = new org.zstack.sdk.ReconnectNfvInstAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def reconnectPrimaryStorage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ReconnectPrimaryStorageAction.class) Closure c) { def a = new org.zstack.sdk.ReconnectPrimaryStorageAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -41093,6 +41535,33 @@ abstract class ApiHelper { } + def syncNfvInstGroup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.SyncNfvInstGroupAction.class) Closure c) { + def a = new org.zstack.sdk.SyncNfvInstGroupAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def syncPrimaryStorageCapacity(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.SyncPrimaryStorageCapacityAction.class) Closure c) { def a = new org.zstack.sdk.SyncPrimaryStorageCapacityAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -45089,6 +45558,60 @@ abstract class ApiHelper { } + def updateNfvInstGroup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UpdateNfvInstGroupAction.class) Closure c) { + def a = new org.zstack.sdk.UpdateNfvInstGroupAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + + def updateNfvInstProvisionConfig(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UpdateNfvInstProvisionConfigAction.class) Closure c) { + def a = new org.zstack.sdk.UpdateNfvInstProvisionConfigAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def updateOAuthClient(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.UpdateOAuthClientAction.class) Closure c) { def a = new org.zstack.sdk.UpdateOAuthClientAction() a.sessionId = Test.currentEnvSpec?.session?.uuid diff --git a/testlib/src/main/java/org/zstack/testlib/KVMSimulator.groovy b/testlib/src/main/java/org/zstack/testlib/KVMSimulator.groovy index 6e77c2dfed..81bd88ac6b 100755 --- a/testlib/src/main/java/org/zstack/testlib/KVMSimulator.groovy +++ b/testlib/src/main/java/org/zstack/testlib/KVMSimulator.groovy @@ -463,6 +463,22 @@ class KVMSimulator implements Simulator { return new KVMAgentCommands.AgentResponse() } + spec.simulator(KVMConstant.KVM_OVS_CHECK_LOCAL_PORT_PATH) { + return new KVMAgentCommands.OvsCheckPortRsp() + } + + spec.simulator(KVMConstant.KVM_OVS_SYNC_PORT_PATH) { + return new KVMAgentCommands.OvsSyncPortRsp() + } + + spec.simulator(KVMConstant.KVM_OVS_SET_REQUESTED_CHASSIS_PATH) { + return new KVMAgentCommands.OvsSetRequestedChassisRsp() + } + + spec.simulator(KVMConstant.KVM_OVS_SET_DB_CONNECTION_PATH) { + return new KVMAgentCommands.OvsSetDbConnectionRsp() + } + spec.simulator(KVMConstant.KVM_SYNC_VM_DEVICEINFO_PATH) { HttpEntity e -> SyncVmDeviceInfoCmd cmd = JSONObjectUtil.toObject(e.body, SyncVmDeviceInfoCmd.class) def rsp = new SyncVmDeviceInfoResponse() diff --git a/testlib/src/main/java/org/zstack/testlib/VipSpec.groovy b/testlib/src/main/java/org/zstack/testlib/VipSpec.groovy new file mode 100644 index 0000000000..8490372cdc --- /dev/null +++ b/testlib/src/main/java/org/zstack/testlib/VipSpec.groovy @@ -0,0 +1,57 @@ +package org.zstack.testlib + +import org.zstack.sdk.VipInventory +import org.zstack.sdk.VmNicInventory + +/** + * Created by shixin.ruan on 2025/12/10. + */ +class VipSpec extends Spec implements HasSession { + @SpecParam(required = true) + String name + @SpecParam(required = true) + String l3NetworkUuid + @SpecParam + String description + @SpecParam + String requiredIp + + VipInventory inventory + + VipSpec(EnvSpec envSpec) { + super(envSpec) + } + + SpecID create(String uuid, String sessionId) { + inventory = createVip { + delegate.resourceUuid = uuid + delegate.name = name + delegate.l3NetworkUuid = l3NetworkUuid + delegate.description = description + delegate.requiredIp = requiredIp + delegate.userTags = userTags + delegate.systemTags = systemTags + delegate.sessionId = sessionId + } + + postCreate { + inventory = queryVip { + conditions=["uuid=${inventory.uuid}".toString()] + }[0] + } + + return id(name, inventory.uuid) + } + + @Override + void delete(String sessionId) { + if (inventory != null) { + deleteVip { + delegate.uuid = inventory.uuid + delegate.sessionId = sessionId + } + + inventory = null + } + } +} diff --git a/testlib/src/main/java/org/zstack/testlib/ZoneSpec.groovy b/testlib/src/main/java/org/zstack/testlib/ZoneSpec.groovy index 9d78316d8d..0404637ddb 100755 --- a/testlib/src/main/java/org/zstack/testlib/ZoneSpec.groovy +++ b/testlib/src/main/java/org/zstack/testlib/ZoneSpec.groovy @@ -139,6 +139,15 @@ class ZoneSpec extends Spec { return spec } + VipSpec vip(@DelegatesTo(strategy = Closure.DELEGATE_FIRST, value = VipSpec.class) Closure c) { + def spec = new VipSpec(envSpec) + c.delegate = spec + c.resolveStrategy = Closure.DELEGATE_FIRST + c() + addChild(spec) + return spec + } + EipSpec eip(@DelegatesTo(strategy = Closure.DELEGATE_FIRST, value = EipSpec.class) Closure c) { def spec = new EipSpec(envSpec) c.delegate = spec From 0c852e20ccbbe69979ec8aff832df58cec69d25d Mon Sep 17 00:00:00 2001 From: "shan.wu" Date: Tue, 11 Nov 2025 14:22:29 +0800 Subject: [PATCH 48/48] [sharedblock]: convert memory snapshot install path from absolute path to protocol path convert memory snapshot install path from absolute path to protocol path Resolves/Related: ZSTAC-79756 Change-Id: I6e626d68626461627a737765786a676e6b617064 --- conf/db/upgrade/V5.5.0__schema.sql | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/conf/db/upgrade/V5.5.0__schema.sql b/conf/db/upgrade/V5.5.0__schema.sql index e76e26d5d7..a559decf34 100644 --- a/conf/db/upgrade/V5.5.0__schema.sql +++ b/conf/db/upgrade/V5.5.0__schema.sql @@ -471,3 +471,8 @@ CREATE TABLE IF NOT EXISTS `OvnControllerVO` ( INSERT IGNORE INTO OvnControllerVO (uuid, remoteOvn) SELECT uuid, 0 FROM SdnControllerVO where vendorType = 'Ovn'; + +UPDATE VolumeSnapshotVO AS sp, PrimaryStorageVO AS ps +SET sp.primaryStorageInstallPath = REPLACE(sp.primaryStorageInstallPath, '/dev/', 'sharedblock://') +WHERE sp.primaryStorageUuid = ps.uuid AND ps.type = 'SharedBlock' AND sp.volumeType = 'Memory' AND sp.primaryStorageInstallPath LIKE '/dev/%'; +