This is an automated email from the ASF dual-hosted git repository. pearl11594 pushed a commit to branch netris-update-vpc-and-tier-names in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit 57609c79c42bd1a0debab6cf9fbc37d8c6ca56a3 Author: Pearl Dsilva <pearl1...@gmail.com> AuthorDate: Sat Jan 11 21:12:32 2025 -0500 Add support to add IPv6 Public IP range as IPAM Allocation / Subnet on Netris (#36) * Add support to add IPv6 Public IP range as IPAM Allocation / Subnet on Netris * Add ipam alloc and subnet for the ipv6 subnet associated to the vpc tier network * remove commented code --- .../engine/orchestration/NetworkOrchestrator.java | 8 +++ .../src/main/java/com/cloud/dc/dao/VlanDao.java | 2 + .../main/java/com/cloud/dc/dao/VlanDaoImpl.java | 27 ++++++++ .../agent/api/CreateNetrisVnetCommand.java | 9 +++ .../cloudstack/service/NetrisApiClientImpl.java | 34 +++++++--- .../cloudstack/service/NetrisServiceImpl.java | 77 +++++++++++----------- .../java/com/cloud/network/NetworkServiceImpl.java | 4 -- ui/src/views/infra/network/IpRangesTabPublic.vue | 10 +++ 8 files changed, 121 insertions(+), 50 deletions(-) diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 99a3ec3caca..7e1ca652f47 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -43,6 +43,7 @@ import com.cloud.bgp.BGPService; import com.cloud.dc.VlanDetailsVO; import com.cloud.dc.dao.ASNumberDao; import com.cloud.dc.dao.VlanDetailsDao; +import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao; import com.cloud.network.dao.NetrisProviderDao; import com.cloud.network.dao.NsxProviderDao; import org.apache.cloudstack.acl.ControlledEntity.ACLType; @@ -361,6 +362,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra private ASNumberDao asNumberDao; @Inject private BGPService bgpService; + @Inject + private Ipv6GuestPrefixSubnetNetworkMapDao ipv6GuestPrefixSubnetNetworkMapDao; @Override public List<NetworkGuru> getNetworkGurus() { @@ -824,6 +827,11 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (domainId != null && aclType == ACLType.Domain) { _networksDao.addDomainToNetwork(id, domainId, subdomainAccess == null || subdomainAccess); } + String ipv6Cidr = network.getIp6Cidr(); + String ipv6Gateway = network.getIp6Gateway(); + if (StringUtils.isNoneBlank(ipv6Cidr, ipv6Gateway)) { + ipv6Service.assignIpv6SubnetToNetwork(ipv6Cidr, networkPersisted.getId()); + } } }); guru.setup(network, relatedFile); diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java index 84f38f05441..a6c267bb189 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java @@ -64,4 +64,6 @@ public interface VlanDao extends GenericDao<VlanVO, Long> { List<VlanVO> listIpv6RangeByZoneIdAndVlanId(long zoneId, String vlanId); List<VlanVO> listIpv6SupportingVlansByZone(long zoneId); + + List<VlanVO> listVlansForExternalNetworkProvider(long zoneId, String detailKey); } diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java index 461a9a13b10..d9fad3cad12 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java @@ -26,6 +26,7 @@ import java.util.Map; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.dc.VlanDetailsVO; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; @@ -67,6 +68,8 @@ public class VlanDaoImpl extends GenericDaoBase<VlanVO, Long> implements VlanDao protected SearchBuilder<VlanVO> ZoneVlanIp6Search; protected SearchBuilder<VlanVO> ZoneIp6Search; protected SearchBuilder<VlanVO> ZoneVlansSearch; + protected SearchBuilder<VlanVO> ProviderVlanSearch; + protected SearchBuilder<VlanDetailsVO> VlanDetailsProviderSearch; protected SearchBuilder<AccountVlanMapVO> AccountVlanMapSearch; protected SearchBuilder<DomainVlanMapVO> DomainVlanMapSearch; @@ -79,6 +82,8 @@ public class VlanDaoImpl extends GenericDaoBase<VlanVO, Long> implements VlanDao protected DomainVlanMapDao _domainVlanMapDao; @Inject protected IPAddressDao _ipAddressDao; + @Inject + protected VlanDetailsDao vlanDetailsDao; @Override public VlanVO findByZoneAndVlanId(long zoneId, String vlanId) { @@ -277,6 +282,19 @@ public class VlanDaoImpl extends GenericDaoBase<VlanVO, Long> implements VlanDao ZoneVlansSearch.and("zoneId", ZoneVlansSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); ZoneVlansSearch.and("vlan", ZoneVlansSearch.entity().getVlanTag(), SearchCriteria.Op.IN); ZoneVlansSearch.done(); + + ProviderVlanSearch = createSearchBuilder(); + ProviderVlanSearch.and("removed", ProviderVlanSearch.entity().getRemoved(), SearchCriteria.Op.NULL); + ProviderVlanSearch.and("dataCenterId", ProviderVlanSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); + VlanDetailsProviderSearch = vlanDetailsDao.createSearchBuilder(); + VlanDetailsProviderSearch.and("name", VlanDetailsProviderSearch.entity().getName(), SearchCriteria.Op.EQ); + VlanDetailsProviderSearch.and("value", VlanDetailsProviderSearch.entity().getValue(), SearchCriteria.Op.EQ); + ProviderVlanSearch.join("VlanDetailsProviderSearch", VlanDetailsProviderSearch, ProviderVlanSearch.entity().getId(), + VlanDetailsProviderSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); + + VlanDetailsProviderSearch.done(); + ProviderVlanSearch.done(); + return result; } @@ -434,4 +452,13 @@ public class VlanDaoImpl extends GenericDaoBase<VlanVO, Long> implements VlanDao return listBy(sc); } + @Override + public List<VlanVO> listVlansForExternalNetworkProvider(long zoneId, String detailKey) { + SearchCriteria<VlanVO> sc = ProviderVlanSearch.create(); + sc.setParameters("dataCenterId", zoneId); + sc.setJoinParameters("VlanDetailsProviderSearch", "name", detailKey); + sc.setJoinParameters("VlanDetailsProviderSearch", "value", "true"); + return search(sc, null); + } + } diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisVnetCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisVnetCommand.java index 7ba6c9250fd..7095c4549b1 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisVnetCommand.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisVnetCommand.java @@ -23,6 +23,7 @@ public class CreateNetrisVnetCommand extends NetrisCommand { private Integer vxlanId; private String gateway; private String netrisTag; + private String ipv6Cidr; public CreateNetrisVnetCommand(Long zoneId, Long accountId, Long domainId, String vpcName, Long vpcId, String vNetName, Long networkId, String cidr, String gateway, boolean isVpc) { super(zoneId, accountId, domainId, vNetName, networkId, isVpc); @@ -64,4 +65,12 @@ public class CreateNetrisVnetCommand extends NetrisCommand { public void setNetrisTag(String netrisTag) { this.netrisTag = netrisTag; } + + public String getIpv6Cidr() { + return ipv6Cidr; + } + + public void setIpv6Cidr(String ipv6Cidr) { + this.ipv6Cidr = ipv6Cidr; + } } diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java index 8d6d088407e..bfed67a915a 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java @@ -594,6 +594,7 @@ public class NetrisApiClientImpl implements NetrisApiClient { String netrisTag = cmd.getNetrisTag(); String netmask = vnetCidr.split("/")[1]; String netrisGateway = cmd.getGateway() + "/" + netmask; + String netrisV6Cidr = cmd.getIpv6Cidr(); boolean isVpc = cmd.isVpc(); String suffix = getNetrisVpcNameSuffix(vpcId, vpcName, networkId, networkName, isVpc); @@ -614,9 +615,18 @@ public class NetrisApiClientImpl implements NetrisApiClient { String netrisSubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, vnetCidr) ; createIpamSubnetInternal(netrisSubnetName, vnetCidr, SubnetBody.PurposeEnum.COMMON, associatedVpc); + if (Objects.nonNull(netrisV6Cidr)) { + String netrisV6IpamAllocationName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_ALLOCATION, netrisV6Cidr); + String netrisV6SubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, netrisV6Cidr) ; + InlineResponse2004Data createdIpamAllocation = createIpamAllocationInternal(netrisV6IpamAllocationName, netrisV6Cidr, associatedVpc); + if (Objects.isNull(createdIpamAllocation)) { + throw new CloudRuntimeException(String.format("Failed to create Netris IPAM Allocation %s for VPC %s", netrisV6IpamAllocationName, netrisVpcName)); + } + createIpamSubnetInternal(netrisV6SubnetName, netrisV6Cidr, SubnetBody.PurposeEnum.COMMON, associatedVpc); + } logger.debug("Successfully created IPAM Subnet {} for network {} on Netris", netrisSubnetName, networkName); - VnetResAddBody vnetResponse = createVnetInternal(associatedVpc, netrisVnetName, netrisGateway, vxlanId, netrisTag); + VnetResAddBody vnetResponse = createVnetInternal(associatedVpc, netrisVnetName, netrisGateway, netrisV6Cidr, vxlanId, netrisTag); if (vnetResponse == null || !vnetResponse.isIsSuccess()) { String reason = vnetResponse == null ? "Empty response" : "Operation failed on Netris"; logger.debug("The Netris vNet creation {} failed: {}", vNetName, reason); @@ -1107,25 +1117,33 @@ public class NetrisApiClientImpl implements NetrisApiClient { } } - VnetResAddBody createVnetInternal(VPCListing associatedVpc, String netrisVnetName, String netrisGateway, Integer vxlanId, String netrisTag) { + VnetResAddBody createVnetInternal(VPCListing associatedVpc, String netrisVnetName, String netrisGateway, String netrisV6Gateway, Integer vxlanId, String netrisTag) { logger.debug("Creating Netris VPC vNet {} for CIDR {}", netrisVnetName, netrisGateway); try { VnetAddBody vnetBody = new VnetAddBody(); vnetBody.setCustomAnycastMac(""); - VnetAddBodyGateways gateways = new VnetAddBodyGateways(); - gateways.prefix(netrisGateway); - gateways.setDhcpEnabled(false); + VnetAddBodyGateways gatewayV4 = new VnetAddBodyGateways(); + gatewayV4.prefix(netrisGateway); + gatewayV4.setDhcpEnabled(false); VnetAddBodyDhcp dhcp = new VnetAddBodyDhcp(); dhcp.setEnd(""); dhcp.setStart(""); dhcp.setOptionSet(new VnetAddBodyDhcpOptionSet()); - gateways.setDhcp(dhcp); + gatewayV4.setDhcp(dhcp); List<VnetAddBodyGateways> gatewaysList = new ArrayList<>(); - gatewaysList.add(gateways); - vnetBody.setGateways(gatewaysList); + gatewaysList.add(gatewayV4); + + if (Objects.nonNull(netrisV6Gateway)) { + VnetAddBodyGateways gatewayV6 = new VnetAddBodyGateways(); + gatewayV6.prefix(netrisV6Gateway); + gatewayV6.setDhcpEnabled(false); + gatewayV6.setDhcp(dhcp); + gatewaysList.add(gatewayV6); + } + vnetBody.setGateways(gatewaysList); vnetBody.setGuestTenants(new ArrayList<>()); vnetBody.setL3vpn(false); vnetBody.setName(netrisVnetName); diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java index cb2047e32e8..0a9fe4ac239 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java @@ -18,17 +18,15 @@ package org.apache.cloudstack.service; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; -import com.cloud.dc.VlanDetailsVO; import com.cloud.dc.VlanVO; import com.cloud.dc.dao.VlanDao; -import com.cloud.dc.dao.VlanDetailsDao; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.IpAddress; +import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMapVO; import com.cloud.network.Network; import com.cloud.network.Networks; import com.cloud.network.SDNProviderNetworkRule; -import com.cloud.network.dao.IPAddressDao; -import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao; import com.cloud.network.dao.NetrisProviderDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; @@ -37,6 +35,7 @@ import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.element.NetrisProviderVO; import com.cloud.network.netris.NetrisService; import com.cloud.network.vpc.Vpc; +import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import inet.ipaddr.IPAddress; @@ -82,11 +81,9 @@ public class NetrisServiceImpl implements NetrisService, Configurable { @Inject private PhysicalNetworkDao physicalNetworkDao; @Inject - private IPAddressDao ipAddressDao; - @Inject private VlanDao vlanDao; @Inject - private VlanDetailsDao vlanDetailsDao; + private Ipv6GuestPrefixSubnetNetworkMapDao ipv6PrefixNetworkMapDao; @Override public String getConfigComponentName() { @@ -138,10 +135,10 @@ public class NetrisServiceImpl implements NetrisService, Configurable { /** * Prepare the Netris Public Range to be used by CloudStack after the zone is created and the Netris provider is added */ - public SetupNetrisPublicRangeCommand createSetupPublicRangeCommand(long zoneId, String gateway, String netmask, String ipRange) { + private Pair<String, String> getAllocationAndSubnet(String gateway, String netmask, String ipRange) { String superCidr = NetUtils.getCidrFromGatewayAndNetmask(gateway, netmask); String subnetNatCidr = calculateSubnetCidrFromIpRange(ipRange); - return new SetupNetrisPublicRangeCommand(zoneId, superCidr, subnetNatCidr); + return new Pair<>(superCidr, subnetNatCidr); } @Override @@ -151,38 +148,38 @@ public class NetrisServiceImpl implements NetrisService, Configurable { if (CollectionUtils.isEmpty(physicalNetworks)) { return false; } - for (PhysicalNetworkVO physicalNetwork : physicalNetworks) { - List<IPAddressVO> publicIps = ipAddressDao.listByPhysicalNetworkId(physicalNetwork.getId()); - List<Long> vlanDbIds = publicIps.stream() - .filter(x -> !x.isForSystemVms()) - .map(IPAddressVO::getVlanId) - .collect(Collectors.toList()); - if (CollectionUtils.isEmpty(vlanDbIds)) { - String msg = "Cannot find a public IP range VLAN range for the Netris Public traffic"; - logger.error(msg); - throw new CloudRuntimeException(msg); + + List<VlanVO> providerVlanIds = vlanDao.listVlansForExternalNetworkProvider(zoneId, ApiConstants.NETRIS_DETAIL_KEY); + List<Long> vlanDbIds = providerVlanIds.stream().map(VlanVO::getId).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(vlanDbIds)) { + String msg = "Cannot find a public IP range VLAN range for the Netris Public traffic"; + logger.error(msg); + throw new CloudRuntimeException(msg); + } + for (Long vlanDbId : vlanDbIds) { + VlanVO vlanRecord = vlanDao.findById(vlanDbId); + + String gateway = Objects.nonNull(vlanRecord.getVlanGateway()) ? vlanRecord.getVlanGateway() : vlanRecord.getIp6Gateway(); + String netmask = vlanRecord.getVlanNetmask(); + String ipRange = vlanRecord.getIpRange(); + String ip6Cidr = vlanRecord.getIp6Cidr(); + SetupNetrisPublicRangeCommand cmd = null; + if (NetUtils.isValidIp4(gateway)) { + Pair<String, String> allocationAndSubnet = getAllocationAndSubnet(gateway, netmask, ipRange); + cmd = new SetupNetrisPublicRangeCommand(zoneId, allocationAndSubnet.first(), allocationAndSubnet.second()); + } else if (NetUtils.isValidIp6(gateway)) { + cmd = new SetupNetrisPublicRangeCommand(zoneId, ip6Cidr, ip6Cidr); } - for (Long vlanDbId : vlanDbIds) { - VlanVO vlanRecord = vlanDao.findById(vlanDbId); - if (vlanRecord == null) { - logger.error("Cannot set up the Netris Public IP range as it cannot find the public range on database"); - return false; - } - VlanDetailsVO vlanDetail = vlanDetailsDao.findDetail(vlanDbId, ApiConstants.NETRIS_DETAIL_KEY); - if (vlanDetail == null) { - logger.debug("Skipping the Public IP range {} creation on Netris as it does not belong to the Netris Public IP Pool", vlanRecord.getIpRange()); - continue; - } - String gateway = vlanRecord.getVlanGateway(); - String netmask = vlanRecord.getVlanNetmask(); - String ipRange = vlanRecord.getIpRange(); - SetupNetrisPublicRangeCommand cmd = createSetupPublicRangeCommand(zoneId, gateway, netmask, ipRange); - NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); - if (!answer.getResult()) { - throw new CloudRuntimeException("Netris Public IP Range setup failed, please check the logs"); - } + + if (cmd == null) { + throw new CloudRuntimeException("Incorrect gateway and netmask details provided for the Netris Public IP range setup"); + } + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + if (!answer.getResult()) { + throw new CloudRuntimeException("Netris Public IP Range setup failed, please check the logs"); } } + return true; } @@ -208,6 +205,10 @@ public class NetrisServiceImpl implements NetrisService, Configurable { cmd.setVxlanId(Integer.parseInt(vxlanId)); NetrisProviderVO netrisProvider = netrisProviderDao.findByZoneId(zoneId); cmd.setNetrisTag(netrisProvider.getNetrisTag()); + if (Objects.nonNull(networkId)) { + Ipv6GuestPrefixSubnetNetworkMapVO ipv6PrefixNetworkMapVO = ipv6PrefixNetworkMapDao.findByNetworkId(networkId); + cmd.setIpv6Cidr(ipv6PrefixNetworkMapVO.getSubnet()); + } NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); return answer.getResult(); } diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index 15ff36b6c9e..3d218f3b0a5 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -1800,10 +1800,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C _networkDetailsDao.persist(new NetworkDetailVO(network.getId(), Network.hideIpAddressUsage, String.valueOf(hideIpAddressUsage), false)); } - if (ip6GatewayCidr != null) { - ipv6Service.assignIpv6SubnetToNetwork(ip6Cidr, network.getId()); - } - // assign to network if (NetworkOffering.NetworkMode.ROUTED.equals(ntwkOff.getNetworkMode())) { routedIpv4Manager.assignIpv4SubnetToNetwork(network); diff --git a/ui/src/views/infra/network/IpRangesTabPublic.vue b/ui/src/views/infra/network/IpRangesTabPublic.vue index 0f3610f5e05..62f2418c975 100644 --- a/ui/src/views/infra/network/IpRangesTabPublic.vue +++ b/ui/src/views/infra/network/IpRangesTabPublic.vue @@ -230,6 +230,16 @@ <a-form-item name="ip6cidr" ref="ip6cidr" :label="$t('label.cidr')" class="form__item"> <a-input v-model:value="form.ip6cidr" /> </a-form-item> + <a-form-item name="provider" ref="provider"> + <template #label> + <tooltip-label :title="$t('label.provider')"/> + </template> + <a-select v-model:value="form.provider"> + <a-select-option value=""></a-select-option> + <a-select-option value="NSX">{{ $t('label.nsx') }}</a-select-option> + <a-select-option value="Netris">{{ $t('label.netris') }}</a-select-option> + </a-select> + </a-form-item> </div> <div v-else> <a-form-item name="gateway" ref="gateway" :label="$t('label.gateway')" class="form__item">