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
	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
This commit is contained in:
Alena Prokharchyk 2012-05-10 12:55:57 -07:00
parent 5f3e0c5783
commit 810151586b
11 changed files with 152 additions and 51 deletions

View File

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

View File

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

View File

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

View File

@ -134,4 +134,10 @@ public interface NetworkService {
List<? extends Network> getIsolatedNetworksWithSourceNATOwnedByAccountInZone(long zoneId, Account owner);
/**
* @param network
* @return
*/
boolean canUseForDeploy(Network network);
}

View File

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

View File

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

View File

@ -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<NetworkVO> 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<Network.Capability, String> 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<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, 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<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");
@ -4368,6 +4386,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

@ -55,5 +55,7 @@ public interface IPAddressDao extends GenericDao<IPAddressVO, Long> {
List<IPAddressVO> listByPhysicalNetworkId(long physicalNetworkId);
long countFreeIPs();
}
long countFreePublicIPs();
long countFreeIPsInNetwork(long networkId);
}

View File

@ -110,6 +110,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);
@ -293,10 +294,18 @@ 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);
return customSearch(sc, null).get(0);
}
@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);
@ -117,7 +119,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);
@ -298,11 +310,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
@ -311,6 +325,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) {