From 4fcb406f2bb548cbc6726cd75dbef9834b3a3689 Mon Sep 17 00:00:00 2001 From: alena Date: Tue, 21 Jun 2011 16:11:56 -0700 Subject: [PATCH] bug 4706: allow to specify which ip address from the network to take when do vm deployment. The model is supported for multiple network case as well. status 4706: resolved fixed --- api/src/com/cloud/api/ApiConstants.java | 1 + .../com/cloud/api/commands/DeployVMCmd.java | 46 +++++++++++++++-- api/src/com/cloud/vm/NicProfile.java | 9 ++++ api/src/com/cloud/vm/UserVmService.java | 37 +++++++------- .../src/com/cloud/network/NetworkManager.java | 5 +- .../com/cloud/network/NetworkManagerImpl.java | 49 ++++++++++++++++--- .../cloud/network/guru/DirectNetworkGuru.java | 8 +-- .../guru/DirectPodBasedNetworkGuru.java | 7 ++- .../cloud/network/guru/GuestNetworkGuru.java | 4 +- .../network/guru/PodBasedNetworkGuru.java | 4 ++ .../cloud/network/guru/PublicNetworkGuru.java | 7 ++- .../VirtualNetworkApplianceManagerImpl.java | 2 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 24 +++++---- .../cloud/vm/VirtualMachineProfileImpl.java | 2 + 14 files changed, 157 insertions(+), 48 deletions(-) diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index 37e26e9a6e3..e787b75ab84 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -246,4 +246,5 @@ public class ApiConstants { public static final String SNAPSHOT_POLICY = "snapshotpolicy"; public static final String SNAPSHOT_RESERVATION = "snapshotreservation"; public static final String REDUNDANT_ROUTER = "redundantrouter"; + public static final String IP_NETWORK_LIST = "iptonetworklist"; } diff --git a/api/src/com/cloud/api/commands/DeployVMCmd.java b/api/src/com/cloud/api/commands/DeployVMCmd.java index 1399d4b7f19..596614f518e 100644 --- a/api/src/com/cloud/api/commands/DeployVMCmd.java +++ b/api/src/com/cloud/api/commands/DeployVMCmd.java @@ -19,7 +19,11 @@ package com.cloud.api.commands; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; import org.apache.log4j.Logger; @@ -79,7 +83,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { private Long domainId; //Network information - @Parameter(name=ApiConstants.NETWORK_IDS, type=CommandType.LIST, collectionType=CommandType.LONG, description="list of network ids used by virtual machine") + @Parameter(name=ApiConstants.NETWORK_IDS, type=CommandType.LIST, collectionType=CommandType.LONG, description="list of network ids used by virtual machine. Can't be specified with ipToNetworkList parameter") private List networkIds; //DataDisk information @@ -109,6 +113,9 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { @Parameter(name=ApiConstants.SECURITY_GROUP_NAMES, type=CommandType.LIST, collectionType=CommandType.STRING, description="comma separated list of security groups names that going to be applied to the virtual machine. Should be passed only when vm is created from a zone with Basic Network support. Mutually exclusive with securitygroupids parameter") private List securityGroupNameList; + + @Parameter(name = ApiConstants.IP_NETWORK_LIST, type = CommandType.MAP, description = "ip to network mapping. Can't be specified with networkIds parameter. Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].networkid=204 - requests to use ip 10.10.10.11 in network id=204") + private Map ipToNetworkList; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -187,6 +194,16 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { } public List getNetworkIds() { + if (ipToNetworkList != null ) { + if (networkIds != null) { + throw new InvalidParameterValueException("NetworkIds can't be specified along with ipToNetworkMap"); + } else { + List networks = new ArrayList(); + networks.addAll(getIpToNetworkMap().keySet()); + return networks; + } + } + return networkIds; } @@ -201,6 +218,27 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { public Long getHostId() { return hostId; } + + private Map getIpToNetworkMap() { + if (networkIds != null && ipToNetworkList != null) { + throw new InvalidParameterValueException("NetworkIds can't be specified along with ipToNetworkMap"); + } + Map ipToNetworkMap = null; + if (ipToNetworkList != null && !ipToNetworkList.isEmpty()) { + ipToNetworkMap = new HashMap(); + Collection ipsCollection = ipToNetworkList.values(); + Iterator iter = ipsCollection.iterator(); + while (iter.hasNext()) { + HashMap ips = (HashMap) iter.next(); + Long networkId = Long.valueOf(ips.get("networkid")); + String requestedIp = (String) ips.get("ip"); + + ipToNetworkMap.put(networkId, requestedIp); + } + } + + return ipToNetworkMap; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -322,18 +360,18 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { throw new InvalidParameterValueException("Can't specify network Ids in Basic zone"); } else { vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(), owner, name, - displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName); + displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap()); } } else { if (zone.isSecurityGroupEnabled()) { vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), getSecurityGroupIdList(), - owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName); + owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap()); } else { if (getSecurityGroupIdList() != null && !getSecurityGroupIdList().isEmpty()) { throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone"); } vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, getNetworkIds(), owner, name, displayName, - diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName); + diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap()); } } } diff --git a/api/src/com/cloud/vm/NicProfile.java b/api/src/com/cloud/vm/NicProfile.java index 7105fa6226b..d59e9e5c831 100644 --- a/api/src/com/cloud/vm/NicProfile.java +++ b/api/src/com/cloud/vm/NicProfile.java @@ -55,6 +55,7 @@ public class NicProfile { Integer networkRate; boolean isSecurityGroupEnabled; List tags; + String requestedIp; public String getDns1() { return dns1; @@ -254,6 +255,10 @@ public class NicProfile { this.netmask = netmask; this.strategy = strategy; } + + public NicProfile(String requestedIp) { + this.requestedIp = requestedIp; + } public NicProfile() { } @@ -278,6 +283,10 @@ public class NicProfile { this.isSecurityGroupEnabled = enabled; } + public String getRequestedIp() { + return requestedIp; + } + public void deallocate() { this.gateway = null; this.mode = null; diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index ad9f5a6e91f..02f8a37b58e 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -18,6 +18,7 @@ package com.cloud.vm; import java.util.List; +import java.util.Map; import javax.naming.InsufficientResourcesException; @@ -145,10 +146,6 @@ public interface UserVmService { * - the template for the virtual machine * @param securityGroupIdList * - comma separated list of security groups id that going to be applied to the virtual machine - * @param accountName - * - an optional account for the virtual machine. Must be used with domainId - * @param domainId - * - an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used * @param hostName * - host name for the virtual machine * @param displayName @@ -171,7 +168,11 @@ public interface UserVmService { * GET (via querystring), you can send up to 2KB of data after base64 encoding * @param sshKeyPair * - name of the ssh key pair used to login to the virtual machine - * + * @param requestedIps TODO + * @param accountName + * - an optional account for the virtual machine. Must be used with domainId + * @param domainId + * - an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used * @return UserVm object if successful. * * @throws InsufficientCapacityException @@ -183,7 +184,7 @@ public interface UserVmService { * @throws InsufficientResourcesException */ UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List securityGroupIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair) + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** @@ -199,10 +200,6 @@ public interface UserVmService { * - list of network ids used by virtual machine * @param securityGroupIdList * - comma separated list of security groups id that going to be applied to the virtual machine - * @param accountName - * - an optional account for the virtual machine. Must be used with domainId - * @param domainId - * - an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used * @param hostName * - host name for the virtual machine * @param displayName @@ -225,7 +222,11 @@ public interface UserVmService { * GET (via querystring), you can send up to 2KB of data after base64 encoding * @param sshKeyPair * - name of the ssh key pair used to login to the virtual machine - * + * @param requestedIps TODO + * @param accountName + * - an optional account for the virtual machine. Must be used with domainId + * @param domainId + * - an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used * @return UserVm object if successful. * * @throws InsufficientCapacityException @@ -237,7 +238,7 @@ public interface UserVmService { * @throws InsufficientResourcesException */ UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, List securityGroupIdList, - Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair) + Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** @@ -251,10 +252,6 @@ public interface UserVmService { * - the template for the virtual machine * @param networkIdList * - list of network ids used by virtual machine - * @param accountName - * - an optional account for the virtual machine. Must be used with domainId - * @param domainId - * - an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used * @param hostName * - host name for the virtual machine * @param displayName @@ -277,7 +274,11 @@ public interface UserVmService { * GET (via querystring), you can send up to 2KB of data after base64 encoding * @param sshKeyPair * - name of the ssh key pair used to login to the virtual machine - * + * @param requestedIps TODO + * @param accountName + * - an optional account for the virtual machine. Must be used with domainId + * @param domainId + * - an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used * @return UserVm object if successful. * * @throws InsufficientCapacityException @@ -289,7 +290,7 @@ public interface UserVmService { * @throws InsufficientResourcesException */ UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair) + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; /** diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index c84e3d4b453..39eee4c1b30 100644 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -62,10 +62,11 @@ public interface NetworkManager extends NetworkService { * @param owner * @param type * @param networkId + * @param requestedIp TODO * @return * @throws InsufficientAddressCapacityException */ - PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId) throws InsufficientAddressCapacityException; + PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp) throws InsufficientAddressCapacityException; /** * assigns a source nat ip address to an account within a network. @@ -204,5 +205,5 @@ public interface NetworkManager extends NetworkService { IPAddressVO markIpAsUnavailable(long addrId); - public String acquireGuestIpAddress(Network network); + public String acquireGuestIpAddress(Network network, String requestedIp); } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index e098dabc795..305d1479f01 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -239,25 +239,29 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag HashMap _lastNetworkIdsToFree = new HashMap(); @Override - public PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId) throws InsufficientAddressCapacityException { - return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, false, true); + public PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp) throws InsufficientAddressCapacityException { + return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, false, true, requestedIp); } @DB - public PublicIp fetchNewPublicIp(long dcId, Long podId, Long vlanDbId, Account owner, VlanType vlanUse, Long networkId, boolean sourceNat, boolean assign) + public PublicIp fetchNewPublicIp(long dcId, Long podId, Long vlanDbId, Account owner, VlanType vlanUse, Long networkId, boolean sourceNat, boolean assign, String requestedIp) throws InsufficientAddressCapacityException { + StringBuilder errorMessage = new StringBuilder("Unable to get ip adress in "); Transaction txn = Transaction.currentTxn(); txn.start(); SearchCriteria sc = null; if (podId != null) { sc = AssignIpAddressFromPodVlanSearch.create(); sc.setJoinParameters("podVlanMapSB", "podId", podId); + errorMessage.append(" pod id=" + podId); } else { sc = AssignIpAddressSearch.create(); + errorMessage.append(" zone id=" + dcId); } if (vlanDbId != null) { sc.addAnd("vlanId", SearchCriteria.Op.EQ, vlanDbId); + errorMessage.append(", vlanId id=" + vlanDbId); } sc.setParameters("dc", dcId); @@ -265,8 +269,15 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag // for direct network take ip addresses only from the vlans belonging to the network if (vlanUse == VlanType.DirectAttached) { sc.setJoinParameters("vlan", "networkId", networkId); + errorMessage.append(", network id=" + networkId); } sc.setJoinParameters("vlan", "type", vlanUse); + + + if (requestedIp != null) { + sc.addAnd("address", SearchCriteria.Op.EQ, requestedIp); + errorMessage.append(": requested ip " + requestedIp + " is not available"); + } Filter filter = new Filter(IPAddressVO.class, "vlanId", true, 0l, 1l); @@ -274,8 +285,10 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag if (addrs.size() == 0) { if (podId != null) { + s_logger.warn(errorMessage.toString()); throw new InsufficientAddressCapacityException("Insufficient address capacity", HostPodDao.class, podId); } + s_logger.warn(errorMessage.toString()); throw new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId); } @@ -380,7 +393,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag vlanId = maps.get(0).getVlanDbId(); } - ip = fetchNewPublicIp(dcId, null, vlanId, owner, VlanType.VirtualNetwork, network.getId(), true, false); + ip = fetchNewPublicIp(dcId, null, vlanId, owner, VlanType.VirtualNetwork, network.getId(), true, false, null); sourceNat = ip.ip(); markPublicIpAsAllocated(sourceNat); @@ -592,7 +605,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } } - ip = fetchNewPublicIp(zoneId, null, null, ipOwner, VlanType.VirtualNetwork, network.getId(), isSourceNat, false); + ip = fetchNewPublicIp(zoneId, null, null, ipOwner, VlanType.VirtualNetwork, network.getId(), isSourceNat, false, null); if (ip == null) { throw new InsufficientAddressCapacityException("Unable to find available public IP addresses", DataCenter.class, zoneId); @@ -2985,12 +2998,23 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag @Override @DB - public String acquireGuestIpAddress(Network network) { + 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(); + + 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) { @@ -2999,7 +3023,20 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag if (allPossibleIps.isEmpty()) { return null; } + Long[] array = allPossibleIps.toArray(new Long[allPossibleIps.size()]); + + if (requestedIp != null) { + //check that requested ip has the same cidr + 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"); + return null; + } else { + return requestedIp; + } + } + String result; do { result = NetUtils.long2Ip(array[_rand.nextInt(array.length)]); diff --git a/server/src/com/cloud/network/guru/DirectNetworkGuru.java b/server/src/com/cloud/network/guru/DirectNetworkGuru.java index 0a47884ecde..6a90bb13fe7 100644 --- a/server/src/com/cloud/network/guru/DirectNetworkGuru.java +++ b/server/src/com/cloud/network/guru/DirectNetworkGuru.java @@ -137,10 +137,10 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { super(); } - protected void getIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Network network) throws InsufficientVirtualNetworkCapcityException, + protected void getIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Network network, String requestedIp) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException { if (nic.getIp4Address() == null) { - PublicIp ip = _networkMgr.assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId()); + PublicIp ip = _networkMgr.assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId(), requestedIp); nic.setIp4Address(ip.getAddress().toString()); nic.setGateway(ip.getGateway()); nic.setNetmask(ip.getNetmask()); @@ -183,7 +183,7 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { nic.setStrategy(ReservationStrategy.Create); } - getIp(nic, dc, vm, network); + getIp(nic, dc, vm, network, nic.getRequestedIp()); nic.setStrategy(ReservationStrategy.Create); return nic; @@ -193,7 +193,7 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { public void reserve(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException { if (nic.getIp4Address() == null) { - getIp(nic, dest.getDataCenter(), vm, network); + getIp(nic, dest.getDataCenter(), vm, network, null); nic.setStrategy(ReservationStrategy.Create); } } diff --git a/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java b/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java index 155b31803e8..245422f1c36 100644 --- a/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java +++ b/server/src/com/cloud/network/guru/DirectPodBasedNetworkGuru.java @@ -47,6 +47,7 @@ import com.cloud.network.dao.IPAddressDao; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.utils.component.Inject; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.Nic.ReservationStrategy; import com.cloud.vm.NicProfile; import com.cloud.vm.ReservationContext; @@ -95,6 +96,10 @@ public class DirectPodBasedNetworkGuru extends DirectNetworkGuru { if (!canHandle(offering, dc)) { return null; } + + if (nic != null && nic.getRequestedIp() != null) { + throw new CloudRuntimeException("Does not support custom ip allocation at this time: " + nic); + } if (nic == null) { nic = new NicProfile(rsStrategy, null, null, null, null); @@ -127,7 +132,7 @@ public class DirectPodBasedNetworkGuru extends DirectNetworkGuru { InsufficientAddressCapacityException, ConcurrentOperationException { DataCenter dc = _dcDao.findById(pod.getDataCenterId()); if (nic.getIp4Address() == null) { - PublicIp ip = _networkMgr.assignPublicIpAddress(dc.getId(), pod.getId(), vm.getOwner(), VlanType.DirectAttached, network.getId()); + PublicIp ip = _networkMgr.assignPublicIpAddress(dc.getId(), pod.getId(), vm.getOwner(), VlanType.DirectAttached, network.getId(), null); nic.setIp4Address(ip.getAddress().toString()); nic.setFormat(AddressFormat.Ip4); nic.setGateway(ip.getGateway()); diff --git a/server/src/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/com/cloud/network/guru/GuestNetworkGuru.java index 186038b45fc..61cb7f981bb 100644 --- a/server/src/com/cloud/network/guru/GuestNetworkGuru.java +++ b/server/src/com/cloud/network/guru/GuestNetworkGuru.java @@ -181,7 +181,7 @@ public class GuestNetworkGuru extends AdapterBase implements NetworkGuru { nic.setIsolationUri(network.getBroadcastUri()); nic.setGateway(network.getGateway()); - String guestIp = _networkMgr.acquireGuestIpAddress(network); + String guestIp = _networkMgr.acquireGuestIpAddress(network, nic.getRequestedIp()); if (guestIp == null) { throw new InsufficientVirtualNetworkCapcityException("Unable to acquire guest IP address for network " + network, DataCenter.class, dc.getId()); } @@ -192,7 +192,7 @@ public class GuestNetworkGuru extends AdapterBase implements NetworkGuru { nic.setDns1(dc.getDns1()); nic.setDns2(dc.getDns2()); - } + } nic.setStrategy(ReservationStrategy.Start); diff --git a/server/src/com/cloud/network/guru/PodBasedNetworkGuru.java b/server/src/com/cloud/network/guru/PodBasedNetworkGuru.java index 9cb4abcfa41..7dbf6653009 100644 --- a/server/src/com/cloud/network/guru/PodBasedNetworkGuru.java +++ b/server/src/com/cloud/network/guru/PodBasedNetworkGuru.java @@ -46,6 +46,7 @@ import com.cloud.user.Account; import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.Inject; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.Nic.ReservationStrategy; import com.cloud.vm.NicProfile; @@ -87,6 +88,9 @@ public class PodBasedNetworkGuru extends AdapterBase implements NetworkGuru { assert (trafficType == TrafficType.Storage || trafficType == TrafficType.Management) : "Well, I can't take care of this config now can I? " + config; if (nic != null) { + if (nic.getRequestedIp() != null) { + throw new CloudRuntimeException("Does not support custom ip allocation at this time: " + nic); + } nic.setStrategy(nic.getIp4Address() != null ? ReservationStrategy.Create : ReservationStrategy.Start); } else { nic = new NicProfile(ReservationStrategy.Start, null, null, null, null); diff --git a/server/src/com/cloud/network/guru/PublicNetworkGuru.java b/server/src/com/cloud/network/guru/PublicNetworkGuru.java index 2004126cb16..9ff2e03e682 100644 --- a/server/src/com/cloud/network/guru/PublicNetworkGuru.java +++ b/server/src/com/cloud/network/guru/PublicNetworkGuru.java @@ -53,6 +53,7 @@ import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.user.Account; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.Inject; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.Nic.ReservationStrategy; import com.cloud.vm.NicProfile; import com.cloud.vm.ReservationContext; @@ -106,7 +107,7 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru { protected void getIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Network network) throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException { if (nic.getIp4Address() == null) { - PublicIp ip = _networkMgr.assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.VirtualNetwork, null); + PublicIp ip = _networkMgr.assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.VirtualNetwork, null, null); nic.setIp4Address(ip.getAddress().toString()); nic.setGateway(ip.getGateway()); nic.setNetmask(ip.getNetmask()); @@ -140,6 +141,10 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru { if (!canHandle(offering, dc)) { return null; } + + if (nic != null && nic.getRequestedIp() != null) { + throw new CloudRuntimeException("Does not support custom ip allocation at this time: " + nic); + } if (nic == null) { nic = new NicProfile(ReservationStrategy.Create, null, null, null, null); diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 05440b7be6f..42a045a8cd7 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -846,7 +846,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian networks.add(new Pair(publicNetworks.get(0), defaultNic)); NicProfile gatewayNic = new NicProfile(); if (isRedundant) { - gatewayNic.setIp4Address(_networkMgr.acquireGuestIpAddress(guestNetwork)); + gatewayNic.setIp4Address(_networkMgr.acquireGuestIpAddress(guestNetwork, null)); gatewayNic.setMacAddress(_networkMgr.getNextAvailableMacAddressInNetwork(guestNetwork.getId())); } else { gatewayNic.setIp4Address(guestNetwork.getGateway()); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 1cc7b1c8077..930f9905fa9 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -18,8 +18,10 @@ package com.cloud.vm; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; @@ -2010,7 +2012,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager @Override public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List securityGroupIdList, Account owner, - String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair) + String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { Account caller = UserContext.current().getCaller(); @@ -2060,13 +2062,13 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, - diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller); + diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps); } @Override public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, List securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, - String sshKeyPair) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, + String sshKeyPair, Map requestedIps) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { Account caller = UserContext.current().getCaller(); @@ -2171,12 +2173,12 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, - diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller); + diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps); } @Override public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List networkIdList, Account owner, String hostName, - String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair) + String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map requestedIps) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { Account caller = UserContext.current().getCaller(); @@ -2289,13 +2291,13 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } } - return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, userData, sshKeyPair, hypervisor, caller); + return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, userData, sshKeyPair, hypervisor, caller, requestedIps); } @DB @ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true) protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, String hostName, String displayName, Account owner, Long diskOfferingId, - Long diskSize, List networkList, List securityGroupIdList, String group, String userData, String sshKeyPair, HypervisorType hypervisor, Account caller) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException { + Long diskSize, List networkList, List securityGroupIdList, String group, String userData, String sshKeyPair, HypervisorType hypervisor, Account caller, Map requestedIps) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException { _accountMgr.checkAccess(caller, owner); long accountId = owner.getId(); @@ -2413,7 +2415,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } DataCenterDeployment plan = new DataCenterDeployment(zone.getId()); - + List> networks = new ArrayList>(); short defaultNetworkNumber = 0; for (NetworkVO network : networkList) { @@ -2426,7 +2428,11 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager defaultNetworkNumber++; } - networks.add(new Pair(network, null)); + NicProfile profile = null; + if (requestedIps != null && requestedIps.get(network.getId()) != null) { + profile = new NicProfile(requestedIps.get(network.getId())); + } + networks.add(new Pair(network, profile)); } // Verify network information - network default network has to be set; and vm can't have more than one default network diff --git a/server/src/com/cloud/vm/VirtualMachineProfileImpl.java b/server/src/com/cloud/vm/VirtualMachineProfileImpl.java index 972832ea609..c1cf22a8ec3 100644 --- a/server/src/com/cloud/vm/VirtualMachineProfileImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineProfileImpl.java @@ -233,4 +233,6 @@ public class VirtualMachineProfileImpl implements Virtua public void setServiceOffering(ServiceOfferingVO offering) { _offering = offering; } + + }