From 1abdb876c9260d2c04ebbad5fa2b7ba876650860 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Thu, 10 May 2012 12:55:57 -0700 Subject: [PATCH] 1) Allow having multiple shared networks with the same vlan 2) Added new parameter to listNetworks command - canUseForDeploy(boolean). When true, list only networks that can be used for vm deployment (networks have enough ip addresses to allocate from for the vm) Conflicts: api/src/com/cloud/api/ApiConstants.java api/src/com/cloud/api/commands/ListNetworksCmd.java api/src/com/cloud/api/response/NetworkResponse.java api/src/com/cloud/network/NetworkService.java server/src/com/cloud/api/ApiDBUtils.java server/src/com/cloud/api/ApiResponseHelper.java server/src/com/cloud/network/NetworkManagerImpl.java server/src/com/cloud/network/dao/IPAddressDao.java server/src/com/cloud/network/dao/IPAddressDaoImpl.java --- api/src/com/cloud/api/ApiConstants.java | 1 + .../cloud/api/commands/ListNetworksCmd.java | 9 +- .../cloud/api/response/NetworkResponse.java | 9 +- api/src/com/cloud/network/NetworkService.java | 5 + server/src/com/cloud/api/ApiDBUtils.java | 6 +- .../src/com/cloud/api/ApiResponseHelper.java | 17 ++-- .../com/cloud/network/NetworkManagerImpl.java | 91 +++++++++++++------ .../com/cloud/network/dao/IPAddressDao.java | 7 +- .../cloud/network/dao/IPAddressDaoImpl.java | 11 ++- .../src/com/cloud/network/dao/NetworkDao.java | 4 +- .../com/cloud/network/dao/NetworkDaoImpl.java | 29 +++++- 11 files changed, 144 insertions(+), 45 deletions(-) diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index 94e8bbc71b1..8b646c34116 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -359,6 +359,7 @@ public class ApiConstants { public static final String VPC_OFF_ID = "vpcofferingid"; public static final String NETWORK = "network"; public static final String VPC_ID = "vpcid"; + public static final String CAN_USE_FOR_DEPLOY = "canusefordeploy"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/com/cloud/api/commands/ListNetworksCmd.java b/api/src/com/cloud/api/commands/ListNetworksCmd.java index 182bf815a02..676c453d72c 100644 --- a/api/src/com/cloud/api/commands/ListNetworksCmd.java +++ b/api/src/com/cloud/api/commands/ListNetworksCmd.java @@ -59,7 +59,7 @@ public class ListNetworksCmd extends BaseListProjectAndAccountResourcesCmd { @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.LONG, description="list networks by physical network id") private Long physicalNetworkId; - @Parameter(name=ApiConstants.SUPPORTED_SERVICES, type=CommandType.LIST, collectionType=CommandType.STRING, description="list network offerings supporting certain services") + @Parameter(name=ApiConstants.SUPPORTED_SERVICES, type=CommandType.LIST, collectionType=CommandType.STRING, description="list networks supporting certain services") private List supportedServices; @Parameter(name=ApiConstants.RESTART_REQUIRED, type=CommandType.BOOLEAN, description="list networks by restartRequired") @@ -71,6 +71,9 @@ public class ListNetworksCmd extends BaseListProjectAndAccountResourcesCmd { @IdentityMapper(entityTableName="vpc") @Parameter(name=ApiConstants.VPC_ID, type=CommandType.LONG, description="List networks by VPC") private Long vpcId; + + @Parameter(name=ApiConstants.CAN_USE_FOR_DEPLOY, type=CommandType.BOOLEAN, description="list networks available for vm deployment") + private Boolean canUseForDeploy; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -115,6 +118,10 @@ public class ListNetworksCmd extends BaseListProjectAndAccountResourcesCmd { public Boolean getSpecifyIpRanges() { return specifyIpRanges; } + + public Boolean canUseForDeploy() { + return canUseForDeploy; + } public Long getVpcId() { return vpcId; diff --git a/api/src/com/cloud/api/response/NetworkResponse.java b/api/src/com/cloud/api/response/NetworkResponse.java index 5cb2cb47a86..87eab0ce8fc 100644 --- a/api/src/com/cloud/api/response/NetworkResponse.java +++ b/api/src/com/cloud/api/response/NetworkResponse.java @@ -15,8 +15,8 @@ package com.cloud.api.response; import java.util.List; import com.cloud.api.ApiConstants; -import com.cloud.utils.IdentityProxy; import com.cloud.serializer.Param; +import com.cloud.utils.IdentityProxy; import com.google.gson.annotations.SerializedName; @SuppressWarnings("unused") @@ -129,6 +129,9 @@ public class NetworkResponse extends BaseResponse implements ControlledEntityRes @SerializedName(ApiConstants.VPC_ID) @Param(description="VPC the network belongs to") private IdentityProxy vpcId = new IdentityProxy("vpc"); + + @SerializedName(ApiConstants.CAN_USE_FOR_DEPLOY) @Param(description="list networks available for vm deployment") + private Boolean canUseForDeploy; public void setId(Long id) { this.id.setValue(id); @@ -275,4 +278,8 @@ public class NetworkResponse extends BaseResponse implements ControlledEntityRes public void setVpcId(Long vpcId) { this.vpcId.setValue(vpcId); } + + public void setCanUseForDeploy(Boolean canUseForDeploy) { + this.canUseForDeploy = canUseForDeploy; + } } diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index 129b6c38b3a..d0754f171cb 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -165,5 +165,10 @@ public interface NetworkService { Network createPrivateNetwork(String networkName, String displayText, long physicalNetworkId, String vlan, String startIp, String endIP, String gateway, String netmask, long networkOwnerId) throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException; + /** + * @param network + * @return + */ + boolean canUseForDeploy(Network network); } diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index d77fbe69fd8..64c7fef6792 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -741,7 +741,7 @@ public class ApiDBUtils { } public static long countFreePublicIps() { - return _ipAddressDao.countFreeIPs(); + return _ipAddressDao.countFreePublicIPs(); } public static long findDefaultRouterServiceOffering() { @@ -768,4 +768,8 @@ public class ApiDBUtils { public static List listVpcNetworks(long vpcId) { return _networkMgr.listNetworksByVpc(vpcId); } + + public static boolean canUseForDeploy(Network network) { + return _networkMgr.canUseForDeploy(network); + } } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index bfedb2db7f8..6a1d1231247 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -1029,7 +1029,7 @@ public class ApiResponseHelper implements ResponseGenerator { volResponse.setCreated(volume.getCreated()); volResponse.setState(volume.getState().toString()); if(volume.getState() == Volume.State.UploadOp){ - com.cloud.storage.VolumeHostVO volumeHostRef = ApiDBUtils.findVolumeHostRef(volume.getId(), volume.getDataCenterId()); + com.cloud.storage.VolumeHostVO volumeHostRef = ApiDBUtils.findVolumeHostRef(volume.getId(), volume.getDataCenterId()); volResponse.setSize(volumeHostRef.getSize()); volResponse.setCreated(volumeHostRef.getCreated()); Account caller = UserContext.current().getCaller(); @@ -1047,17 +1047,17 @@ public class ApiResponseHelper implements ResponseGenerator { } else { volumeStatus = volumeHostRef.getErrorString(); if(volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.NOT_DOWNLOADED){ - volResponse.setState("UploadNotStarted"); + volResponse.setState("UploadNotStarted"); }else { - volResponse.setState("UploadError"); + volResponse.setState("UploadError"); } } volResponse.setStatus(volumeStatus); } else if (volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) { - volResponse.setStatus("Upload Complete"); - volResponse.setState("Uploaded"); + volResponse.setStatus("Upload Complete"); + volResponse.setState("Uploaded"); } else { - volResponse.setStatus("Successfully Installed"); + volResponse.setStatus("Successfully Installed"); } } @@ -1107,7 +1107,7 @@ public class ApiResponseHelper implements ResponseGenerator { // return hypervisor for ROOT and Resource domain only Account caller = UserContext.current().getCaller(); if ((caller.getType() == Account.ACCOUNT_TYPE_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) && volume.getState() != Volume.State.UploadOp) { - volResponse.setHypervisor(ApiDBUtils.getVolumeHyperType(volume.getId()).toString()); + volResponse.setHypervisor(ApiDBUtils.getVolumeHyperType(volume.getId()).toString()); } volResponse.setAttached(volume.getAttached()); @@ -2815,7 +2815,7 @@ public class ApiResponseHelper implements ResponseGenerator { response.setBroadcastUri(broadcastUri); String vlan="N/A"; if (broadcastUri.startsWith("vlan")) { - vlan = broadcastUri.substring("vlan://".length(), broadcastUri.length()); + vlan = broadcastUri.substring("vlan://".length(), broadcastUri.length()); } response.setVlan(vlan); } @@ -2895,6 +2895,7 @@ public class ApiResponseHelper implements ResponseGenerator { } response.setSpecifyIpRanges(network.getSpecifyIpRanges()); + response.setCanUseForDeploy(ApiDBUtils.canUseForDeploy(network)); response.setVpcId(network.getVpcId()); response.setObjectName("network"); diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 86239611cd6..f2f870c054a 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -2901,14 +2901,22 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } } - // Don't allow to create network with vlan that already exists in the system if (vlanId != null) { String uri = "vlan://" + vlanId; - List networks = _networksDao.listBy(zoneId, uri); - if ((networks != null && !networks.isEmpty())) { - throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists in zone " + zoneId); + // For Isolated networks, don't allow to create network with vlan that already exists in the zone + if (ntwkOff.getGuestType() == GuestType.Isolated) { + if (_networksDao.countByZoneAndUri(zoneId, uri) > 0) { + throw new InvalidParameterValueException("Network with vlan " + vlanId + " already exists in zone " + zoneId); + } + } else { + //don't allow to create Shared network with Vlan that already exists in the zone for Isolated networks + if (_networksDao.countByZoneUriAndGuestType(zoneId, uri, GuestType.Isolated) > 0) { + throw new InvalidParameterValueException("Isolated network with vlan " + vlanId + " already exists " + + "in zone " + zoneId); + } } } + // If networkDomain is not specified, take it from the global configuration if (areServicesSupportedByNetworkOffering(networkOfferingId, Service.Dns)) { Map dnsCapabilities = getNetworkOfferingServiceCapabilities @@ -3047,6 +3055,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag boolean isRecursive = cmd.isRecursive(); Boolean specifyIpRanges = cmd.getSpecifyIpRanges(); Long vpcId = cmd.getVpcId(); + Boolean canUseForDeploy = cmd.canUseForDeploy(); // 1) default is system to false if not specified // 2) reset parameter to false if it's specified by the regular user @@ -3199,10 +3208,32 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } } - return supportedNetworks; - } else { - return networksToReturn; + networksToReturn=supportedNetworks; } + + if (canUseForDeploy != null) { + List networksForDeploy = new ArrayList(); + for (NetworkVO network : networksToReturn) { + if (canUseForDeploy(network) == canUseForDeploy) { + networksForDeploy.add(network); + } + } + + networksToReturn=networksForDeploy; + } + + return networksToReturn; + } + + @Override + public boolean canUseForDeploy(Network network) { + boolean hasFreeIps = true; + if (network.getGuestType() == GuestType.Shared) { + hasFreeIps = _ipAddressDao.countFreeIPsInNetwork(network.getId()) > 0; + } else { + hasFreeIps = (getAvailableIps(network, null)).size() > 0; + } + return hasFreeIps; } private SearchCriteria buildNetworkSearchCriteria(SearchBuilder sb, String keyword, Long id, @@ -4691,36 +4722,23 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag @Override @DB - public String acquireGuestIpAddress(Network network, String requestedIp) { - List ips = _nicDao.listIpAddressInNetwork(network.getId()); - String[] cidr = network.getCidr().split("/"); - Set allPossibleIps = NetUtils.getAllIpsFromCidr(cidr[0], Integer.parseInt(cidr[1])); - Set usedIps = new TreeSet(); - + public String acquireGuestIpAddress(Network network, String requestedIp) { if (requestedIp != null && requestedIp.equals(network.getGateway())) { s_logger.warn("Requested ip address " + requestedIp + " is used as a gateway address in network " + network); return null; } - for (String ip : ips) { - if (requestedIp != null && requestedIp.equals(ip)) { - s_logger.warn("Requested ip address " + requestedIp + " is already in use in network " + network); - return null; - } - - usedIps.add(NetUtils.ip2Long(ip)); - } - if (usedIps.size() != 0) { - allPossibleIps.removeAll(usedIps); - } - if (allPossibleIps.isEmpty()) { + Set availableIps = getAvailableIps(network, requestedIp); + + if (availableIps.isEmpty()) { return null; } - Long[] array = allPossibleIps.toArray(new Long[allPossibleIps.size()]); + Long[] array = availableIps.toArray(new Long[availableIps.size()]); if (requestedIp != null) { // check that requested ip has the same cidr + String[] cidr = network.getCidr().split("/"); boolean isSameCidr = NetUtils.sameSubnetCIDR(requestedIp, NetUtils.long2Ip(array[0]), Integer.parseInt(cidr[1])); if (!isSameCidr) { s_logger.warn("Requested ip address " + requestedIp + " doesn't belong to the network " + network + " cidr"); @@ -4737,6 +4755,27 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag return result; } + protected Set getAvailableIps(Network network, String requestedIp) { + String[] cidr = network.getCidr().split("/"); + List ips = _nicDao.listIpAddressInNetwork(network.getId()); + Set allPossibleIps = NetUtils.getAllIpsFromCidr(cidr[0], Integer.parseInt(cidr[1])); + Set usedIps = new TreeSet(); + + for (String ip : ips) { + if (requestedIp != null && requestedIp.equals(ip)) { + s_logger.warn("Requested ip address " + requestedIp + " is already in use in network" + network); + return null; + } + + usedIps.add(NetUtils.ip2Long(ip)); + } + if (usedIps.size() != 0) { + allPossibleIps.removeAll(usedIps); + } + return allPossibleIps; + } + + private String getZoneNetworkDomain(long zoneId) { return _dcDao.findById(zoneId).getDomain(); } diff --git a/server/src/com/cloud/network/dao/IPAddressDao.java b/server/src/com/cloud/network/dao/IPAddressDao.java index 54867703f36..0624bf86c33 100755 --- a/server/src/com/cloud/network/dao/IPAddressDao.java +++ b/server/src/com/cloud/network/dao/IPAddressDao.java @@ -54,9 +54,10 @@ public interface IPAddressDao extends GenericDao { public IPAddressVO findByIpAndDcId(long dcId, String ipAddress); List listByPhysicalNetworkId(long physicalNetworkId); - - long countFreeIPs(); - List listByAssociatedVpc(long vpcId, Boolean isSourceNat); + List listByAssociatedVpc(long vpcId, Boolean isSourceNat); + long countFreePublicIPs(); + + long countFreeIPsInNetwork(long networkId); } diff --git a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java index b2979b05684..8e8229ea2e6 100755 --- a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java +++ b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java @@ -111,6 +111,7 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen CountFreePublicIps = createSearchBuilder(Long.class); CountFreePublicIps.select(null, Func.COUNT, null); CountFreePublicIps.and("state", CountFreePublicIps.entity().getState(), SearchCriteria.Op.EQ); + CountFreePublicIps.and("networkId", CountFreePublicIps.entity().getSourceNetworkId(), SearchCriteria.Op.EQ); SearchBuilder join = _vlanDao.createSearchBuilder(); join.and("vlanType", join.entity().getVlanType(), Op.EQ); CountFreePublicIps.join("vlans", join, CountFreePublicIps.entity().getVlanId(), join.entity().getId(), JoinBuilder.JoinType.INNER); @@ -295,7 +296,7 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen } @Override - public long countFreeIPs() { + public long countFreePublicIPs() { SearchCriteria sc = CountFreePublicIps.create(); sc.setParameters("state", State.Free); sc.setJoinParameters("vlans", "vlanType", VlanType.VirtualNetwork); @@ -313,4 +314,12 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen return listBy(sc); } + + @Override + public long countFreeIPsInNetwork(long networkId) { + SearchCriteria sc = CountFreePublicIps.create(); + sc.setParameters("state", State.Free); + sc.setParameters("networkId", networkId); + return customSearch(sc, null).get(0); + } } diff --git a/server/src/com/cloud/network/dao/NetworkDao.java b/server/src/com/cloud/network/dao/NetworkDao.java index 299f5ee8a26..f73591f4070 100644 --- a/server/src/com/cloud/network/dao/NetworkDao.java +++ b/server/src/com/cloud/network/dao/NetworkDao.java @@ -54,7 +54,9 @@ public interface NetworkDao extends GenericDao { List listBy(long accountId, long networkId); - List listBy(long zoneId, String broadcastUri); + long countByZoneAndUri(long zoneId, String broadcastUri); + + long countByZoneUriAndGuestType(long zoneId, String broadcastUri, GuestType guestType); List listByZone(long zoneId); diff --git a/server/src/com/cloud/network/dao/NetworkDaoImpl.java b/server/src/com/cloud/network/dao/NetworkDaoImpl.java index 8fa107c8710..9c4a5f87263 100644 --- a/server/src/com/cloud/network/dao/NetworkDaoImpl.java +++ b/server/src/com/cloud/network/dao/NetworkDaoImpl.java @@ -21,6 +21,7 @@ import javax.persistence.TableGenerator; import com.cloud.acl.ControlledEntity.ACLType; import com.cloud.network.Network; +import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.NetworkAccountDaoImpl; @@ -62,6 +63,7 @@ public class NetworkDaoImpl extends GenericDaoBase implements N final GenericSearchBuilder NetworksRegularUserCanCreateSearch; private final GenericSearchBuilder NetworksCount; final SearchBuilder SourceNATSearch; + final GenericSearchBuilder CountByZoneAndURI; NetworkAccountDaoImpl _accountsDao = ComponentLocator.inject(NetworkAccountDaoImpl.class); @@ -118,7 +120,17 @@ public class NetworkDaoImpl extends GenericDaoBase implements N ZoneBroadcastUriSearch = createSearchBuilder(); ZoneBroadcastUriSearch.and("dataCenterId", ZoneBroadcastUriSearch.entity().getDataCenterId(), Op.EQ); ZoneBroadcastUriSearch.and("broadcastUri", ZoneBroadcastUriSearch.entity().getBroadcastUri(), Op.EQ); + ZoneBroadcastUriSearch.and("guestType", ZoneBroadcastUriSearch.entity().getGuestType(), Op.EQ); ZoneBroadcastUriSearch.done(); + + CountByZoneAndURI = createSearchBuilder(Long.class); + CountByZoneAndURI.select(null, Func.COUNT, null); + CountByZoneAndURI.and("dataCenterId", CountByZoneAndURI.entity().getDataCenterId(), Op.EQ); + CountByZoneAndURI.and("broadcastUri", CountByZoneAndURI.entity().getBroadcastUri(), Op.EQ); + CountByZoneAndURI.and("guestType", CountByZoneAndURI.entity().getGuestType(), Op.EQ); + + CountByZoneAndURI.done(); + ZoneSecurityGroupSearch = createSearchBuilder(); ZoneSecurityGroupSearch.and("dataCenterId", ZoneSecurityGroupSearch.entity().getDataCenterId(), Op.EQ); @@ -300,11 +312,13 @@ public class NetworkDaoImpl extends GenericDaoBase implements N } @Override - public List listBy(long zoneId, String broadcastUri) { - SearchCriteria sc = ZoneBroadcastUriSearch.create(); + public long countByZoneAndUri(long zoneId, String broadcastUri) { + + SearchCriteria sc = CountByZoneAndURI.create(); sc.setParameters("dataCenterId", zoneId); sc.setParameters("broadcastUri", broadcastUri); - return search(sc, null); + + return customSearch(sc, null).get(0); } @Override @@ -313,6 +327,15 @@ public class NetworkDaoImpl extends GenericDaoBase implements N sc.setParameters("dataCenterId", zoneId); return search(sc, null); } + + @Override + public long countByZoneUriAndGuestType(long zoneId, String broadcastUri, GuestType guestType) { + SearchCriteria sc = CountByZoneAndURI.create(); + sc.setParameters("dataCenterId", zoneId); + sc.setParameters("broadcastUri", broadcastUri); + sc.setParameters("guestType", guestType); + return customSearch(sc, null).get(0); + } @Override public List listByZoneSecurityGroup(Long zoneId) {