diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index f7acd5168be..7872cba309d 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -357,6 +357,7 @@ public class ApiConstants { public static final String VSM_CONFIG_STATE = "vsmconfigstate"; public static final String VSM_DEVICE_STATE = "vsmdevicestate"; public static final String ADD_VSM_FLAG = "addvsmflag"; + 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 a92feaa2067..8f665b90776 100644 --- a/api/src/com/cloud/api/commands/ListNetworksCmd.java +++ b/api/src/com/cloud/api/commands/ListNetworksCmd.java @@ -63,14 +63,17 @@ 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 network offerings by restartRequired option") + @Parameter(name=ApiConstants.RESTART_REQUIRED, type=CommandType.BOOLEAN, description="list networks by restartRequired option") private Boolean restartRequired; @Parameter(name=ApiConstants.SPECIFY_IP_RANGES, type=CommandType.BOOLEAN, description="true if need to list only networks which support specifying ip ranges") private Boolean specifyIpRanges; + + @Parameter(name=ApiConstants.CAN_USE_FOR_DEPLOY, type=CommandType.BOOLEAN, description="list networks available for vm deployment") + private Boolean canUseForDeploy; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -115,8 +118,12 @@ public class ListNetworksCmd extends BaseListProjectAndAccountResourcesCmd { public Boolean getSpecifyIpRanges() { return specifyIpRanges; } + + public Boolean canUseForDeploy() { + return canUseForDeploy; + } - ///////////////////////////////////////////////////// + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @Override diff --git a/api/src/com/cloud/api/response/NetworkResponse.java b/api/src/com/cloud/api/response/NetworkResponse.java index a8b2e5f5099..4c16240ff8d 100644 --- a/api/src/com/cloud/api/response/NetworkResponse.java +++ b/api/src/com/cloud/api/response/NetworkResponse.java @@ -131,6 +131,9 @@ public class NetworkResponse extends BaseResponse implements ControlledEntityRes @SerializedName(ApiConstants.SPECIFY_IP_RANGES) @Param(description="true if network supports specifying ip ranges, false otherwise") private Boolean specifyIpRanges; + @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); } @@ -272,4 +275,8 @@ public class NetworkResponse extends BaseResponse implements ControlledEntityRes public void setSpecifyIpRanges(Boolean specifyIpRanges) { this.specifyIpRanges = specifyIpRanges; } + + 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 99f8014e6a6..d7e40a977c6 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -134,4 +134,10 @@ public interface NetworkService { List getIsolatedNetworksWithSourceNATOwnedByAccountInZone(long zoneId, Account owner); + /** + * @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 f4948860183..4d2eea42f77 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -49,6 +49,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.IPAddressVO; import com.cloud.network.IpAddress; import com.cloud.network.LoadBalancerVO; +import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; @@ -84,6 +85,7 @@ import com.cloud.storage.GuestOS; import com.cloud.storage.GuestOSCategoryVO; import com.cloud.storage.Snapshot; import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolVO; import com.cloud.storage.StorageStats; @@ -91,9 +93,8 @@ import com.cloud.storage.UploadVO; import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateSwiftVO; import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.VolumeHostVO; -import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Volume.Type; +import com.cloud.storage.VolumeHostVO; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.GuestOSCategoryDao; @@ -733,7 +734,7 @@ public class ApiDBUtils { } public static long countFreePublicIps() { - return _ipAddressDao.countFreeIPs(); + return _ipAddressDao.countFreePublicIPs(); } public static long findDefaultRouterServiceOffering() { @@ -748,4 +749,7 @@ public class ApiDBUtils { public static String getHaTag() { return _haMgr.getHaTag(); } + 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 eb64d98512c..1112dba0e1f 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -1021,7 +1021,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(); @@ -1039,17 +1039,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"); } } @@ -1099,7 +1099,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()); @@ -2804,7 +2804,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); } @@ -2884,6 +2884,7 @@ public class ApiResponseHelper implements ResponseGenerator { } response.setSpecifyIpRanges(network.getSpecifyIpRanges()); + response.setCanUseForDeploy(ApiDBUtils.canUseForDeploy(network)); response.setObjectName("network"); return response; diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 60c98b86d96..783f9e6f089 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -2458,8 +2458,10 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag @Override @DB - public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, boolean isSecurityGroupEnabled, - Long domainId, PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { + public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, + String cidr, String vlanId, String networkDomain, Account owner, boolean isSecurityGroupEnabled, + Long domainId, PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess) + throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); // this method supports only guest network creation @@ -2549,16 +2551,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())) { - // TBD: If zoneId and vlanId are being passed in as params, how to get the VO object or class? Hard code - // the tablename in a call to addProxyObject(). - 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(_configMgr.getNetworkOffering(networkOfferingId), Service.Dns); @@ -2690,6 +2698,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag boolean listAll = cmd.listAll(); boolean isRecursive = cmd.isRecursive(); Boolean specifyIpRanges = cmd.getSpecifyIpRanges(); + 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 @@ -2831,10 +2840,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, Boolean isSystem, Long zoneId, String guestIpType, String trafficType, Long physicalNetworkId, @@ -4322,36 +4353,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"); @@ -4368,6 +4386,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 711a7fe8e1c..4e086435c38 100755 --- a/server/src/com/cloud/network/dao/IPAddressDao.java +++ b/server/src/com/cloud/network/dao/IPAddressDao.java @@ -55,5 +55,7 @@ public interface IPAddressDao extends GenericDao { List listByPhysicalNetworkId(long physicalNetworkId); - long countFreeIPs(); -} + 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 425c215c430..02615e3fcc9 100755 --- a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java +++ b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java @@ -110,6 +110,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); @@ -293,10 +294,18 @@ 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); return customSearch(sc, null).get(0); } + + @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 df74f238409..801c721f958 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 f907ce8116b..acaece4b7d1 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); @@ -117,7 +119,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); @@ -298,11 +310,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 @@ -311,6 +325,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) {