diff --git a/api/src/com/cloud/network/lb/LoadBalancingRulesService.java b/api/src/com/cloud/network/lb/LoadBalancingRulesService.java index 4c87d342db5..ee1df33cd41 100644 --- a/api/src/com/cloud/network/lb/LoadBalancingRulesService.java +++ b/api/src/com/cloud/network/lb/LoadBalancingRulesService.java @@ -94,7 +94,7 @@ public interface LoadBalancingRulesService { /** * Assign a virtual machine, or list of virtual machines, to a load balancer. */ - boolean assignToLoadBalancer(long lbRuleId, List vmIds); + boolean assignToLoadBalancer(long lbRuleId, List vmIds, Map> vmIdIpMap); boolean assignSSLCertToLoadBalancerRule(Long lbRuleId, String certName, String publicCert, String privateKey); diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 32107edf840..6dc5c18241f 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -262,6 +262,8 @@ public class ApiConstants { public static final String VALUE = "value"; public static final String VIRTUAL_MACHINE_ID = "virtualmachineid"; public static final String VIRTUAL_MACHINE_IDS = "virtualmachineids"; + public static final String VIRTUAL_MACHINE_ID_IP = "vmidipmap"; + public static final String VLAN = "vlan"; public static final String VLAN_RANGE = "vlanrange"; public static final String REMOVE_VLAN = "removevlan"; diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/AssignToLoadBalancerRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/AssignToLoadBalancerRuleCmd.java index 6bd75378272..fad2c2a0c1d 100644 --- a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/AssignToLoadBalancerRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/AssignToLoadBalancerRuleCmd.java @@ -16,7 +16,12 @@ // under the License. package org.apache.cloudstack.api.command.user.loadbalancer; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Collection; +import java.util.Iterator; +import java.util.ArrayList; import org.apache.log4j.Logger; @@ -62,10 +67,12 @@ public class AssignToLoadBalancerRuleCmd extends BaseAsyncCmd { type = CommandType.LIST, collectionType = CommandType.UUID, entityType = UserVmResponse.class, - required = true, description = "the list of IDs of the virtual machine that are being assigned to the load balancer rule(i.e. virtualMachineIds=1,2,3)") private List virtualMachineIds; + @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID_IP, type = CommandType.MAP, description = "VM ID and IP map, vmidipmap[0].vmid=1 vmidipmap[0].ip=10.1.1.75") + private Map vmIdIpMap; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -78,6 +85,10 @@ public class AssignToLoadBalancerRuleCmd extends BaseAsyncCmd { return virtualMachineIds; } + public Map getVmIdIpMap() { + return vmIdIpMap; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -106,10 +117,42 @@ public class AssignToLoadBalancerRuleCmd extends BaseAsyncCmd { return "applying instances for load balancer: " + getLoadBalancerId() + " (ids: " + StringUtils.join(getVirtualMachineIds(), ",") + ")"; } + + public Map> getVmIdIpListMap() { + Map> vmIdIpsMap = null; + if (vmIdIpMap != null && !vmIdIpMap.isEmpty()) { + vmIdIpsMap = new HashMap>(); + Collection idIpsCollection = vmIdIpMap.values(); + Iterator iter = idIpsCollection.iterator(); + while (iter.hasNext()) { + HashMap idIpsMap = (HashMap)iter.next(); + String vmId = idIpsMap.get("vmid"); + String vmIp = idIpsMap.get("vmip"); + + Long longVmId = new Long(vmId); + + List ipsList = null; + if (vmIdIpsMap.containsKey(longVmId)) { + ipsList = vmIdIpsMap.get(longVmId); + } else { + ipsList = new ArrayList(); + } + ipsList.add(vmIp); + vmIdIpsMap.put(longVmId, ipsList); + + } + } + + return vmIdIpsMap; + } + @Override public void execute() { CallContext.current().setEventDetails("Load balancer Id: " + getLoadBalancerId() + " VmIds: " + StringUtils.join(getVirtualMachineIds(), ",")); - boolean result = _lbService.assignToLoadBalancer(getLoadBalancerId(), virtualMachineIds); + + Map> vmIdIpsMap = getVmIdIpListMap(); + + boolean result = _lbService.assignToLoadBalancer(getLoadBalancerId(), virtualMachineIds, vmIdIpsMap); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDao.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDao.java index 79eaf8e16ba..51f45c219eb 100644 --- a/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDao.java +++ b/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDao.java @@ -34,4 +34,6 @@ public interface LoadBalancerVMMapDao extends GenericDao listByInstanceIp(String instanceIp); } diff --git a/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDaoImpl.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDaoImpl.java index b0b14fc23c1..bb24e042212 100644 --- a/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDaoImpl.java +++ b/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDaoImpl.java @@ -59,6 +59,14 @@ public class LoadBalancerVMMapDaoImpl extends GenericDaoBase listByInstanceIp(String instanceIp) { + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("instanceIp", SearchCriteria.Op.EQ, instanceIp); + + return listBy(sc); + } + @Override public List listByLoadBalancerId(long loadBalancerId) { SearchCriteria sc = createSearchCriteria(); diff --git a/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapVO.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapVO.java index 0a67106dc9b..08b918475c3 100644 --- a/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapVO.java +++ b/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapVO.java @@ -39,6 +39,9 @@ public class LoadBalancerVMMapVO implements InternalIdentity { @Column(name = "instance_id") private long instanceId; + @Column(name = "instance_ip") + private String instanceIp; + @Column(name = "revoke") private boolean revoke = false; @@ -59,6 +62,13 @@ public class LoadBalancerVMMapVO implements InternalIdentity { this.revoke = revoke; } + public LoadBalancerVMMapVO(long loadBalancerId, long instanceId, String vmIp, boolean revoke) { + this.loadBalancerId = loadBalancerId; + this.instanceId = instanceId; + this.instanceIp = vmIp; + this.revoke = revoke; + } + @Override public long getId() { return id; @@ -87,4 +97,13 @@ public class LoadBalancerVMMapVO implements InternalIdentity { public void setState(String state) { this.state = state; } + + public String getInstanceIp() { + return instanceIp; + } + + public void setInstanceIp(String instanceIp) { + this.instanceIp = instanceIp; + } + } diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 9238a1e8ce7..e255976ae8a 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -113,10 +113,12 @@ import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.OvsProviderDao; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.LoadBalancerVMMapDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.dao.LoadBalancerVMMapVO; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.OvsProviderVO; import com.cloud.network.element.VirtualRouterElement; @@ -307,6 +309,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { IpAddressManager _ipAddrMgr; @Inject EntityManager _entityMgr; + @Inject + LoadBalancerVMMapDao _lbVmMapDao; int _cidrLimit; boolean _allowSubdomainNetworkAccess; @@ -806,7 +810,15 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { s_logger.debug("VM nic IP " + secondaryIp + " is associated with the static NAT rule public IP address id " + publicIpVO.getId()); throw new InvalidParameterValueException("Can' remove the ip " + secondaryIp + "is associate with static NAT rule public IP address id " + publicIpVO.getId()); } - } else if (dc.getNetworkType() == NetworkType.Basic || ntwkOff.getGuestType() == Network.GuestType.Shared) { + + List lbVmMap = _lbVmMapDao.listByInstanceIp(secondaryIp); + if (lbVmMap != null && lbVmMap.size() != 0) { + s_logger.debug("VM nic IP " + secondaryIp + " is mapped to load balancing rule"); + throw new InvalidParameterValueException("Can't remove the secondary ip " + secondaryIp + " is mapped to load balancing rule"); + + } + + } else if (dc.getNetworkType() == NetworkType.Basic || ntwkOff.getGuestType() == Network.GuestType.Shared) { final IPAddressVO ip = _ipAddressDao.findByIpAndSourceNetworkId(secIpVO.getNetworkId(), secIpVO.getIp4Address()); if (ip != null) { Transaction.execute(new TransactionCallbackNoReturn() { @@ -3819,12 +3831,12 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { PhysicalNetworkVO pvo = _physicalNetworkDao.findById(physicalNetworkId); DataCenterVO dvo = _dcDao.findById(pvo.getDataCenterId()); if (dvo.getNetworkType() == NetworkType.Basic) { - - Provider provider = Network.Provider.getProvider("BaremetalDhcpProvider"); - if (provider == null) { + + Provider provider = Network.Provider.getProvider("BaremetalDhcpProvider"); + if (provider == null) { // baremetal is not loaded return null; - } + } addProviderToPhysicalNetwork(physicalNetworkId, "BaremetalDhcpProvider", null, null); addProviderToPhysicalNetwork(physicalNetworkId, "BaremetalPxeProvider", null, null); diff --git a/server/src/com/cloud/network/as/AutoScaleManagerImpl.java b/server/src/com/cloud/network/as/AutoScaleManagerImpl.java index 99189fe43aa..b6e917dac92 100644 --- a/server/src/com/cloud/network/as/AutoScaleManagerImpl.java +++ b/server/src/com/cloud/network/as/AutoScaleManagerImpl.java @@ -1414,7 +1414,7 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScale } } lstVmId.add(new Long(vmId)); - return _loadBalancingRulesService.assignToLoadBalancer(lbId, lstVmId); + return _loadBalancingRulesService.assignToLoadBalancer(lbId, lstVmId, null); } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 9f280ef7a80..8a7e0298b45 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -30,6 +30,7 @@ import java.util.Set; import javax.ejb.Local; import javax.inject.Inject; +import com.cloud.vm.dao.NicSecondaryIpDao; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBHealthCheckPolicyCmd; import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBStickinessPolicyCmd; @@ -258,6 +259,9 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements @Inject LoadBalancerCertMapDao _lbCertMapDao; + @Inject + NicSecondaryIpDao _nicSecondaryIpDao; + // Will return a string. For LB Stickiness this will be a json, for // autoscale this will be "," separated values @Override @@ -923,7 +927,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements @Override @DB @ActionEvent(eventType = EventTypes.EVENT_ASSIGN_TO_LOAD_BALANCER_RULE, eventDescription = "assigning to load balancer", async = true) - public boolean assignToLoadBalancer(long loadBalancerId, List instanceIds) { + public boolean assignToLoadBalancer(long loadBalancerId, List instanceIds, Map> vmIdIpMap) { CallContext ctx = CallContext.current(); Account caller = ctx.getCallingAccount(); @@ -932,22 +936,68 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements throw new InvalidParameterValueException("Failed to assign to load balancer " + loadBalancerId + ", the load balancer was not found."); } + + if (instanceIds == null && vmIdIpMap == null) { + throw new InvalidParameterValueException("Both instanceids and vmidipmap can't be null"); + } + + // instanceIds and vmIdipmap is passed + if (instanceIds != null && vmIdIpMap != null) { + for(long instanceId: instanceIds) { + if (!vmIdIpMap.containsKey(instanceId)) { + vmIdIpMap.put(instanceId, null); + } + } + } + + //only instanceids list passed + if (instanceIds != null && vmIdIpMap == null){ + vmIdIpMap = new HashMap>(); + for (long instanceId: instanceIds){ + vmIdIpMap.put(instanceId, null); + } + } + List mappedInstances = _lb2VmMapDao.listByLoadBalancerId(loadBalancerId, false); Set mappedInstanceIds = new HashSet(); for (LoadBalancerVMMapVO mappedInstance : mappedInstances) { mappedInstanceIds.add(Long.valueOf(mappedInstance.getInstanceId())); } - final List vmsToAdd = new ArrayList(); + Map> existingVmIdIps = new HashMap>(); + // now get the ips of vm and add it to map + for (LoadBalancerVMMapVO mappedInstance : mappedInstances) { - if (instanceIds == null || instanceIds.isEmpty()) { - s_logger.warn("List of vms to assign to the lb, is empty"); - return false; + List ipsList = null; + if (existingVmIdIps.containsKey(mappedInstance.getInstanceId())) { + ipsList = existingVmIdIps.get(mappedInstance.getInstanceId()); + } else { + ipsList = new ArrayList(); + } + ipsList.add(mappedInstance.getInstanceIp()); + existingVmIdIps.put(mappedInstance.getInstanceId(), ipsList); } - for (Long instanceId : instanceIds) { - if (mappedInstanceIds.contains(instanceId)) { - throw new InvalidParameterValueException("VM " + instanceId + " is already mapped to load balancer."); + + + + final List vmsToAdd = new ArrayList(); + + // check for conflict + Set passedInstanceIds = vmIdIpMap.keySet(); + for (Long instanceId : passedInstanceIds) { + if (existingVmIdIps.containsKey(instanceId)) { + // now check for ip address + List mappedIps = existingVmIdIps.get(instanceId); + List newIps = vmIdIpMap.get(instanceId); + + if (newIps != null) { + for (String newIp: newIps) { + if (mappedIps.contains(newIp)) { + throw new InvalidParameterValueException("VM " + instanceId + " with " + newIp +" is already mapped to load balancer."); + } + } + } } UserVm vm = _vmDao.findById(instanceId); @@ -985,18 +1035,43 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements throw ex; } + String priIp = nicInSameNetwork.getIp4Address(); + List vmIpsList = vmIdIpMap.get(instanceId); + String vmLbIp = null; + + if (vmIpsList == null) { + vmIpsList = new ArrayList(); + vmIpsList.add(priIp); + vmIdIpMap.put(instanceId, vmIpsList); + } else { + //check if the ips belongs to nic secondary ip + for (String ip: vmIpsList) { + if(_nicSecondaryIpDao.findByIp4AddressAndNicId(ip,nicInSameNetwork.getId()) == null) { + throw new InvalidParameterValueException("VM ip specified " + ip + " is not belongs to nic in network " + nicInSameNetwork.getNetworkId()); + } + } + } + + if (s_logger.isDebugEnabled()) { s_logger.debug("Adding " + vm + " to the load balancer pool"); } vmsToAdd.add(vm); } + final Set vmIds = vmIdIpMap.keySet(); + final Map> newMap = vmIdIpMap; + Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { - for (UserVm vm : vmsToAdd) { - LoadBalancerVMMapVO map = new LoadBalancerVMMapVO(loadBalancer.getId(), vm.getId(), false); + + for (Long vmId : vmIds) { + final List lbVmIps = newMap.get(vmId); + for (String vmIp: lbVmIps) { + LoadBalancerVMMapVO map = new LoadBalancerVMMapVO(loadBalancer.getId(), vmId, vmIp, false); map = _lb2VmMapDao.persist(map); + } } } }); @@ -1020,8 +1095,8 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { - for (UserVm vm : vmsToAdd) { - vmInstanceIds.add(vm.getId()); + for (Long vmId : vmIds) { + vmInstanceIds.add(vmId); } } }); @@ -1875,7 +1950,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements for (LoadBalancerVMMapVO lbVmMap : lbVmMaps) { UserVm vm = _vmDao.findById(lbVmMap.getInstanceId()); Nic nic = _nicDao.findByInstanceIdAndNetworkIdIncludingRemoved(lb.getNetworkId(), vm.getId()); - dstIp = nic.getIp4Address(); + dstIp = lbVmMap.getInstanceIp() == null ? nic.getIp4Address(): lbVmMap.getInstanceIp(); LbDestination lbDst = new LbDestination(lb.getDefaultPortStart(), lb.getDefaultPortEnd(), dstIp, lbVmMap.isRevoke()); dstList.add(lbDst); } diff --git a/setup/db/db/schema-430to440.sql b/setup/db/db/schema-430to440.sql index 9a44835ce9b..ed8638708ba 100644 --- a/setup/db/db/schema-430to440.sql +++ b/setup/db/db/schema-430to440.sql @@ -745,3 +745,5 @@ ALTER TABLE `cloud`.`vpc` ADD COLUMN uses_distributed_router boolean default fa INSERT INTO `cloud`.`storage_pool_details` (pool_id,name,value,display) SELECT storage_pool.id,data_center_details.name,data_center_details.value,data_center_details.display FROM `cloud`.`storage_pool` JOIN `cloud`.`data_center_details` ON data_center_details.dc_id=storage_pool.data_center_id WHERE data_center_details.name = "storage.overprovisioning.factor"; DELETE FROM `cloud`.`data_center_details` WHERE name="storage.overprovisioning.factor"; +ALTER TABLE `cloud`.`load_balancer_vm_map` ADD COLUMN instance_ip VARCHAR(40); +ALTER TABLE `cloud`.`load_balancer_vm_map` DROP KEY `load_balancer_id`, ADD UNIQUE KEY load_balancer_id (`load_balancer_id`, `instance_id`, `instance_ip`); \ No newline at end of file