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
This commit is contained in:
Alena Prokharchyk 2012-05-10 12:55:57 -07:00
parent 5235894b20
commit 1abdb876c9
11 changed files with 144 additions and 45 deletions

View File

@ -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;

View File

@ -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<String> 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;

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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<? extends Network> listVpcNetworks(long vpcId) {
return _networkMgr.listNetworksByVpc(vpcId);
}
public static boolean canUseForDeploy(Network network) {
return _networkMgr.canUseForDeploy(network);
}
}

View File

@ -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");

View File

@ -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<NetworkVO> 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<Network.Capability, String> 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<NetworkVO> networksForDeploy = new ArrayList<NetworkVO>();
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<NetworkVO> buildNetworkSearchCriteria(SearchBuilder<NetworkVO> 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<String> ips = _nicDao.listIpAddressInNetwork(network.getId());
String[] cidr = network.getCidr().split("/");
Set<Long> allPossibleIps = NetUtils.getAllIpsFromCidr(cidr[0], Integer.parseInt(cidr[1]));
Set<Long> usedIps = new TreeSet<Long>();
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<Long> 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<Long> getAvailableIps(Network network, String requestedIp) {
String[] cidr = network.getCidr().split("/");
List<String> ips = _nicDao.listIpAddressInNetwork(network.getId());
Set<Long> allPossibleIps = NetUtils.getAllIpsFromCidr(cidr[0], Integer.parseInt(cidr[1]));
Set<Long> usedIps = new TreeSet<Long>();
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();
}

View File

@ -54,9 +54,10 @@ public interface IPAddressDao extends GenericDao<IPAddressVO, Long> {
public IPAddressVO findByIpAndDcId(long dcId, String ipAddress);
List<IPAddressVO> listByPhysicalNetworkId(long physicalNetworkId);
long countFreeIPs();
List<IPAddressVO> listByAssociatedVpc(long vpcId, Boolean isSourceNat);
List<IPAddressVO> listByAssociatedVpc(long vpcId, Boolean isSourceNat);
long countFreePublicIPs();
long countFreeIPsInNetwork(long networkId);
}

View File

@ -111,6 +111,7 @@ public class IPAddressDaoImpl extends GenericDaoBase<IPAddressVO, Long> 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<VlanVO> 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<IPAddressVO, Long> implemen
}
@Override
public long countFreeIPs() {
public long countFreePublicIPs() {
SearchCriteria<Long> sc = CountFreePublicIps.create();
sc.setParameters("state", State.Free);
sc.setJoinParameters("vlans", "vlanType", VlanType.VirtualNetwork);
@ -313,4 +314,12 @@ public class IPAddressDaoImpl extends GenericDaoBase<IPAddressVO, Long> implemen
return listBy(sc);
}
@Override
public long countFreeIPsInNetwork(long networkId) {
SearchCriteria<Long> sc = CountFreePublicIps.create();
sc.setParameters("state", State.Free);
sc.setParameters("networkId", networkId);
return customSearch(sc, null).get(0);
}
}

View File

@ -54,7 +54,9 @@ public interface NetworkDao extends GenericDao<NetworkVO, Long> {
List<NetworkVO> listBy(long accountId, long networkId);
List<NetworkVO> listBy(long zoneId, String broadcastUri);
long countByZoneAndUri(long zoneId, String broadcastUri);
long countByZoneUriAndGuestType(long zoneId, String broadcastUri, GuestType guestType);
List<NetworkVO> listByZone(long zoneId);

View File

@ -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<NetworkVO, Long> implements N
final GenericSearchBuilder<NetworkVO, Long> NetworksRegularUserCanCreateSearch;
private final GenericSearchBuilder<NetworkVO, Integer> NetworksCount;
final SearchBuilder<NetworkVO> SourceNATSearch;
final GenericSearchBuilder<NetworkVO, Long> CountByZoneAndURI;
NetworkAccountDaoImpl _accountsDao = ComponentLocator.inject(NetworkAccountDaoImpl.class);
@ -118,7 +120,17 @@ public class NetworkDaoImpl extends GenericDaoBase<NetworkVO, Long> 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<NetworkVO, Long> implements N
}
@Override
public List<NetworkVO> listBy(long zoneId, String broadcastUri) {
SearchCriteria<NetworkVO> sc = ZoneBroadcastUriSearch.create();
public long countByZoneAndUri(long zoneId, String broadcastUri) {
SearchCriteria<Long> 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<NetworkVO, Long> implements N
sc.setParameters("dataCenterId", zoneId);
return search(sc, null);
}
@Override
public long countByZoneUriAndGuestType(long zoneId, String broadcastUri, GuestType guestType) {
SearchCriteria<Long> sc = CountByZoneAndURI.create();
sc.setParameters("dataCenterId", zoneId);
sc.setParameters("broadcastUri", broadcastUri);
sc.setParameters("guestType", guestType);
return customSearch(sc, null).get(0);
}
@Override
public List<NetworkVO> listByZoneSecurityGroup(Long zoneId) {