mirror of https://github.com/apache/cloudstack.git
CLOUDSTACK-10218: Fix for forced network update in a nuage network (#2445)
Fix for forced network update to a nuage network offering with vr fails with IllegalArgumentException. Addressed review comments DaanHoogland.
This commit is contained in:
parent
0befb2cceb
commit
8949efe8d1
|
|
@ -89,10 +89,10 @@ public class AssociateNuageVspDomainTemplateCmd extends BaseCmd {
|
|||
@Override
|
||||
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException {
|
||||
try {
|
||||
boolean result =_nuageVspManager.associateNuageVspDomainTemplate(this);
|
||||
_nuageVspManager.associateNuageVspDomainTemplate(this);
|
||||
SuccessResponse response = new SuccessResponse(getCommandName());
|
||||
response.setResponseName(getCommandName());
|
||||
response.setSuccess(result);
|
||||
response.setSuccess(true);
|
||||
this.setResponseObject(response);
|
||||
} catch (InvalidParameterValueException invalidParamExcp) {
|
||||
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, invalidParamExcp.getMessage());
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ import com.cloud.network.dao.IPAddressDao;
|
|||
import com.cloud.network.dao.IPAddressVO;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkServiceMapDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.network.dao.PhysicalNetworkDao;
|
||||
import com.cloud.network.dao.PhysicalNetworkVO;
|
||||
import com.cloud.network.manager.NuageVspManager;
|
||||
|
|
@ -276,14 +275,8 @@ public class NuageVspElement extends AdapterBase implements ConnectivityProvider
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!_nuageVspEntityBuilder.usesVirtualRouter(offering.getId())) {
|
||||
// Update broadcast uri if VR is no longer used
|
||||
NetworkVO networkToUpdate = _networkDao.findById(network.getId());
|
||||
String broadcastUriStr = networkToUpdate.getUuid() + "/null";
|
||||
networkToUpdate.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr));
|
||||
_networkDao.update(network.getId(), networkToUpdate);
|
||||
}
|
||||
|
||||
_nuageVspManager.updateBroadcastUri(network);
|
||||
network = _networkDao.findById(network.getId());
|
||||
VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network);
|
||||
List<VspAclRule> ingressFirewallRules = getFirewallRulesToApply(network, FirewallRule.TrafficType.Ingress);
|
||||
List<VspAclRule> egressFirewallRules = getFirewallRulesToApply(network, FirewallRule.TrafficType.Egress);
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru implements Networ
|
|||
VpcDetailVO detail = _vpcDetailsDao.findDetail(network.getVpcId(), NuageVspManager.nuageDomainTemplateDetailName);
|
||||
if (detail != null && network.getNetworkACLId() != null) {
|
||||
s_logger.error("Pre-configured DT are used in combination with ACL lists. Which is not supported.");
|
||||
throw new IllegalArgumentException("CloudStack ACLs are not supported with Nuage Preconfigured Domain Template");
|
||||
throw new IllegalArgumentException("CloudStack ACLs are not supported with Nuage Pre-configured Domain Template");
|
||||
}
|
||||
|
||||
if(detail != null && !_nuageVspManager.checkIfDomainTemplateExist(network.getDomainId(),detail.getValue(),network.getDataCenterId(),null)){
|
||||
|
|
@ -302,7 +302,9 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru implements Networ
|
|||
implemented.setCidr(network.getCidr());
|
||||
}
|
||||
|
||||
VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(implemented, true);
|
||||
implemented.setBroadcastUri(_nuageVspManager.calculateBroadcastUri(implemented));
|
||||
implemented.setBroadcastDomainType(Networks.BroadcastDomainType.Vsp);
|
||||
VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(implemented);
|
||||
|
||||
if (vspNetwork.isShared()) {
|
||||
Boolean previousUnderlay= null;
|
||||
|
|
@ -321,11 +323,6 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru implements Networ
|
|||
}
|
||||
}
|
||||
|
||||
String tenantId = context.getDomain().getName() + "-" + context.getAccount().getAccountId();
|
||||
String broadcastUriStr = implemented.getUuid() + "/" + vspNetwork.getVirtualRouterIp();
|
||||
implemented.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr));
|
||||
implemented.setBroadcastDomainType(Networks.BroadcastDomainType.Vsp);
|
||||
|
||||
boolean implementSucceeded = implement(network.getVpcId(), physicalNetworkId, vspNetwork, implemented, _nuageVspEntityBuilder.buildNetworkDhcpOption(network, offering));
|
||||
|
||||
if (!implementSucceeded) {
|
||||
|
|
@ -340,6 +337,7 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru implements Networ
|
|||
}
|
||||
}
|
||||
|
||||
String tenantId = context.getDomain().getName() + "-" + context.getAccount().getAccountId();
|
||||
s_logger.info("Implemented OK, network " + implemented.getUuid() + " in tenant " + tenantId + " linked to " + implemented.getBroadcastUri());
|
||||
} finally {
|
||||
_networkDao.releaseFromLockTable(network.getId());
|
||||
|
|
@ -430,7 +428,7 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru implements Networ
|
|||
public NicProfile allocate(Network network, NicProfile nic, VirtualMachineProfile vm) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException {
|
||||
if (vm.getType() != VirtualMachine.Type.DomainRouter && _nuageVspEntityBuilder.usesVirtualRouter(network.getNetworkOfferingId())) {
|
||||
VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(network);
|
||||
if (nic != null && nic.getRequestedIPv4() != null && vspNetwork.getVirtualRouterIp().equals(nic.getRequestedIPv4())) {
|
||||
if (nic != null && nic.getRequestedIPv4() != null && nic.getRequestedIPv4().equals(vspNetwork.getVirtualRouterIp())) {
|
||||
DataCenter dc = _dcDao.findById(network.getDataCenterId());
|
||||
s_logger.error("Unable to acquire requested Guest IP address " + nic.getRequestedIPv4() + " because it is reserved for the VR in network " + network);
|
||||
throw new InsufficientVirtualNetworkCapacityException("Unable to acquire requested Guest IP address " + nic.getRequestedIPv4() + " because it is reserved " +
|
||||
|
|
@ -470,14 +468,13 @@ public class NuageVspGuestNetworkGuru extends GuestNetworkGuru implements Networ
|
|||
HostVO nuageVspHost = _nuageVspManager.getNuageVspHost(network.getPhysicalNetworkId());
|
||||
VspNetwork vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(vm.getVirtualMachine().getDomainId(), network);
|
||||
|
||||
if (vm.getType() == VirtualMachine.Type.DomainRouter && vspNetwork.getVirtualRouterIp().equals("null")) {
|
||||
//In case of upgrade network offering
|
||||
vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(vm.getVirtualMachine().getDomainId(), network, null, true);
|
||||
String broadcastUriStr = network.getUuid() + "/" + vspNetwork.getVirtualRouterIp();
|
||||
NetworkVO updatedNetwork = _networkDao.createForUpdate(network.getId());
|
||||
updatedNetwork.setBroadcastUri(Networks.BroadcastDomainType.Vsp.toUri(broadcastUriStr));
|
||||
_networkDao.update(updatedNetwork.getId(), updatedNetwork);
|
||||
boolean vrAddedToNuage = vm.getType() == VirtualMachine.Type.DomainRouter && vspNetwork.getVirtualRouterIp()
|
||||
.equals("null");
|
||||
if (vrAddedToNuage) {
|
||||
//In case a VR is added due to upgrade network offering - recalculate the broadcast uri before using it.
|
||||
_nuageVspManager.updateBroadcastUri(network);
|
||||
network = _networkDao.findById(network.getId());
|
||||
vspNetwork = _nuageVspEntityBuilder.buildVspNetwork(vm.getVirtualMachine().getDomainId(), network, null);
|
||||
}
|
||||
|
||||
if (vspNetwork.isShared()) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package com.cloud.network.manager;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||
|
|
@ -35,6 +36,7 @@ import com.cloud.api.response.NuageVlanIpRangeResponse;
|
|||
import com.cloud.api.response.NuageVspDeviceResponse;
|
||||
import com.cloud.dc.Vlan;
|
||||
import com.cloud.api.response.NuageVspDomainTemplateResponse;
|
||||
import com.cloud.exception.InsufficientVirtualNetworkCapacityException;
|
||||
import com.cloud.host.HostVO;
|
||||
import com.cloud.network.Network;
|
||||
import com.cloud.network.NuageVspDeviceVO;
|
||||
|
|
@ -119,10 +121,9 @@ public interface NuageVspManager extends PluggableService {
|
|||
|
||||
/**
|
||||
* Associates a Nuage Vsp domain template with a
|
||||
* @param cmd
|
||||
* @return
|
||||
* @param cmd Associate cmd which contains all the data
|
||||
*/
|
||||
boolean associateNuageVspDomainTemplate(AssociateNuageVspDomainTemplateCmd cmd);
|
||||
void associateNuageVspDomainTemplate(AssociateNuageVspDomainTemplateCmd cmd);
|
||||
|
||||
/**
|
||||
* Queries the VSD to check if the entity provided in the entityCmd exists on the VSD
|
||||
|
|
@ -134,26 +135,41 @@ public interface NuageVspManager extends PluggableService {
|
|||
|
||||
/**
|
||||
* Sets the preconfigured domain template for a given network
|
||||
* @param network
|
||||
* @param domainTemplateName
|
||||
* @param network the network for which we want to set the domain template
|
||||
* @param domainTemplateName the domain template name we want to use
|
||||
*/
|
||||
void setPreConfiguredDomainTemplateName(Network network, String domainTemplateName);
|
||||
|
||||
/**
|
||||
* Returns the current pre configured domain template for a given network
|
||||
* @param network
|
||||
* @return
|
||||
* @param network the network for which we want the domain template name
|
||||
* @return the domain template name
|
||||
*/
|
||||
String getPreConfiguredDomainTemplateName(Network network);
|
||||
|
||||
/**
|
||||
* Checks if a given domain template exists or not on the VSD.
|
||||
* @param domainId
|
||||
* @param domainId Id of the domain to search in.
|
||||
* @param domainTemplate The name of the domain template for which we need to query the VSD.
|
||||
* @param zoneId zoneId OR PhysicalNetworkId needs to be provided.
|
||||
* @param physicalNetworkId zoneId OR PhysicalNetworkId needs to be provided.
|
||||
* @return true if the domain template exists on the VSD else false if it does not exist on the VSD
|
||||
*/
|
||||
public boolean checkIfDomainTemplateExist(Long domainId, String domainTemplate, Long zoneId, Long physicalNetworkId);
|
||||
boolean checkIfDomainTemplateExist(Long domainId, String domainTemplate, Long zoneId, Long physicalNetworkId);
|
||||
|
||||
/**
|
||||
* calculates the new broadcast uri of a network and persists it in the database
|
||||
* @param network the network for which you want to calculate the broadcast uri
|
||||
* @throws InsufficientVirtualNetworkCapacityException in case there is no free ip that can be used as the VR ip.
|
||||
*/
|
||||
void updateBroadcastUri(Network network) throws InsufficientVirtualNetworkCapacityException;
|
||||
|
||||
/**
|
||||
* Calculates the broadcast uri based on the network and the offering of the given network
|
||||
* @param network the network for which you want to calculate the broadcast uri
|
||||
* @return the calculated broadcast uri
|
||||
* @throws InsufficientVirtualNetworkCapacityException in case there is no free ip that can be used as the VR ip.
|
||||
*/
|
||||
URI calculateBroadcastUri(Network network) throws InsufficientVirtualNetworkCapacityException;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import net.nuage.vsp.acs.client.api.model.VspDomainTemplate;
|
|||
import net.nuage.vsp.acs.client.api.model.VspHost;
|
||||
import net.nuage.vsp.acs.client.common.NuageVspApiVersion;
|
||||
import net.nuage.vsp.acs.client.common.NuageVspConstants;
|
||||
import net.nuage.vsp.acs.client.common.model.Pair;
|
||||
import net.nuage.vsp.acs.client.exception.NuageVspException;
|
||||
import org.apache.cloudstack.api.ResponseGenerator;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
|
|
@ -53,15 +54,19 @@ import org.apache.log4j.Logger;
|
|||
import javax.annotation.Nonnull;
|
||||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
|
@ -105,6 +110,7 @@ import com.cloud.dc.dao.VlanDetailsDao;
|
|||
import com.cloud.domain.Domain;
|
||||
import com.cloud.domain.DomainVO;
|
||||
import com.cloud.domain.dao.DomainDao;
|
||||
import com.cloud.exception.InsufficientVirtualNetworkCapacityException;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.host.DetailVO;
|
||||
import com.cloud.host.Host;
|
||||
|
|
@ -113,6 +119,7 @@ import com.cloud.host.Status;
|
|||
import com.cloud.host.dao.HostDao;
|
||||
import com.cloud.host.dao.HostDetailsDao;
|
||||
import com.cloud.network.Network;
|
||||
import com.cloud.network.NetworkModel;
|
||||
import com.cloud.network.Networks;
|
||||
import com.cloud.network.NuageVspDeviceVO;
|
||||
import com.cloud.network.PhysicalNetwork;
|
||||
|
|
@ -154,6 +161,11 @@ import com.cloud.utils.db.TransactionStatus;
|
|||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.fsm.StateListener;
|
||||
import com.cloud.utils.fsm.StateMachine2;
|
||||
import com.cloud.utils.net.NetUtils;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.dao.NicDao;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
|
||||
import static com.cloud.agent.api.sync.SyncNuageVspCmsIdCommand.SyncType;
|
||||
|
||||
|
|
@ -213,6 +225,12 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager,
|
|||
ResponseGenerator _responseGenerator;
|
||||
@Inject
|
||||
MessageBus _messageBus;
|
||||
@Inject
|
||||
VMInstanceDao _vmInstanceDao;
|
||||
@Inject
|
||||
NicDao _nicDao;
|
||||
@Inject
|
||||
NetworkModel _networkModel;
|
||||
|
||||
static {
|
||||
Set<Network.Provider> nuageVspProviders = ImmutableSet.of(Network.Provider.NuageVsp);
|
||||
|
|
@ -902,7 +920,7 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager,
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean associateNuageVspDomainTemplate(AssociateNuageVspDomainTemplateCmd cmd){
|
||||
public void associateNuageVspDomainTemplate(AssociateNuageVspDomainTemplateCmd cmd){
|
||||
VpcVO vpc = _vpcDao.findById(cmd.getVpcId());
|
||||
Long physicalNetworkId;
|
||||
if (cmd.getPhysicalNetworkId() != null) {
|
||||
|
|
@ -923,7 +941,6 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager,
|
|||
throw new InvalidParameterValueException("Could not find a Domain Template with name: " + cmd.getDomainTemplate());
|
||||
}
|
||||
setPreConfiguredDomainTemplateName(cmd.getVpcId(), cmd.getDomainTemplate());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -939,6 +956,131 @@ public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager,
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBroadcastUri(Network network) throws InsufficientVirtualNetworkCapacityException {
|
||||
NetworkVO updatedNetwork = _networkDao.createForUpdate(network.getId());
|
||||
URI broadcastUri = calculateBroadcastUri(network);
|
||||
if (!broadcastUri.equals(network.getBroadcastUri())) {
|
||||
updatedNetwork.setBroadcastUri(broadcastUri);
|
||||
_networkDao.update(network.getId(), updatedNetwork);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI calculateBroadcastUri(Network network) throws InsufficientVirtualNetworkCapacityException {
|
||||
String vrIp = calculateVirtualRouterIp(network);
|
||||
return Networks.BroadcastDomainType.Vsp.toUri(network.getUuid() + "/" + vrIp);
|
||||
}
|
||||
|
||||
private boolean usesVirtualRouter(long networkOfferingId) {
|
||||
return _networkOfferingServiceMapDao.isProviderForNetworkOffering(networkOfferingId, Network.Provider.VirtualRouter) ||
|
||||
_networkOfferingServiceMapDao.isProviderForNetworkOffering(networkOfferingId, Network.Provider.VPCVirtualRouter);
|
||||
}
|
||||
|
||||
private String calculateVirtualRouterIp(Network network)
|
||||
throws InsufficientVirtualNetworkCapacityException {
|
||||
if (!usesVirtualRouter(network.getNetworkOfferingId())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Pair<String, String>> ipAddressRanges =
|
||||
network.getGuestType() == Network.GuestType.Shared ? getSharedIpAddressRanges(network.getId()) : getIpAddressRanges(network);
|
||||
|
||||
//check if a vr might be present already or not? CLOUD-1216 - before we always picked .2
|
||||
List<VMInstanceVO> vrs =_vmInstanceDao.listNonRemovedVmsByTypeAndNetwork(network.getId(), VirtualMachine.Type.DomainRouter);
|
||||
|
||||
for (VMInstanceVO vr : vrs) {
|
||||
return _nicDao.listByVmIdAndNicIdAndNtwkId(vr.getId(), null, network.getId()).get(0).getIPv4Address();
|
||||
}
|
||||
|
||||
ensureIpCapacity(network, ipAddressRanges);
|
||||
|
||||
if(network.getGuestType() == Network.GuestType.Shared) {
|
||||
return ipAddressRanges.stream()
|
||||
.sorted(Comparator.comparingLong(p -> NetUtils.ip2Long(p.getLeft())))
|
||||
.findFirst()
|
||||
.map(Pair::getLeft)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Shared network without ip ranges? How can this happen?"));
|
||||
}
|
||||
|
||||
Network networkToCheck;
|
||||
if (isMigratingNetwork(network)) {
|
||||
networkToCheck = _networkDao.findById(network.getRelated());
|
||||
} else {
|
||||
networkToCheck = network;
|
||||
}
|
||||
|
||||
Long freeIp = _networkModel.getAvailableIps(networkToCheck, null)
|
||||
.stream()
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new InsufficientVirtualNetworkCapacityException("There is no free ip available for the VirtualRouter.",
|
||||
Network.class,
|
||||
network.getId()));
|
||||
|
||||
return NetUtils.long2Ip(freeIp);
|
||||
}
|
||||
|
||||
private List<Pair<String, String>> getSharedIpAddressRanges(long networkId) {
|
||||
List<VlanVO> vlans = _vlanDao.listVlansByNetworkId(networkId);
|
||||
List<Pair<String, String>> ipAddressRanges = Lists.newArrayList();
|
||||
for (VlanVO vlan : vlans) {
|
||||
Pair<String, String> ipAddressRange = NuageVspUtil.getIpAddressRange(vlan);
|
||||
if (ipAddressRange != null) {
|
||||
ipAddressRanges.add(ipAddressRange);
|
||||
}
|
||||
}
|
||||
return ipAddressRanges;
|
||||
}
|
||||
|
||||
private List<Pair<String, String>> getIpAddressRanges(Network network) {
|
||||
List<Pair<String, String>> ipAddressRanges = Lists.newArrayList();
|
||||
String subnet = NetUtils.getCidrSubNet(network.getCidr());
|
||||
String netmask = NetUtils.getCidrNetmask(network.getCidr());
|
||||
long cidrSize = NetUtils.getCidrSize(netmask);
|
||||
Set<Long> allIPsInCidr = NetUtils.getAllIpsFromCidr(subnet, cidrSize, new HashSet<Long>());
|
||||
if (allIPsInCidr == null || !(allIPsInCidr instanceof TreeSet)) {
|
||||
throw new IllegalStateException("The IPs in CIDR for subnet " + subnet + " where null or returned in a non-ordered set.");
|
||||
}
|
||||
|
||||
Iterator<Long> ipIterator = allIPsInCidr.iterator();
|
||||
long ip = ipIterator.next();
|
||||
long gatewayIp = NetUtils.ip2Long(network.getGateway());
|
||||
String lastIp = NetUtils.getIpRangeEndIpFromCidr(subnet, cidrSize);
|
||||
if (gatewayIp == ip) {
|
||||
ip = ipIterator.next();
|
||||
ipAddressRanges.add(Pair.of(NetUtils.long2Ip(ip), lastIp));
|
||||
} else if (!network.getGateway().equals(lastIp)) {
|
||||
ipAddressRanges.add(Pair.of(NetUtils.long2Ip(ip), NetUtils.long2Ip(gatewayIp - 1)));
|
||||
ipAddressRanges.add(Pair.of(NetUtils.long2Ip(gatewayIp + 1), lastIp));
|
||||
} else {
|
||||
ipAddressRanges.add(Pair.of(NetUtils.long2Ip(ip), NetUtils.long2Ip(gatewayIp - 1)));
|
||||
}
|
||||
|
||||
return ipAddressRanges;
|
||||
}
|
||||
|
||||
private void ensureIpCapacity(Network network, List<Pair<String, String>> ipAddressRanges) throws InsufficientVirtualNetworkCapacityException {
|
||||
long ipCount = ipAddressRanges.stream()
|
||||
.mapToLong(this::getIpCount)
|
||||
.sum();
|
||||
|
||||
if (ipCount == 0) {
|
||||
throw new InsufficientVirtualNetworkCapacityException("VSP allocates an IP for VirtualRouter." + " But no ip address ranges are specified", Network.class,
|
||||
network.getId());
|
||||
} else if (ipCount < 3) {
|
||||
throw new InsufficientVirtualNetworkCapacityException("VSP allocates an IP for VirtualRouter." + " So, subnet should have atleast minimum 3 hosts", Network.class,
|
||||
network.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isMigratingNetwork(Network network) {
|
||||
return network.getRelated() != network.getId();
|
||||
}
|
||||
|
||||
private long getIpCount(Pair<String, String> ipAddressRange) {
|
||||
return NetUtils.ip2Long(ipAddressRange.getRight()) - NetUtils.ip2Long(ipAddressRange.getLeft()) + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean entityExist(EntityExistsCommand cmd, Long physicalNetworkId){
|
||||
Long hostId = getNuageVspHostId(physicalNetworkId);
|
||||
|
|
|
|||
|
|
@ -19,13 +19,8 @@
|
|||
|
||||
package com.cloud.util;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
|
@ -44,10 +39,8 @@ import net.nuage.vsp.acs.client.api.model.VspVm;
|
|||
import net.nuage.vsp.acs.client.common.model.Pair;
|
||||
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
|
|
@ -60,7 +53,6 @@ import com.cloud.dc.dao.VlanDetailsDao;
|
|||
import com.cloud.domain.Domain;
|
||||
import com.cloud.domain.DomainVO;
|
||||
import com.cloud.domain.dao.DomainDao;
|
||||
import com.cloud.exception.InsufficientVirtualNetworkCapacityException;
|
||||
import com.cloud.network.Network;
|
||||
import com.cloud.network.NetworkModel;
|
||||
import com.cloud.network.dao.IPAddressDao;
|
||||
|
|
@ -79,7 +71,6 @@ import com.cloud.offerings.dao.NetworkOfferingDao;
|
|||
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.net.NetUtils;
|
||||
import com.cloud.vm.NicProfile;
|
||||
import com.cloud.vm.NicVO;
|
||||
|
|
@ -157,30 +148,18 @@ public class NuageVspEntityBuilder {
|
|||
}
|
||||
|
||||
public VspNetwork buildVspNetwork(Network network) {
|
||||
return buildVspNetwork(network.getDomainId(), network, null, false);
|
||||
}
|
||||
|
||||
public VspNetwork buildVspNetwork(Network network, boolean recalculateBroadcastUri) {
|
||||
return buildVspNetwork(network.getDomainId(), network, null, recalculateBroadcastUri);
|
||||
return buildVspNetwork(network.getDomainId(), network, null);
|
||||
}
|
||||
|
||||
public VspNetwork buildVspNetwork(Network network, String vsdSubnetId) {
|
||||
return buildVspNetwork(network.getDomainId(), network, vsdSubnetId, false);
|
||||
return buildVspNetwork(network.getDomainId(), network, vsdSubnetId);
|
||||
}
|
||||
|
||||
public VspNetwork buildVspNetwork(long domainId, Network network) {
|
||||
return buildVspNetwork(domainId, network, null, false);
|
||||
}
|
||||
|
||||
public VspNetwork buildVspNetwork(long domainId, Network network, boolean recalculateBroadcastUri) {
|
||||
return buildVspNetwork(domainId, network, null, recalculateBroadcastUri);
|
||||
return buildVspNetwork(domainId, network, null);
|
||||
}
|
||||
|
||||
public VspNetwork buildVspNetwork(long domainId, Network network, String vsdSubnetId) {
|
||||
return buildVspNetwork(domainId, network, vsdSubnetId, false);
|
||||
}
|
||||
|
||||
public VspNetwork buildVspNetwork(long domainId, Network network, String vsdSubnetId, boolean recalculateBroadcastUri) {
|
||||
VspNetwork.Builder vspNetworkBuilder = new VspNetwork.Builder()
|
||||
.id(network.getId())
|
||||
.uuid(network.getUuid())
|
||||
|
|
@ -254,15 +233,8 @@ public class NuageVspEntityBuilder {
|
|||
vspNetworkBuilder.domainTemplateName(preConfiguredDomainTemplateName);
|
||||
|
||||
if (usesVirtualRouter(networkOffering.getId())) {
|
||||
try {
|
||||
List<Pair<String, String>> ipAddressRanges =
|
||||
networkOffering.getGuestType() == Network.GuestType.Shared ? getSharedIpAddressRanges(network.getId()) : getIpAddressRanges(network);
|
||||
String virtualRouterIp = getVirtualRouterIP(network, ipAddressRanges, recalculateBroadcastUri);
|
||||
String virtualRouterIp = getVirtualRouterIP(network);
|
||||
vspNetworkBuilder.virtualRouterIp(virtualRouterIp);
|
||||
} catch (InsufficientVirtualNetworkCapacityException ex) {
|
||||
s_logger.error("There is an insufficient network capacity in network " + network.getId(), ex);
|
||||
throw new CloudRuntimeException("There is an insufficient network capacity in network " + network.getId(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
return vspNetworkBuilder.build();
|
||||
|
|
@ -298,128 +270,16 @@ public class NuageVspEntityBuilder {
|
|||
}
|
||||
|
||||
private boolean isVlanContainingIp(Vlan vlan, long ip) {
|
||||
Pair<String, String> ipAddressRange = getIpAddressRange(vlan);
|
||||
Pair<String, String> ipAddressRange = NuageVspUtil.getIpAddressRange(vlan);
|
||||
long startIp = NetUtils.ip2Long(ipAddressRange.getLeft());
|
||||
long endIp = NetUtils.ip2Long(ipAddressRange.getRight());
|
||||
return startIp <= ip && ip <= endIp;
|
||||
}
|
||||
|
||||
private List<Pair<String, String>> getSharedIpAddressRanges(long networkId) {
|
||||
List<VlanVO> vlans = _vlanDao.listVlansByNetworkId(networkId);
|
||||
List<Pair<String, String>> ipAddressRanges = Lists.newArrayList();
|
||||
for (VlanVO vlan : vlans) {
|
||||
Pair<String, String> ipAddressRange = getIpAddressRange(vlan);
|
||||
if (ipAddressRange != null) {
|
||||
ipAddressRanges.add(ipAddressRange);
|
||||
}
|
||||
}
|
||||
return ipAddressRanges;
|
||||
private String getVirtualRouterIP(Network network) {
|
||||
return network.getBroadcastUri() != null ? network.getBroadcastUri().getPath().substring(1) : null;
|
||||
}
|
||||
|
||||
private List<Pair<String, String>> getIpAddressRanges(Network network) {
|
||||
List<Pair<String, String>> ipAddressRanges = Lists.newArrayList();
|
||||
String subnet = NetUtils.getCidrSubNet(network.getCidr());
|
||||
String netmask = NetUtils.getCidrNetmask(network.getCidr());
|
||||
long cidrSize = NetUtils.getCidrSize(netmask);
|
||||
Set<Long> allIPsInCidr = NetUtils.getAllIpsFromCidr(subnet, cidrSize, new HashSet<Long>());
|
||||
if (allIPsInCidr == null || !(allIPsInCidr instanceof TreeSet)) {
|
||||
throw new IllegalStateException("The IPs in CIDR for subnet " + subnet + " where null or returned in a non-ordered set.");
|
||||
}
|
||||
|
||||
Iterator<Long> ipIterator = allIPsInCidr.iterator();
|
||||
long ip = ipIterator.next();
|
||||
long gatewayIp = NetUtils.ip2Long(network.getGateway());
|
||||
String lastIp = NetUtils.getIpRangeEndIpFromCidr(subnet, cidrSize);
|
||||
if (gatewayIp == ip) {
|
||||
ip = ipIterator.next();
|
||||
ipAddressRanges.add(Pair.of(NetUtils.long2Ip(ip), lastIp));
|
||||
} else if (!network.getGateway().equals(lastIp)) {
|
||||
ipAddressRanges.add(Pair.of(NetUtils.long2Ip(ip), NetUtils.long2Ip(gatewayIp - 1)));
|
||||
ipAddressRanges.add(Pair.of(NetUtils.long2Ip(gatewayIp + 1), lastIp));
|
||||
} else {
|
||||
ipAddressRanges.add(Pair.of(NetUtils.long2Ip(ip), NetUtils.long2Ip(gatewayIp - 1)));
|
||||
}
|
||||
|
||||
return ipAddressRanges;
|
||||
}
|
||||
|
||||
public Pair<String, String> getIpAddressRange(Vlan vlan) {
|
||||
boolean isIpv4 = StringUtils.isNotBlank(vlan.getIpRange());
|
||||
String[] range = isIpv4 ? vlan.getIpRange().split("-") : vlan.getIp6Range().split("-");
|
||||
if (range.length == 2) {
|
||||
return Pair.of(range[0], range[1]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getVirtualRouterIP(Network network, List<Pair<String, String>> ipAddressRanges, boolean recalculateBroadcastUri) throws InsufficientVirtualNetworkCapacityException {
|
||||
//Add a check to see if a VR should be present in the offering or not?
|
||||
if (!recalculateBroadcastUri && network.getBroadcastUri() != null) {
|
||||
return network.getBroadcastUri().getPath().substring(1);
|
||||
}
|
||||
ensureIpCapacity(network, ipAddressRanges);
|
||||
|
||||
if(network.getGuestType() == Network.GuestType.Shared) {
|
||||
return ipAddressRanges.stream()
|
||||
.sorted(Comparator.comparingLong(p -> NetUtils.ip2Long(p.getLeft())))
|
||||
.findFirst()
|
||||
.map(Pair::getLeft)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Shared network without ip ranges? How can this happen?"));
|
||||
}
|
||||
|
||||
Pair<String, String> lowestIpAddressRange = null;
|
||||
long ipCount = 0;
|
||||
if (ipAddressRanges.size() == 1) {
|
||||
lowestIpAddressRange = Iterables.getOnlyElement(ipAddressRanges);
|
||||
ipCount = NetUtils.ip2Long(lowestIpAddressRange.getRight()) - NetUtils.ip2Long(lowestIpAddressRange.getLeft()) + 1;
|
||||
} else {
|
||||
for (Pair<String, String> ipAddressRange : ipAddressRanges) {
|
||||
if (lowestIpAddressRange == null || NetUtils.ip2Long(ipAddressRange.getLeft()) < NetUtils.ip2Long(lowestIpAddressRange.getLeft())) {
|
||||
lowestIpAddressRange = ipAddressRange;
|
||||
}
|
||||
ipCount += NetUtils.ip2Long(ipAddressRange.getRight()) - NetUtils.ip2Long(ipAddressRange.getLeft()) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Network networkToCheck;
|
||||
if (isMigratingNetwork(network)) {
|
||||
networkToCheck = _networkDao.findById(network.getRelated());
|
||||
} else {
|
||||
networkToCheck = network;
|
||||
}
|
||||
|
||||
Long freeIp = _networkModel.getAvailableIps(networkToCheck, null)
|
||||
.stream()
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new InsufficientVirtualNetworkCapacityException("There is no free ip available for the VirtualRouter.",
|
||||
Network.class,
|
||||
network.getId()));
|
||||
|
||||
return NetUtils.long2Ip(freeIp);
|
||||
}
|
||||
|
||||
private boolean isMigratingNetwork(Network network) {
|
||||
return network.getRelated() != network.getId();
|
||||
}
|
||||
|
||||
private void ensureIpCapacity(Network network, List<Pair<String, String>> ipAddressRanges) throws InsufficientVirtualNetworkCapacityException {
|
||||
long ipCount = ipAddressRanges.stream()
|
||||
.mapToLong(this::getIpCount)
|
||||
.sum();
|
||||
|
||||
if (ipCount == 0) {
|
||||
throw new InsufficientVirtualNetworkCapacityException("VSP allocates an IP for VirtualRouter." + " But no ip address ranges are specified", Network.class,
|
||||
network.getId());
|
||||
} else if (ipCount < 3) {
|
||||
throw new InsufficientVirtualNetworkCapacityException("VSP allocates an IP for VirtualRouter." + " So, subnet should have atleast minimum 3 hosts", Network.class,
|
||||
network.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private long getIpCount(Pair<String, String> ipAddressRange) {
|
||||
return NetUtils.ip2Long(ipAddressRange.getRight()) - NetUtils.ip2Long(ipAddressRange.getLeft()) + 1;
|
||||
}
|
||||
|
||||
public VspVm buildVspVm(VirtualMachine vm, Network network) {
|
||||
VspVm.Builder vspVmBuilder = new VspVm.Builder()
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import com.cloud.dc.VlanDetailsVO;
|
|||
import com.cloud.dc.dao.VlanDetailsDao;
|
||||
import com.cloud.network.manager.NuageVspManager;
|
||||
import com.cloud.utils.StringUtils;
|
||||
|
||||
import net.nuage.vsp.acs.client.common.model.Pair;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
public class NuageVspUtil {
|
||||
|
|
@ -44,4 +46,13 @@ public class NuageVspUtil {
|
|||
VlanDetailsVO nuageUnderlayDetail = vlanDetailsDao.findDetail(vlan.getId(), NuageVspManager.nuageUnderlayVlanIpRangeDetailKey);
|
||||
return nuageUnderlayDetail != null && nuageUnderlayDetail.getValue().equalsIgnoreCase(String.valueOf(true));
|
||||
}
|
||||
|
||||
public static Pair<String, String> getIpAddressRange(Vlan vlan) {
|
||||
boolean isIpv4 = StringUtils.isNotBlank(vlan.getIpRange());
|
||||
String[] range = isIpv4 ? vlan.getIpRange().split("-") : vlan.getIp6Range().split("-");
|
||||
if (range.length == 2) {
|
||||
return Pair.of(range[0], range[1]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,9 +92,7 @@ public class NuageTest {
|
|||
|
||||
VspNetwork vspNetwork = buildVspNetwork();
|
||||
when(_nuageVspEntityBuilder.buildVspNetwork(any(Network.class))).thenReturn(vspNetwork);
|
||||
when(_nuageVspEntityBuilder.buildVspNetwork(any(Network.class), anyBoolean())).thenReturn(vspNetwork);
|
||||
when(_nuageVspEntityBuilder.buildVspNetwork(anyLong(), any(Network.class))).thenReturn(vspNetwork);
|
||||
when(_nuageVspEntityBuilder.buildVspNetwork(anyLong(), any(Network.class), anyBoolean())).thenReturn(vspNetwork);
|
||||
|
||||
when(_nuageVspEntityBuilder.buildVspVm(any(VirtualMachine.class), any(Network.class))).thenReturn(buildVspVm());
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.tags.dao.ResourceTagDao;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
@ -60,9 +62,7 @@ import com.cloud.network.NuageVspDeviceVO;
|
|||
import com.cloud.network.dao.FirewallRulesDao;
|
||||
import com.cloud.network.dao.IPAddressDao;
|
||||
import com.cloud.network.dao.IPAddressVO;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkServiceMapDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.network.dao.NuageVspDao;
|
||||
import com.cloud.network.dao.PhysicalNetworkDao;
|
||||
import com.cloud.network.dao.PhysicalNetworkVO;
|
||||
|
|
@ -89,6 +89,7 @@ import static org.mockito.Matchers.any;
|
|||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
public class NuageVspElementTest extends NuageTest {
|
||||
|
||||
|
|
@ -119,6 +120,7 @@ public class NuageVspElementTest extends NuageTest {
|
|||
_nuageVspElement._nuageVspEntityBuilder = _nuageVspEntityBuilder;
|
||||
_nuageVspElement._vpcDetailsDao = _vpcDetailsDao;
|
||||
_nuageVspElement._routerDao = _domainRouterDao;
|
||||
_nuageVspElement._networkDao = _networkDao;
|
||||
|
||||
when(_networkServiceMapDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.Connectivity, Provider.NuageVsp)).thenReturn(true);
|
||||
when(_networkServiceMapDao.canProviderSupportServiceInNetwork(NETWORK_ID, Service.SourceNat, Provider.NuageVsp)).thenReturn(true);
|
||||
|
|
@ -166,7 +168,7 @@ public class NuageVspElementTest extends NuageTest {
|
|||
|
||||
@Test
|
||||
public void testImplement() throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, URISyntaxException {
|
||||
final Network network = mock(Network.class);
|
||||
final Network network = mock(NetworkVO.class, withSettings().extraInterfaces(Network.class));
|
||||
when(network.getBroadcastDomainType()).thenReturn(BroadcastDomainType.Vsp);
|
||||
when(network.getId()).thenReturn(NETWORK_ID);
|
||||
when(network.getVpcId()).thenReturn(null);
|
||||
|
|
@ -209,6 +211,7 @@ public class NuageVspElementTest extends NuageTest {
|
|||
when(_firewallRulesDao.listByNetworkPurposeTrafficType(NETWORK_ID, FirewallRule.Purpose.Firewall, FirewallRule.TrafficType.Egress)).thenReturn(new ArrayList<FirewallRuleVO>());
|
||||
when(_ipAddressDao.listStaticNatPublicIps(NETWORK_ID)).thenReturn(new ArrayList<IPAddressVO>());
|
||||
when(_nuageVspManager.getDnsDetails(network.getDataCenterId())).thenReturn(new ArrayList<String>());
|
||||
when(_networkDao.findById(network.getId())).thenReturn((NetworkVO)network);
|
||||
|
||||
assertTrue(_nuageVspElement.implement(network, offering, deployDest, context));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -947,3 +947,63 @@ class TestNuageInternalDns(nuageTestCase):
|
|||
self.debug("excepted value found in vm: " + item)
|
||||
else:
|
||||
self.fail("excepted value not found in vm: " + item)
|
||||
|
||||
@attr(tags=["advanced", "nuagevsp"], required_hardware="true")
|
||||
def test_09_update_network_offering_isolated_network(self):
|
||||
"""Test Update network offering for isolated Networks
|
||||
with Nuage VSP SDN plugin
|
||||
"""
|
||||
# Create an Isolated Network with Nuage VSP Isolated Network
|
||||
# offering specifying Services which don't need a VR.
|
||||
# Update the network offering of this network to one that
|
||||
# needs a VR, check that a VR is spawn
|
||||
# After that update network to previous offering
|
||||
# Check that VR is destroyed and removed.
|
||||
|
||||
self.debug("+++Create an Isolated network with a network "
|
||||
"offering which has only services without VR")
|
||||
cmd = updateZone.updateZoneCmd()
|
||||
cmd.id = self.zone.id
|
||||
cmd.domain = "isolated.com"
|
||||
self.apiclient.updateZone(cmd)
|
||||
self.debug("Creating and enabling Nuage Vsp Isolated Network "
|
||||
"offering which has only service without VR...")
|
||||
network_offering = self.create_NetworkOffering(
|
||||
self.test_data["nuagevsp"]
|
||||
["isolated_network_offering_without_vr"])
|
||||
self.validate_NetworkOffering(network_offering, state="Enabled")
|
||||
|
||||
network_1 = self.create_Network(network_offering)
|
||||
self.validate_Network(network_1, state="Allocated")
|
||||
|
||||
self.debug("+++Deploy VM in the created Isolated network "
|
||||
"with only services without VR")
|
||||
vm_1 = self.create_VM(network_1)
|
||||
|
||||
# VSD verification
|
||||
self.verify_vsd_network(self.domain.id, network_1)
|
||||
self.verify_vsd_vm(vm_1)
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
self.get_Router(network_1)
|
||||
self.debug("+++Verified no VR is spawned for this network ")
|
||||
|
||||
self.debug("+++ Upgrade offering of created Isolated network with "
|
||||
"a dns offering which spins a VR")
|
||||
self.upgrade_Network(self.test_data["nuagevsp"][
|
||||
"isolated_network_offering"],
|
||||
network_1)
|
||||
vr = self.get_Router(network_1)
|
||||
self.check_Router_state(vr, state="Running")
|
||||
# VSD verification
|
||||
self.verify_vsd_network(self.domain.id, network_1)
|
||||
self.verify_vsd_router(vr)
|
||||
|
||||
self.debug("+++ Upgrade offering of created Isolated network with "
|
||||
"an offering which removes the VR...")
|
||||
self.upgrade_Network(self.test_data["nuagevsp"][
|
||||
"isolated_network_offering_without_vr"],
|
||||
network_1)
|
||||
with self.assertRaises(Exception):
|
||||
self.get_Router(network_1)
|
||||
self.debug("+++Verified no VR is spawned for this network ")
|
||||
|
|
|
|||
Loading…
Reference in New Issue