mirror of https://github.com/apache/cloudstack.git
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
This commit is contained in:
parent
f54cb50d17
commit
57609c79c4
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
Loading…
Reference in New Issue