From 926c4c14ded8ee2a0b96ffdededa693b9fd0622d Mon Sep 17 00:00:00 2001 From: "shixin.ruan" Date: Sun, 28 Jun 2026 11:25:02 +0800 Subject: [PATCH 1/7] [mgt-ipv6]: support IPv6 management network Squash IPv6 management network feature changes onto latest 5.5.28. Resolves: ZSTAC-79206 Change-Id: I4352b96cb247538cfd59ab5da4f8b1cf16ec570e --- .../compute/allocator/TagAllocatorFlow.java | 3 +- .../compute/host/HostApiInterceptor.java | 67 +- .../compute/vm/VmCreateOnHypervisorFlow.java | 4 +- ...InstantiateResourceForChangeImageFlow.java | 8 +- .../vm/VmInstantiateResourcePostFlow.java | 8 +- .../vm/VmInstantiateResourcePreFlow.java | 8 +- .../compute/vm/VmReleaseResourceFlow.java | 7 +- ...ManagementNetworkIpVersionManagerImpl.java | 145 +++++ .../zstack/compute/zone/ZoneManagerImpl.java | 45 ++ .../zstack/compute/zone/ZoneSystemTags.java | 5 + conf/db/upgrade/V5.5.28__schema.sql | 18 + conf/deploydb.sh | 23 +- conf/deployuidb.sh | 26 +- conf/springConfigXml/DatabaseFacade.xml | 2 +- .../springConfigXml/PrimaryStorageManager.xml | 6 + conf/springConfigXml/SftpBackupStorage.xml | 9 +- conf/springConfigXml/ZoneManager.xml | 16 +- conf/springConfigXml/ceph.xml | 1 + conf/zstack.properties | 3 +- conf/zstack.xml | 1 - .../zstack/console/ConsoleApiInterceptor.java | 17 +- .../zstack/console/ConsoleManagerImpl.java | 110 +++- .../org/zstack/console/ConsoleProxyBase.java | 10 +- .../ManagementServerConsoleProxyBackend.java | 63 +- .../org/zstack/core/CoreGlobalProperty.java | 4 + .../main/java/org/zstack/core/Platform.java | 612 ++++++++++++++++-- .../zstack/core/agent/AgentManagerImpl.java | 8 +- .../zstack/core/ansible/AnsibleRunner.java | 11 +- .../core/ansible/CallBackNetworkChecker.java | 17 +- .../zstack/core/cloudbus/CloudBusImpl3.java | 13 +- .../org/zstack/core/config/GlobalConfig.java | 5 + .../core/config/GlobalConfigConstant.java | 2 + .../core/config/GlobalConfigFacadeImpl.java | 6 +- .../zstack/core/db/DatabaseFacadeImpl.java | 2 +- .../main/java/org/zstack/core/db/GLock.java | 7 + core/src/main/java/org/zstack/core/db/Q.java | 4 +- .../org/zstack/core/db/SimpleQueryImpl.java | 6 + .../org/zstack/core/rest/RESTFacadeImpl.java | 46 +- .../core/search/SearchBackendConstant.java | 7 + .../search/ZStackZSha2JGroupsBackend.java | 12 + .../core/search/ZStackZSha2NodeSelector.java | 21 + .../core/timeout/ApiTimeoutManagerImpl.java | 11 +- .../APIUpdateConsoleProxyAgentMsg.java | 22 + ...UpdateConsoleProxyAgentMsgDoc_zh_cn.groovy | 18 + .../console/ConsoleProxyAgentInventory.java | 20 + .../header/console/ConsoleProxyAgentVO.java | 22 + .../console/UpdateConsoleProxyAgentMsg.java | 18 + .../org/zstack/header/host/APIAddHostMsg.java | 4 +- .../host/APIUpdateHostMsgDoc_zh_cn.groovy | 2 +- .../org/zstack/header/rest/RESTFacade.java | 8 + .../zstack/header/zone/APICreateZoneMsg.java | 2 + .../ManagementNetworkIpVersionManager.java | 56 ++ ...etworkIpVersionResourceExtensionPoint.java | 5 + .../network/l3/L3NetworkApiInterceptor.java | 29 +- .../zstack/appliancevm/ApplianceVmBase.java | 14 +- .../appliancevm/ApplianceVmConstant.java | 1 + .../appliancevm/ApplianceVmFacadeImpl.java | 69 +- .../storage/ceph/CephApiInterceptor.java | 172 ++++- .../java/org/zstack/storage/ceph/MonUri.java | 11 + .../CephBackupStorageMetaDataMaker.java | 9 +- .../ceph/backup/CephBackupStorageMonBase.java | 3 +- .../ceph/primary/CephPrimaryStorageBase.java | 7 +- .../primary/CephPrimaryStorageMonBase.java | 3 +- .../network/service/flat/FlatDhcpBackend.java | 2 + .../kvm/APIAddKVMHostMsgDoc_zh_cn.groovy | 2 +- .../kvm/APIUpdateKVMHostMsgDoc_zh_cn.groovy | 2 +- .../kvm/KVMConsoleHypervisorBackend.java | 7 +- .../src/main/java/org/zstack/kvm/KVMHost.java | 108 ++-- .../java/org/zstack/kvm/KVMHostFactory.java | 35 +- .../java/org/zstack/kvm/KVMHostUtils.java | 5 + .../zstack/kvm/KvmHostIpmiPowerExecutor.java | 8 +- .../kvm/VmCpuVendorKvmStartVmExtension.java | 13 +- .../primary/local/LocalStorageConstants.java | 3 +- .../primary/nfs/NfsApiParamChecker.java | 41 +- .../backup/sftp/SftpBackupStorage.java | 3 +- .../sftp/SftpBackupStorageApiInterceptor.java | 81 ++- .../sftp/SftpBackupStorageMetaDataMaker.java | 3 +- .../service/virtualrouter/VirtualRouter.java | 6 +- .../VirtualRouterApiInterceptor.java | 5 - .../virtualrouter/VirtualRouterManager.java | 9 + .../VirtualRouterManagerImpl.java | 79 +-- .../VirtualRouterDeployAgentFlow.java | 4 +- .../virtualrouter/vyos/VyosConnectFlow.java | 2 +- .../APICreateVxlanPoolRemoteVtepMsg.java | 2 +- .../APIDeleteVxlanPoolRemoteVtepMsg.java | 2 +- .../VxlanNetworkPoolConstant.java | 1 + .../VxlanPoolApiInterceptor.java | 40 +- .../java/org/zstack/storage/zbs/MdsUri.java | 5 +- .../org/zstack/storage/zbs/ZbsAgentUrl.java | 26 +- .../ManagementNodeManagerImpl.java | 19 + .../zstack/resourceconfig/ResourceConfig.java | 5 + .../ResourceConfigFacadeImpl.java | 8 +- .../sdk/ConsoleProxyAgentInventory.java | 16 + .../sdk/CreateVxlanPoolRemoteVtepAction.java | 2 +- .../sdk/DeleteVxlanPoolRemoteVtepAction.java | 2 +- .../SetIpOnHostNetworkInterfaceAction.java | 3 + .../sdk/UpdateConsoleProxyAgentAction.java | 6 + ...ementNetworkIpVersionStorageExtension.java | 68 ++ .../backup/BackupStorageApiInterceptor.java | 14 + .../primary/PrimaryStorageApiInterceptor.java | 50 ++ .../PrimaryStorageFeatureAllocatorFlow.java | 4 +- .../PrimaryStorageTagAllocatorFlow.java | 7 +- .../host/HostApiInterceptorIpv6Case.groovy | 33 + .../zstack/kvm/KVMHostFactoryIpv6Case.groovy | 21 + .../appliancevm/ApplianceVmIpv6Case.groovy | 85 +++ .../console/ConsoleProxyCase.groovy | 58 ++ .../core/ManagementNetworkIpv6Case.groovy | 597 +++++++++++++++++ .../test/integration/core/MustFailCase.groovy | 2 + .../kvm/host/KvmHostIpv6Case.groovy | 149 +++++ .../l3network/ipv6/IPv6DhcpCase.groovy | 4 +- .../l3network/ipv6/Ipv6RangeCase.groovy | 56 +- .../AddRemoteVxlanVtepIpCase.groovy | 141 ++-- .../vxlanNetwork/AddVxlanVtepIpCase.groovy | 77 +++ ...tworkIpVersionStorageConstraintCase.groovy | 394 +++++++++++ .../addon/zbs/ZbsPrimaryStorageCase.groovy | 33 + .../unittest/utils/NetworkUtilsCase.groovy | 27 + .../org/zstack/test/kvm/KVMHostUtilsTest.java | 7 + .../unitTestSuiteXml/BackupStorageManager.xml | 9 +- .../main/java/org/zstack/utils/TagUtils.java | 117 +++- .../java/org/zstack/utils/URLBuilder.java | 7 +- .../CloudOperationsErrorCode.java | 98 +++ .../zstack/utils/network/IPv6Constants.java | 1 + .../utils/network/IPv6NetworkUtils.java | 74 +++ .../ManagementNetworkIpVersionUtils.java | 105 +++ .../zstack/utils/network/NetworkUtils.java | 38 +- .../main/java/org/zstack/utils/ssh/Ssh.java | 5 +- .../java/org/zstack/utils/ssh/SshShell.java | 31 +- .../org/zstack/utils/zsha2/ZSha2Helper.java | 2 +- 128 files changed, 4295 insertions(+), 468 deletions(-) create mode 100644 compute/src/main/java/org/zstack/compute/zone/ManagementNetworkIpVersionManagerImpl.java create mode 100644 core/src/main/java/org/zstack/core/search/SearchBackendConstant.java create mode 100644 core/src/main/java/org/zstack/core/search/ZStackZSha2JGroupsBackend.java create mode 100644 core/src/main/java/org/zstack/core/search/ZStackZSha2NodeSelector.java create mode 100644 header/src/main/java/org/zstack/header/zone/ManagementNetworkIpVersionManager.java create mode 100644 header/src/main/java/org/zstack/header/zone/ManagementNetworkIpVersionResourceExtensionPoint.java create mode 100644 storage/src/main/java/org/zstack/storage/ManagementNetworkIpVersionStorageExtension.java create mode 100644 test/src/test/groovy/org/zstack/compute/host/HostApiInterceptorIpv6Case.groovy create mode 100644 test/src/test/groovy/org/zstack/kvm/KVMHostFactoryIpv6Case.groovy create mode 100644 test/src/test/groovy/org/zstack/test/integration/appliancevm/ApplianceVmIpv6Case.groovy create mode 100644 test/src/test/groovy/org/zstack/test/integration/core/ManagementNetworkIpv6Case.groovy create mode 100644 test/src/test/groovy/org/zstack/test/integration/kvm/host/KvmHostIpv6Case.groovy create mode 100644 test/src/test/groovy/org/zstack/test/integration/storage/ManagementNetworkIpVersionStorageConstraintCase.groovy create mode 100644 utils/src/main/java/org/zstack/utils/network/ManagementNetworkIpVersionUtils.java diff --git a/compute/src/main/java/org/zstack/compute/allocator/TagAllocatorFlow.java b/compute/src/main/java/org/zstack/compute/allocator/TagAllocatorFlow.java index 0d046d2cc7e..c98bb3403bf 100755 --- a/compute/src/main/java/org/zstack/compute/allocator/TagAllocatorFlow.java +++ b/compute/src/main/java/org/zstack/compute/allocator/TagAllocatorFlow.java @@ -40,7 +40,7 @@ public class TagAllocatorFlow extends AbstractHostAllocatorFlow { private List instanceOfferingExtensions; private List diskOfferingExtensions; - public TagAllocatorFlow() { + private void loadExtensions() { instanceOfferingExtensions = pluginRgty.getExtensionList(InstanceOfferingTagAllocatorExtensionPoint.class); diskOfferingExtensions = pluginRgty.getExtensionList(DiskOfferingTagAllocatorExtensionPoint.class); } @@ -48,6 +48,7 @@ public TagAllocatorFlow() { @Override public void allocate() { throwExceptionIfIAmTheFirstFlow(); + loadExtensions(); if (!instanceOfferingExtensions.isEmpty()) { SimpleQuery q = dbf.createQuery(SystemTagVO.class); diff --git a/compute/src/main/java/org/zstack/compute/host/HostApiInterceptor.java b/compute/src/main/java/org/zstack/compute/host/HostApiInterceptor.java index 0bbbe166d1c..60e19d32371 100755 --- a/compute/src/main/java/org/zstack/compute/host/HostApiInterceptor.java +++ b/compute/src/main/java/org/zstack/compute/host/HostApiInterceptor.java @@ -11,10 +11,14 @@ import org.zstack.header.apimediator.ApiMessageInterceptionException; import org.zstack.header.apimediator.ApiMessageInterceptor; import org.zstack.header.apimediator.StopRoutingException; +import org.zstack.header.cluster.ClusterVO; +import org.zstack.header.cluster.ClusterVO_; import org.zstack.header.host.*; import org.zstack.header.message.APIMessage; +import org.zstack.header.zone.ManagementNetworkIpVersionManager; import org.zstack.utils.ShellResult; import org.zstack.utils.ShellUtils; +import org.zstack.utils.network.IPv6NetworkUtils; import org.zstack.utils.network.NetworkUtils; import static org.zstack.core.Platform.argerr; @@ -28,12 +32,19 @@ * To change this template use File | Settings | File Templates. */ public class HostApiInterceptor implements ApiMessageInterceptor { + private static final String INVALID_MANAGEMENT_IP_ERROR = + "managementIp[%s] is not a valid IPv4 address, IPv6 address, or hostname"; + private static final String RESERVED_MANAGEMENT_IPV6_ERROR = + "managementIp[%s] is an IPv6 address that cannot be used as a management address"; + @Autowired private CloudBus bus; @Autowired private ErrorFacade errf; @Autowired private DatabaseFacade dbf; + @Autowired + private ManagementNetworkIpVersionManager managementNetworkIpVersionManager; private void setServiceId(APIMessage msg) { if (msg instanceof HostMessage) { @@ -112,18 +123,70 @@ private void validate(APIDeleteHostMsg msg) { private void validate(APIUpdateHostMsg msg) { if (msg.getManagementIp() != null) { + msg.setManagementIp(validateManagementEndpoint(msg.getManagementIp())); + SimpleQuery q = dbf.createQuery(HostVO.class); q.add(HostVO_.managementIp, Op.EQ, msg.getManagementIp()); if (q.isExists()) { throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_COMPUTE_HOST_10112, "there has been a host having managementIp[%s]", msg.getManagementIp())); } + + String zoneUuid = Q.New(HostVO.class) + .select(HostVO_.zoneUuid) + .eq(HostVO_.uuid, msg.getUuid()) + .findValue(); + managementNetworkIpVersionManager.validateEndpointInZone(zoneUuid, msg.getManagementIp(), + "host", msg.getUuid(), ORG_ZSTACK_COMPUTE_HOST_10130); } } private void validate(APIAddHostMsg msg) { - if (!NetworkUtils.isIpv4Address(msg.getManagementIp()) && !NetworkUtils.isHostname(msg.getManagementIp())) { - throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_COMPUTE_HOST_10113, "managementIp[%s] is neither an IPv4 address nor a valid hostname", msg.getManagementIp())); + validateManagementEndpoint(msg); + String zoneUuid = Q.New(ClusterVO.class) + .select(ClusterVO_.zoneUuid) + .eq(ClusterVO_.uuid, msg.getClusterUuid()) + .findValue(); + managementNetworkIpVersionManager.validateEndpointInZone(zoneUuid, msg.getManagementIp(), + "host", msg.getName(), ORG_ZSTACK_COMPUTE_HOST_10130); + } + + static void validateManagementEndpoint(APIAddHostMsg msg) { + String managementIp = msg.getManagementIp(); + msg.setManagementIp(validateManagementEndpoint(managementIp)); + } + + static String validateManagementEndpoint(String managementIp) { + if (IPv6NetworkUtils.isIpv6Address(managementIp)) { + if (!IPv6NetworkUtils.isValidManagementIpv6Address(managementIp)) { + throw new ApiMessageInterceptionException(argerr( + ORG_ZSTACK_COMPUTE_HOST_10129, + RESERVED_MANAGEMENT_IPV6_ERROR, + managementIp)); + } + } else if (!isValidManagementEndpoint(managementIp)) { + throw new ApiMessageInterceptionException(argerr( + ORG_ZSTACK_COMPUTE_HOST_10128, + INVALID_MANAGEMENT_IP_ERROR, + managementIp)); } + + if (IPv6NetworkUtils.isIpv6Address(managementIp)) { + return IPv6NetworkUtils.getIpv6AddressCanonicalString(managementIp); + } + + return managementIp; + } + + static String getManagementEndpointValidationErrorCode(String managementIp) { + if (IPv6NetworkUtils.isIpv6Address(managementIp)) { + return IPv6NetworkUtils.isValidManagementIpv6Address(managementIp) ? null : ORG_ZSTACK_COMPUTE_HOST_10129; + } + + return isValidManagementEndpoint(managementIp) ? null : ORG_ZSTACK_COMPUTE_HOST_10128; + } + + private static boolean isValidManagementEndpoint(String endpoint) { + return IPv6NetworkUtils.isValidManagementEndpoint(endpoint); } private void validate(APIChangeHostStateMsg msg){ diff --git a/compute/src/main/java/org/zstack/compute/vm/VmCreateOnHypervisorFlow.java b/compute/src/main/java/org/zstack/compute/vm/VmCreateOnHypervisorFlow.java index 5b054dede75..6a40c15c34b 100755 --- a/compute/src/main/java/org/zstack/compute/vm/VmCreateOnHypervisorFlow.java +++ b/compute/src/main/java/org/zstack/compute/vm/VmCreateOnHypervisorFlow.java @@ -33,10 +33,8 @@ public class VmCreateOnHypervisorFlow implements Flow { @Autowired private EventFacade evtf; - private final List exts = pluginRgty.getExtensionList(VmBeforeCreateOnHypervisorExtensionPoint.class); - private void fireExtensions(VmInstanceSpec spec) { - for (VmBeforeCreateOnHypervisorExtensionPoint ext : exts) { + for (VmBeforeCreateOnHypervisorExtensionPoint ext : pluginRgty.getExtensionList(VmBeforeCreateOnHypervisorExtensionPoint.class)) { ext.beforeCreateVmOnHypervisor(spec); } } diff --git a/compute/src/main/java/org/zstack/compute/vm/VmInstantiateResourceForChangeImageFlow.java b/compute/src/main/java/org/zstack/compute/vm/VmInstantiateResourceForChangeImageFlow.java index bbdb2978036..dbf1b574e35 100755 --- a/compute/src/main/java/org/zstack/compute/vm/VmInstantiateResourceForChangeImageFlow.java +++ b/compute/src/main/java/org/zstack/compute/vm/VmInstantiateResourceForChangeImageFlow.java @@ -25,8 +25,9 @@ public class VmInstantiateResourceForChangeImageFlow implements Flow { @Autowired private PluginRegistry pluginRgty; - private final List extensions = pluginRgty.getExtensionList(ChangeVmImageExtensionPoint.class); - + private List getExtensions() { + return pluginRgty.getExtensionList(ChangeVmImageExtensionPoint.class); + } private void runExtensions(final Iterator it, final VmInstanceSpec spec, final FlowTrigger chain) { if (!it.hasNext()) { @@ -53,6 +54,7 @@ public void fail(ErrorCode errorCode) { @Override public void run(FlowTrigger chain, Map data) { VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString()); + List extensions = getExtensions(); for (ChangeVmImageExtensionPoint extp : extensions) { try { extp.preBeforeInstantiateVmResource(spec); @@ -89,6 +91,6 @@ public void fail(ErrorCode errorCode) { @Override public void rollback(FlowRollback chain, Map data) { VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString()); - rollbackExtensions(extensions.iterator(), spec, chain); + rollbackExtensions(getExtensions().iterator(), spec, chain); } } diff --git a/compute/src/main/java/org/zstack/compute/vm/VmInstantiateResourcePostFlow.java b/compute/src/main/java/org/zstack/compute/vm/VmInstantiateResourcePostFlow.java index e6a7f14c34d..a5f8e46bd54 100755 --- a/compute/src/main/java/org/zstack/compute/vm/VmInstantiateResourcePostFlow.java +++ b/compute/src/main/java/org/zstack/compute/vm/VmInstantiateResourcePostFlow.java @@ -28,11 +28,13 @@ public class VmInstantiateResourcePostFlow implements Flow { @Autowired private PluginRegistry pluginRgty; - private final List extensions = pluginRgty.getExtensionList(PostVmInstantiateResourceExtensionPoint.class); - + private List getExtensions() { + return pluginRgty.getExtensionList(PostVmInstantiateResourceExtensionPoint.class); + } public void run(FlowTrigger trigger, Map data) { VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString()); + List extensions = getExtensions(); for (PostVmInstantiateResourceExtensionPoint ext : extensions) { ext.postBeforeInstantiateVmResource(spec); } @@ -64,7 +66,7 @@ public void fail(ErrorCode errorCode) { @Override public void rollback(FlowRollback trigger, Map data) { VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString()); - rollbackExtensions(extensions.iterator(), spec, trigger); + rollbackExtensions(getExtensions().iterator(), spec, trigger); } private void rollbackExtensions(final Iterator iterator, final VmInstanceSpec spec, final FlowRollback trigger) { diff --git a/compute/src/main/java/org/zstack/compute/vm/VmInstantiateResourcePreFlow.java b/compute/src/main/java/org/zstack/compute/vm/VmInstantiateResourcePreFlow.java index 4c7b6eee38f..4f4f7e6ff63 100755 --- a/compute/src/main/java/org/zstack/compute/vm/VmInstantiateResourcePreFlow.java +++ b/compute/src/main/java/org/zstack/compute/vm/VmInstantiateResourcePreFlow.java @@ -29,8 +29,9 @@ public class VmInstantiateResourcePreFlow implements Flow { @Autowired private PluginRegistry pluginRgty; - private final List extensions = pluginRgty.getExtensionList(PreVmInstantiateResourceExtensionPoint.class); - + private List getExtensions() { + return pluginRgty.getExtensionList(PreVmInstantiateResourceExtensionPoint.class); + } private void runExtensions(final Iterator it, final VmInstanceSpec spec, final FlowTrigger chain) { if (!it.hasNext()) { @@ -61,6 +62,7 @@ public void fail(ErrorCode errorCode) { @Override public void run(FlowTrigger chain, Map data) { VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString()); + List extensions = getExtensions(); for (PreVmInstantiateResourceExtensionPoint extp : extensions) { try { extp.preBeforeInstantiateVmResource(spec); @@ -97,6 +99,6 @@ public void fail(ErrorCode errorCode) { @Override public void rollback(FlowRollback chain, Map data) { VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString()); - rollbackExtensions(extensions.iterator(), spec, chain); + rollbackExtensions(getExtensions().iterator(), spec, chain); } } diff --git a/compute/src/main/java/org/zstack/compute/vm/VmReleaseResourceFlow.java b/compute/src/main/java/org/zstack/compute/vm/VmReleaseResourceFlow.java index a57b93acde1..119ffdb74f5 100755 --- a/compute/src/main/java/org/zstack/compute/vm/VmReleaseResourceFlow.java +++ b/compute/src/main/java/org/zstack/compute/vm/VmReleaseResourceFlow.java @@ -26,9 +26,10 @@ public class VmReleaseResourceFlow implements Flow { @Autowired private PluginRegistry pluginRgty; - - private final List extensions = pluginRgty.getExtensionList(VmReleaseResourceExtensionPoint.class); + private List getExtensions() { + return pluginRgty.getExtensionList(VmReleaseResourceExtensionPoint.class); + } private void fireExtensions(final Iterator it, final VmInstanceSpec spec, final Map ctx, final FlowTrigger chain) { if (!it.hasNext()) { @@ -53,7 +54,7 @@ public void fail(ErrorCode errorCode) { @Override public void run(FlowTrigger chain, Map data) { VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString()); - fireExtensions(extensions.iterator(), spec, data, chain); + fireExtensions(getExtensions().iterator(), spec, data, chain); } @Override diff --git a/compute/src/main/java/org/zstack/compute/zone/ManagementNetworkIpVersionManagerImpl.java b/compute/src/main/java/org/zstack/compute/zone/ManagementNetworkIpVersionManagerImpl.java new file mode 100644 index 00000000000..7117791bfb4 --- /dev/null +++ b/compute/src/main/java/org/zstack/compute/zone/ManagementNetworkIpVersionManagerImpl.java @@ -0,0 +1,145 @@ +package org.zstack.compute.zone; + +import org.springframework.beans.factory.annotation.Autowired; +import org.zstack.core.componentloader.PluginRegistry; +import org.zstack.core.db.DatabaseFacade; +import org.zstack.core.db.Q; +import org.zstack.header.apimediator.ApiMessageInterceptionException; +import org.zstack.header.host.HostVO; +import org.zstack.header.host.HostVO_; +import org.zstack.header.tag.SystemTagInventory; +import org.zstack.header.zone.ManagementNetworkIpVersionManager; +import org.zstack.header.zone.ManagementNetworkIpVersionResourceExtensionPoint; +import org.zstack.header.zone.ZoneVO; +import org.zstack.utils.network.ManagementNetworkIpVersionUtils; + +import java.util.List; +import java.util.Map; + +import static org.zstack.core.Platform.argerr; +import static org.zstack.utils.clouderrorcode.CloudOperationsErrorCode.ORG_ZSTACK_COMPUTE_ZONE_10004; +import static org.zstack.utils.clouderrorcode.CloudOperationsErrorCode.ORG_ZSTACK_COMPUTE_ZONE_10005; +import static org.zstack.utils.clouderrorcode.CloudOperationsErrorCode.ORG_ZSTACK_COMPUTE_ZONE_10006; +import static org.zstack.utils.clouderrorcode.CloudOperationsErrorCode.ORG_ZSTACK_COMPUTE_ZONE_10007; + +public class ManagementNetworkIpVersionManagerImpl implements ManagementNetworkIpVersionManager { + private static final String DEFAULT_ZONE_IP_VERSION = ManagementNetworkIpVersionUtils.IPV4; + private static final String HOST_RESOURCE_TYPE = "host"; + private static final String MISMATCH_ERROR = + "%s[%s] uses %s endpoint[%s], but zone[uuid:%s] management network ipVersion is %s"; + + @Autowired + private DatabaseFacade dbf; + @Autowired + private PluginRegistry pluginRgty; + + @Override + public void validateEndpointInZone(String zoneUuid, String endpoint, String resourceType, String resourceIdentity, String errorCode) { + if (zoneUuid == null || endpoint == null) { + return; + } + + validateEndpointMatchesIpVersion(zoneUuid, getZoneIpVersion(zoneUuid), endpoint, resourceType, resourceIdentity, errorCode); + } + + @Override + public void validateEndpointMatchesIpVersion(String zoneUuid, String ipVersion, String endpoint, + String resourceType, String resourceIdentity, String errorCode) { + if (zoneUuid == null || ipVersion == null || endpoint == null) { + return; + } + + if (ManagementNetworkIpVersionUtils.isIpv6LinkLocalEndpoint(endpoint)) { + throw new ApiMessageInterceptionException(argerr( + ORG_ZSTACK_COMPUTE_ZONE_10007, + "%s[%s] uses IPv6 link-local endpoint[%s], which is not supported for zone[uuid:%s] management network", + resourceType, resourceIdentity, endpoint, zoneUuid)); + } + + String endpointIpVersion = ManagementNetworkIpVersionUtils.getEndpointIpVersion(endpoint); + if (endpointIpVersion == null || endpointIpVersion.equals(ipVersion)) { + return; + } + + throw new ApiMessageInterceptionException(argerr(errorCode, MISMATCH_ERROR, + resourceType, resourceIdentity, endpointIpVersion, endpoint, zoneUuid, ipVersion)); + } + + @Override + public String getZoneIpVersion(String zoneUuid) { + Map tokens = ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION.getTokensByResourceUuid(zoneUuid); + if (tokens == null) { + return DEFAULT_ZONE_IP_VERSION; + } + + return ManagementNetworkIpVersionUtils.normalizeIpVersion( + tokens.get(ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION_TOKEN)); + } + + @Override + public void validateZoneCompatibleWithExistingResources(String zoneUuid, String ipVersion) { + validateExistingHosts(zoneUuid, ipVersion); + for (ManagementNetworkIpVersionResourceExtensionPoint ext : + pluginRgty.getExtensionList(ManagementNetworkIpVersionResourceExtensionPoint.class)) { + ext.validateExistingResourcesInZone(zoneUuid, ipVersion); + } + } + + public void validateZoneIpVersionTag(String resourceUuid, String systemTag) { + validateZoneIpVersionTag(resourceUuid, systemTag, null); + } + + public void validateZoneIpVersionTag(String resourceUuid, String systemTag, String excludedTagUuid) { + validateZoneIpVersionTagValue(resourceUuid, systemTag); + validateZoneHasNoOtherIpVersionTag(resourceUuid, excludedTagUuid); + } + + public void validateZoneIpVersionTagValue(String resourceUuid, String systemTag) { + if (!ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION.isMatch(systemTag)) { + return; + } + + if (!dbf.isExist(resourceUuid, ZoneVO.class)) { + return; + } + + String ipVersion = ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION.getTokenByTag( + systemTag, + ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION_TOKEN); + String normalizedIpVersion = ManagementNetworkIpVersionUtils.normalizeIpVersion(ipVersion); + if (normalizedIpVersion == null) { + throw new ApiMessageInterceptionException(argerr( + ORG_ZSTACK_COMPUTE_ZONE_10004, + "management network ipVersion[%s] is invalid, allowed values are [%s, %s]", + ipVersion, + ManagementNetworkIpVersionUtils.IPV4, + ManagementNetworkIpVersionUtils.IPV6)); + } + + validateZoneCompatibleWithExistingResources(resourceUuid, normalizedIpVersion); + } + + private void validateZoneHasNoOtherIpVersionTag(String zoneUuid, String excludedTagUuid) { + for (SystemTagInventory tag : ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION.getTagInventories(zoneUuid)) { + if (excludedTagUuid != null && excludedTagUuid.equals(tag.getUuid())) { + continue; + } + + throw new ApiMessageInterceptionException(argerr( + ORG_ZSTACK_COMPUTE_ZONE_10006, + "zone[uuid:%s] already has management network ipVersion system tag[%s], update or delete it before creating another one", + zoneUuid, tag.getTag())); + } + } + + private void validateExistingHosts(String zoneUuid, String ipVersion) { + List hosts = Q.New(HostVO.class) + .eq(HostVO_.zoneUuid, zoneUuid) + .list(); + + for (HostVO host : hosts) { + validateEndpointMatchesIpVersion(zoneUuid, ipVersion, host.getManagementIp(), + HOST_RESOURCE_TYPE, host.getUuid(), ORG_ZSTACK_COMPUTE_ZONE_10005); + } + } +} diff --git a/compute/src/main/java/org/zstack/compute/zone/ZoneManagerImpl.java b/compute/src/main/java/org/zstack/compute/zone/ZoneManagerImpl.java index e450fa75f9b..1537ed30318 100755 --- a/compute/src/main/java/org/zstack/compute/zone/ZoneManagerImpl.java +++ b/compute/src/main/java/org/zstack/compute/zone/ZoneManagerImpl.java @@ -20,9 +20,13 @@ import org.zstack.header.exception.CloudRuntimeException; import org.zstack.header.message.APIMessage; import org.zstack.header.message.Message; +import org.zstack.header.tag.AbstractSystemTagOperationJudger; +import org.zstack.header.tag.SystemTagInventory; +import org.zstack.header.tag.SystemTagValidator; import org.zstack.header.zone.*; import org.zstack.search.SearchQuery; import org.zstack.tag.TagManager; +import org.zstack.utils.network.ManagementNetworkIpVersionUtils; import org.zstack.utils.ObjectUtils; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; @@ -51,9 +55,13 @@ public class ZoneManagerImpl extends AbstractService implements ZoneManager { private TagManager tagMgr; @Autowired private ThreadFacade thdf; + @Autowired + private ManagementNetworkIpVersionManagerImpl managementNetworkIpVersionManager; private Map zoneFactories = Collections.synchronizedMap(new HashMap()); private static final Set allowedMessageAfterSoftDeletion = new HashSet(); + private static final String DEFAULT_MANAGEMENT_NETWORK_IP_VERSION_TAG = + String.format("managementNetwork::ipVersion::%s", ManagementNetworkIpVersionUtils.IPV4); static { allowedMessageAfterSoftDeletion.add(ZoneDeletionMsg.class); @@ -156,10 +164,22 @@ protected void scripts() { }.execute(); tagMgr.createTagsFromAPICreateMessage(msg, finalVO.getUuid(), ZoneVO.class.getSimpleName()); + createDefaultManagementNetworkIpVersionTagIfAbsent(finalVO.getUuid()); return ZoneInventory.valueOf(finalVO); } + private void createDefaultManagementNetworkIpVersionTagIfAbsent(String zoneUuid) { + if (ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION.getTagInventory(zoneUuid) != null) { + return; + } + + tagMgr.createNonInherentSystemTag( + zoneUuid, + DEFAULT_MANAGEMENT_NETWORK_IP_VERSION_TAG, + ZoneVO.class.getSimpleName()); + } + private void createZone(APICreateZoneMsg msg, ReturnValueCompletion completion) { if (msg.getDefault() == null || !msg.getDefault()) { completion.success(createZoneFromApiMessage(msg)); @@ -225,6 +245,31 @@ private void populateExtensions() { @Override public boolean start() { populateExtensions(); + ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION.installValidator(new SystemTagValidator() { + @Override + public void validateSystemTag(String resourceUuid, Class resourceType, String systemTag) { + managementNetworkIpVersionManager.validateZoneIpVersionTagValue(resourceUuid, systemTag); + } + }); + ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION.installJudger(new AbstractSystemTagOperationJudger() { + @Override + public void tagPreCreated(SystemTagInventory tag) { + managementNetworkIpVersionManager.validateZoneIpVersionTag( + tag.getResourceUuid(), tag.getTag()); + } + + @Override + public void tagPreUpdated(SystemTagInventory old, SystemTagInventory newTag) { + managementNetworkIpVersionManager.validateZoneIpVersionTag( + newTag.getResourceUuid(), newTag.getTag(), old.getUuid()); + } + + @Override + public void tagPreDeleted(SystemTagInventory tag) { + managementNetworkIpVersionManager.validateZoneCompatibleWithExistingResources( + tag.getResourceUuid(), ManagementNetworkIpVersionUtils.IPV4); + } + }); return true; } diff --git a/compute/src/main/java/org/zstack/compute/zone/ZoneSystemTags.java b/compute/src/main/java/org/zstack/compute/zone/ZoneSystemTags.java index e2d68ff9bd8..8de485355e1 100755 --- a/compute/src/main/java/org/zstack/compute/zone/ZoneSystemTags.java +++ b/compute/src/main/java/org/zstack/compute/zone/ZoneSystemTags.java @@ -10,4 +10,9 @@ public class ZoneSystemTags { public static PatternedSystemTag HOST_RESERVED_CPU_CAPACITY = new PatternedSystemTag("host::reservedCpu::{capacity}", ZoneVO.class); public static PatternedSystemTag HOST_RESERVED_MEMORY_CAPACITY = new PatternedSystemTag("host::reservedMemory::{capacity}", ZoneVO.class); + public static final String MANAGEMENT_NETWORK_IP_VERSION_TOKEN = "ipVersion"; + public static PatternedSystemTag MANAGEMENT_NETWORK_IP_VERSION = new PatternedSystemTag( + String.format("managementNetwork::ipVersion::{%s}", MANAGEMENT_NETWORK_IP_VERSION_TOKEN), + ZoneVO.class + ); } diff --git a/conf/db/upgrade/V5.5.28__schema.sql b/conf/db/upgrade/V5.5.28__schema.sql index 80ba45b1b82..43958fc4b21 100644 --- a/conf/db/upgrade/V5.5.28__schema.sql +++ b/conf/db/upgrade/V5.5.28__schema.sql @@ -165,3 +165,21 @@ CREATE TABLE IF NOT EXISTS `zstack`.`ResourceSourceRefVO` ( KEY `idxResourceSourceRefVOResourceSync` (`resourceType`, `resourceUuid`, `syncType`), KEY `idxResourceSourceRefVOSyncType` (`syncType`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `zstack`.`VtepVO` MODIFY COLUMN `vtepIp` varchar(128) NOT NULL; +ALTER TABLE `zstack`.`RemoteVtepVO` MODIFY COLUMN `vtepIp` varchar(128) NOT NULL; + +INSERT INTO `zstack`.`SystemTagVO` (`uuid`, `resourceUuid`, `resourceType`, `inherent`, `type`, `tag`, `createDate`, `lastOpDate`) +SELECT REPLACE(UUID(), '-', ''), z.uuid, 'ZoneVO', 0, 'System', 'managementNetwork::ipVersion::ipv4', CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP() +FROM `zstack`.`ZoneVO` z +WHERE NOT EXISTS ( + SELECT 1 + FROM `zstack`.`SystemTagVO` st + WHERE st.resourceUuid = z.uuid + AND st.resourceType = 'ZoneVO' + AND st.type = 'System' + AND st.tag LIKE 'managementNetwork::ipVersion::%' +); + +ALTER TABLE `zstack`.`ConsoleProxyAgentVO` ADD COLUMN `consoleProxyOverriddenIpv4` varchar(255) DEFAULT NULL; +ALTER TABLE `zstack`.`ConsoleProxyAgentVO` ADD COLUMN `consoleProxyOverriddenIpv6` varchar(255) DEFAULT NULL; diff --git a/conf/deploydb.sh b/conf/deploydb.sh index 033da079954..c0d27e12d41 100755 --- a/conf/deploydb.sh +++ b/conf/deploydb.sh @@ -8,6 +8,16 @@ password="$2" host="$3" port="$4" zstack_user_password="$5" +mysql_host="$host" + +case "$mysql_host" in + \[*\]) mysql_host="${mysql_host#\[}"; mysql_host="${mysql_host%\]}" ;; +esac + +jdbc_host="$mysql_host" +case "$jdbc_host" in + *:*) jdbc_host="[$jdbc_host]" ;; +esac base=`dirname $0` @@ -30,7 +40,7 @@ if command -v greatdb &> /dev/null; then fi mysql_run() { - $MYSQL --user=$user --password=$password --host=$host --port=$port "$@" + $MYSQL --user=$user --password=$password --host=$mysql_host --port=$port "$@" } if command -v greatdb &> /dev/null; then @@ -67,7 +77,7 @@ mkdir -p $flyway_sql cp $base/db/V0.6__schema.sql $flyway_sql cp $base/db/upgrade/* $flyway_sql -url="jdbc:mysql://$host:$port/zstack" +url="jdbc:mysql://$jdbc_host:$port/zstack" bash $flyway -user=$user -password=$password -url=$url clean @@ -81,7 +91,7 @@ eval "rm -f $flyway_sql/*" cp $base/db/V0.6__schema_buildin_httpserver.sql $flyway_sql -url="jdbc:mysql://$host:$port/zstack_rest" +url="jdbc:mysql://$jdbc_host:$port/zstack_rest" bash $flyway -user=$user -password=$password -url=$url clean bash $flyway -user=$user -password=$password -url=$url migrate @@ -92,7 +102,7 @@ hostname=`hostname` [ -z $zstack_user_password ] && zstack_user_password='' if command -v greatdb &> /dev/null; then - $MYSQL --user=$user --password=$password --host=$host --port=$port << EOF + $MYSQL --user=$user --password=$password --host=$mysql_host --port=$port << EOF drop user if exists zstack; drop user if exists zstack_rest; create user if not exists 'zstack'@'localhost' identified by "$zstack_user_password"; @@ -110,7 +120,7 @@ EOF else db_version=`$MYSQL --version | awk '/Distrib/{print $5}' |awk -F'.' '{print $1}'` if [ $db_version -ge 10 ];then - $MYSQL --user=$user --password=$password --host=$host --port=$port << EOF + $MYSQL --user=$user --password=$password --host=$mysql_host --port=$port << EOF drop user if exists zstack; drop user if exists zstack_rest; create user 'zstack' identified by "$zstack_user_password"; @@ -122,7 +132,7 @@ else flush privileges; EOF else - $MYSQL --user=$user --password=$password --host=$host --port=$port << EOF + $MYSQL --user=$user --password=$password --host=$mysql_host --port=$port << EOF grant usage on *.* to 'zstack'@'localhost'; grant usage on *.* to 'zstack'@'%'; drop user zstack; @@ -137,4 +147,3 @@ EOF EOF fi fi - diff --git a/conf/deployuidb.sh b/conf/deployuidb.sh index 16a7e659576..cba144bdcad 100755 --- a/conf/deployuidb.sh +++ b/conf/deployuidb.sh @@ -6,6 +6,16 @@ password="$2" host="$3" port="$4" zstack_ui_db_password="$5" +mysql_host="$host" + +case "$mysql_host" in + \[*\]) mysql_host="${mysql_host#\[}"; mysql_host="${mysql_host%\]}" ;; +esac + +jdbc_host="$mysql_host" +case "$jdbc_host" in + *:*) jdbc_host="[$jdbc_host]" ;; +esac MYSQL='mysql' @@ -27,18 +37,18 @@ flyway_sql="$base/tools/flyway-3.2.1/sql/" # give grant option to the new management ip after `zstack-ctl change_ip` if command -v greatdb &> /dev/null; then $MYSQL --user=$user --password=$password --port=$port << EOF - grant all privileges on *.* to 'root'@"$host" with grant option; + grant all privileges on *.* to 'root'@"$mysql_host" with grant option; FLUSH PRIVILEGES; EOF else $MYSQL --user=$user --password=$password --port=$port << EOF - grant all privileges on *.* to 'root'@"$host" identified by "$password" with grant option; + grant all privileges on *.* to 'root'@"$mysql_host" identified by "$password" with grant option; FLUSH PRIVILEGES; EOF fi if command -v greatdb &> /dev/null; then - $MYSQL --user=$user --password=$password --host=$host --port=$port << EOF + $MYSQL --user=$user --password=$password --host=$mysql_host --port=$port << EOF grant usage on *.* to 'root'@'localhost'; grant usage on *.* to 'root'@'%'; DROP DATABASE IF EXISTS zstack_ui; @@ -50,7 +60,7 @@ if command -v greatdb &> /dev/null; then flush privileges; EOF else - $MYSQL --user=$user --password=$password --host=$host --port=$port << EOF + $MYSQL --user=$user --password=$password --host=$mysql_host --port=$port << EOF grant usage on *.* to 'root'@'localhost'; grant usage on *.* to 'root'@'%'; DROP DATABASE IF EXISTS zstack_ui; @@ -67,7 +77,7 @@ mkdir -p $flyway_sql ui_schema_path=`echo ~zstack`"/zstack-ui/tmp/WEB-INF/classes/db/migration/" if [ -d $ui_schema_path ]; then cp $ui_schema_path/* $flyway_sql - url="jdbc:mysql://$host:$port/zstack_ui" + url="jdbc:mysql://$jdbc_host:$port/zstack_ui" bash $flyway -user=$user -password=$password -url=$url clean bash $flyway -user=$user -password=$password -url=$url migrate eval "rm -f $flyway_sql/*" @@ -76,7 +86,7 @@ fi hostname=`hostname` if command -v greatdb &> /dev/null; then - $MYSQL --user=$user --password=$password --host=$host --port=$port << EOF + $MYSQL --user=$user --password=$password --host=$mysql_host --port=$port << EOF drop user if exists zstack_ui; create user 'zstack_ui' identified by "$zstack_ui_db_password"; create user if not exists 'zstack_ui'@'localhost' identified by "$zstack_ui_db_password"; @@ -88,7 +98,7 @@ EOF else db_version=`$MYSQL --version | awk '/Distrib/{print $5}' |awk -F'.' '{print $1}'` if [ $db_version -ge 10 ];then - $MYSQL --user=$user --password=$password --host=$host --port=$port << EOF + $MYSQL --user=$user --password=$password --host=$mysql_host --port=$port << EOF drop user if exists zstack_ui; create user 'zstack_ui' identified by "$zstack_ui_db_password"; grant all privileges on zstack_ui.* to zstack_ui@'localhost' identified by "$zstack_ui_db_password"; @@ -96,7 +106,7 @@ else flush privileges; EOF else - $MYSQL --user=$user --password=$password --host=$host --port=$port << EOF + $MYSQL --user=$user --password=$password --host=$mysql_host --port=$port << EOF grant usage on *.* to 'zstack_ui'@'localhost'; grant usage on *.* to 'zstack_ui'@'%'; drop user zstack_ui; diff --git a/conf/springConfigXml/DatabaseFacade.xml b/conf/springConfigXml/DatabaseFacade.xml index d7afee98688..44f93eae20b 100755 --- a/conf/springConfigXml/DatabaseFacade.xml +++ b/conf/springConfigXml/DatabaseFacade.xml @@ -78,7 +78,7 @@ infinispan searchConfig/default-infinispan.xml ${Exclusive.indexUse:false} - jgroups + ${Search.backend:jgroups} searchConfig/jgroup-backend-tcp.xml \n") } - + return out } else { return errorOut(a.call()) @@ -3695,20 +3695,20 @@ abstract class ApiHelper { 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()) @@ -5747,19 +5747,20 @@ abstract class ApiHelper { 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()) @@ -9823,20 +9824,20 @@ abstract class ApiHelper { 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()) @@ -15034,20 +15035,20 @@ abstract class ApiHelper { 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()) @@ -19948,19 +19949,20 @@ abstract class ApiHelper { 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()) @@ -20136,19 +20138,20 @@ abstract class ApiHelper { 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()) @@ -20264,26 +20267,26 @@ abstract class ApiHelper { } - def extendHostCacheStore(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExtendHostCacheStoreAction.class) Closure c) { - def a = new org.zstack.sdk.ExtendHostCacheStoreAction() + def exportBuildApp(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExportBuildAppAction.class) Closure c) { + def a = new org.zstack.sdk.ExportBuildAppAction() 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()) @@ -20291,8 +20294,8 @@ abstract class ApiHelper { } - def exportBuildApp(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExportBuildAppAction.class) Closure c) { - def a = new org.zstack.sdk.ExportBuildAppAction() + def exportImageFromBackupStorage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExportImageFromBackupStorageAction.class) Closure c) { + def a = new org.zstack.sdk.ExportImageFromBackupStorageAction() a.sessionId = Test.currentEnvSpec?.session?.uuid c.resolveStrategy = Closure.OWNER_FIRST c.delegate = a @@ -20318,8 +20321,8 @@ abstract class ApiHelper { } - def exportImageFromBackupStorage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExportImageFromBackupStorageAction.class) Closure c) { - def a = new org.zstack.sdk.ExportImageFromBackupStorageAction() + def exportNbdVolumes(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExportNbdVolumesAction.class) Closure c) { + def a = new org.zstack.sdk.ExportNbdVolumesAction() a.sessionId = Test.currentEnvSpec?.session?.uuid c.resolveStrategy = Closure.OWNER_FIRST c.delegate = a @@ -20345,8 +20348,8 @@ abstract class ApiHelper { } - def exportNbdVolumes(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExportNbdVolumesAction.class) Closure c) { - def a = new org.zstack.sdk.ExportNbdVolumesAction() + def exportVmOvaPackage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExportVmOvaPackageAction.class) Closure c) { + def a = new org.zstack.sdk.ExportVmOvaPackageAction() a.sessionId = Test.currentEnvSpec?.session?.uuid c.resolveStrategy = Closure.OWNER_FIRST c.delegate = a @@ -20372,8 +20375,8 @@ abstract class ApiHelper { } - def exportVmOvaPackage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExportVmOvaPackageAction.class) Closure c) { - def a = new org.zstack.sdk.ExportVmOvaPackageAction() + def expungeBaremetalInstance(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExpungeBaremetalInstanceAction.class) Closure c) { + def a = new org.zstack.sdk.ExpungeBaremetalInstanceAction() a.sessionId = Test.currentEnvSpec?.session?.uuid c.resolveStrategy = Closure.OWNER_FIRST c.delegate = a @@ -20399,8 +20402,8 @@ abstract class ApiHelper { } - def expungeBaremetalInstance(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExpungeBaremetalInstanceAction.class) Closure c) { - def a = new org.zstack.sdk.ExpungeBaremetalInstanceAction() + def expungeDataVolume(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExpungeDataVolumeAction.class) Closure c) { + def a = new org.zstack.sdk.ExpungeDataVolumeAction() a.sessionId = Test.currentEnvSpec?.session?.uuid c.resolveStrategy = Closure.OWNER_FIRST c.delegate = a @@ -20426,8 +20429,8 @@ abstract class ApiHelper { } - def expungeDataVolume(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExpungeDataVolumeAction.class) Closure c) { - def a = new org.zstack.sdk.ExpungeDataVolumeAction() + def expungeImage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExpungeImageAction.class) Closure c) { + def a = new org.zstack.sdk.ExpungeImageAction() a.sessionId = Test.currentEnvSpec?.session?.uuid c.resolveStrategy = Closure.OWNER_FIRST c.delegate = a @@ -20453,8 +20456,8 @@ abstract class ApiHelper { } - def expungeImage(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExpungeImageAction.class) Closure c) { - def a = new org.zstack.sdk.ExpungeImageAction() + def expungeImageGroup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExpungeImageGroupAction.class) Closure c) { + def a = new org.zstack.sdk.ExpungeImageGroupAction() a.sessionId = Test.currentEnvSpec?.session?.uuid c.resolveStrategy = Closure.OWNER_FIRST c.delegate = a @@ -20480,8 +20483,8 @@ abstract class ApiHelper { } - def expungeImageGroup(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExpungeImageGroupAction.class) Closure c) { - def a = new org.zstack.sdk.ExpungeImageGroupAction() + def expungeVmInstance(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExpungeVmInstanceAction.class) Closure c) { + def a = new org.zstack.sdk.ExpungeVmInstanceAction() a.sessionId = Test.currentEnvSpec?.session?.uuid c.resolveStrategy = Closure.OWNER_FIRST c.delegate = a @@ -20507,8 +20510,8 @@ abstract class ApiHelper { } - def expungeVmInstance(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExpungeVmInstanceAction.class) Closure c) { - def a = new org.zstack.sdk.ExpungeVmInstanceAction() + def expungeVmUserDefinedXmlHookScript(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExpungeVmUserDefinedXmlHookScriptAction.class) Closure c) { + def a = new org.zstack.sdk.ExpungeVmUserDefinedXmlHookScriptAction() a.sessionId = Test.currentEnvSpec?.session?.uuid c.resolveStrategy = Closure.OWNER_FIRST c.delegate = a @@ -20534,8 +20537,8 @@ abstract class ApiHelper { } - def expungeVmUserDefinedXmlHookScript(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExpungeVmUserDefinedXmlHookScriptAction.class) Closure c) { - def a = new org.zstack.sdk.ExpungeVmUserDefinedXmlHookScriptAction() + def extendHostCacheStore(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.ExtendHostCacheStoreAction.class) Closure c) { + def a = new org.zstack.sdk.ExtendHostCacheStoreAction() a.sessionId = Test.currentEnvSpec?.session?.uuid c.resolveStrategy = Closure.OWNER_FIRST c.delegate = a @@ -21458,20 +21461,20 @@ abstract class ApiHelper { 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()) @@ -23884,24 +23887,24 @@ abstract class ApiHelper { def getLicenseAuthorizationInfo(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.GetLicenseAuthorizationInfoAction.class) Closure c) { def a = new org.zstack.sdk.GetLicenseAuthorizationInfoAction() - + 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()) @@ -23915,20 +23918,20 @@ abstract class ApiHelper { 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()) @@ -32208,7 +32211,7 @@ abstract class ApiHelper { c.resolveStrategy = Closure.OWNER_FIRST c.delegate = a c() - + a.conditions = a.conditions.collect { it.toString() } @@ -32216,14 +32219,14 @@ abstract class ApiHelper { if (a.apiId == null) { a.apiId = Platform.uuid } - + def tracker = new ApiPathTracker(a.apiId) def out = errorOut(a.call()) def path = tracker.getApiPath() if (!path.isEmpty()) { Test.apiPaths[a.class.name] = path.join(" --->\n") } - + return out } else { return errorOut(a.call()) @@ -35131,6 +35134,35 @@ abstract class ApiHelper { } + def queryResourceSourceRef(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryResourceSourceRefAction.class) Closure c) { + def a = new org.zstack.sdk.QueryResourceSourceRefAction() + 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 queryResourceStack(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.QueryResourceStackAction.class) Closure c) { def a = new org.zstack.sdk.QueryResourceStackAction() a.sessionId = Test.currentEnvSpec?.session?.uuid @@ -38042,20 +38074,20 @@ abstract class ApiHelper { 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()) @@ -42551,20 +42583,20 @@ abstract class ApiHelper { 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()) @@ -45791,20 +45823,20 @@ abstract class ApiHelper { 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()) @@ -48410,20 +48442,20 @@ abstract class ApiHelper { 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()) @@ -50466,6 +50498,33 @@ abstract class ApiHelper { } + def configureIAM2ScimReceiver(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.iam2.api.ConfigureIAM2ScimReceiverAction.class) Closure c) { + def a = new org.zstack.sdk.iam2.api.ConfigureIAM2ScimReceiverAction() + 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 createIAM2Organization(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.iam2.api.CreateIAM2OrganizationAction.class) Closure c) { def a = new org.zstack.sdk.iam2.api.CreateIAM2OrganizationAction() a.sessionId = Test.currentEnvSpec?.session?.uuid