You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ki...@apache.org on 2014/03/14 18:17:35 UTC

git commit: updated refs/heads/master to 384eeaf

Repository: cloudstack
Updated Branches:
  refs/heads/master ee99d5ee8 -> 384eeaf79


CLOUDSTACK-2692 Assigning LB rule for vm nic secondary ips


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/384eeaf7
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/384eeaf7
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/384eeaf7

Branch: refs/heads/master
Commit: 384eeaf79261c3f744daa138369a424d3ef37295
Parents: ee99d5e
Author: Jayapal <ja...@apache.org>
Authored: Fri Mar 14 22:28:45 2014 +0530
Committer: Kishan Kavala <ki...@cloud.com>
Committed: Fri Mar 14 22:47:17 2014 +0530

----------------------------------------------------------------------
 .../network/lb/LoadBalancingRulesService.java   |   2 +-
 .../org/apache/cloudstack/api/ApiConstants.java |   2 +
 .../AssignToLoadBalancerRuleCmd.java            |  47 ++++++++-
 .../cloud/network/dao/LoadBalancerVMMapDao.java |   2 +
 .../network/dao/LoadBalancerVMMapDaoImpl.java   |   8 ++
 .../cloud/network/dao/LoadBalancerVMMapVO.java  |  19 ++++
 .../com/cloud/network/NetworkServiceImpl.java   |  22 +++-
 .../cloud/network/as/AutoScaleManagerImpl.java  |   2 +-
 .../lb/LoadBalancingRulesManagerImpl.java       | 101 ++++++++++++++++---
 setup/db/db/schema-430to440.sql                 |   2 +
 10 files changed, 185 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/384eeaf7/api/src/com/cloud/network/lb/LoadBalancingRulesService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/network/lb/LoadBalancingRulesService.java b/api/src/com/cloud/network/lb/LoadBalancingRulesService.java
index 4c87d34..ee1df33 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<Long> vmIds);
+    boolean assignToLoadBalancer(long lbRuleId, List<Long> vmIds, Map<Long, List<String>> vmIdIpMap);
 
     boolean assignSSLCertToLoadBalancerRule(Long lbRuleId, String certName, String publicCert, String privateKey);
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/384eeaf7/api/src/org/apache/cloudstack/api/ApiConstants.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index 32107ed..6dc5c18 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";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/384eeaf7/api/src/org/apache/cloudstack/api/command/user/loadbalancer/AssignToLoadBalancerRuleCmd.java
----------------------------------------------------------------------
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 6bd7537..fad2c2a 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<Long> 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<Long, String> 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<Long, List<String>> getVmIdIpListMap() {
+        Map<Long, List<String>> vmIdIpsMap = null;
+        if (vmIdIpMap != null && !vmIdIpMap.isEmpty()) {
+            vmIdIpsMap = new HashMap<Long, List<String>>();
+            Collection idIpsCollection = vmIdIpMap.values();
+            Iterator iter = idIpsCollection.iterator();
+            while (iter.hasNext()) {
+                HashMap<String, String> idIpsMap = (HashMap<String, String>)iter.next();
+                String vmId = idIpsMap.get("vmid");
+                String vmIp = idIpsMap.get("vmip");
+
+                Long longVmId = new Long(vmId);
+
+                List<String> ipsList = null;
+                if (vmIdIpsMap.containsKey(longVmId)) {
+                    ipsList = vmIdIpsMap.get(longVmId);
+                } else {
+                    ipsList = new ArrayList<String>();
+                }
+                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<Long, List<String>> vmIdIpsMap = getVmIdIpListMap();
+
+        boolean result = _lbService.assignToLoadBalancer(getLoadBalancerId(), virtualMachineIds, vmIdIpsMap);
         if (result) {
             SuccessResponse response = new SuccessResponse(getCommandName());
             this.setResponseObject(response);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/384eeaf7/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDao.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDao.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDao.java
index 79eaf8e..51f45c2 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<LoadBalancerVMMapVO, Lo
     LoadBalancerVMMapVO findByLoadBalancerIdAndVmId(long loadBalancerId, long instanceId);
 
     boolean isVmAttachedToLoadBalancer(long loadBalancerId);
+
+    List<LoadBalancerVMMapVO> listByInstanceIp(String instanceIp);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/384eeaf7/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDaoImpl.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDaoImpl.java
index b0b14fc..bb24e04 100644
--- a/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDaoImpl.java
+++ b/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapDaoImpl.java
@@ -60,6 +60,14 @@ public class LoadBalancerVMMapDaoImpl extends GenericDaoBase<LoadBalancerVMMapVO
     }
 
     @Override
+    public List<LoadBalancerVMMapVO> listByInstanceIp(String instanceIp) {
+        SearchCriteria<LoadBalancerVMMapVO> sc = createSearchCriteria();
+        sc.addAnd("instanceIp", SearchCriteria.Op.EQ, instanceIp);
+
+        return listBy(sc);
+    }
+
+    @Override
     public List<LoadBalancerVMMapVO> listByLoadBalancerId(long loadBalancerId) {
         SearchCriteria<LoadBalancerVMMapVO> sc = createSearchCriteria();
         sc.addAnd("loadBalancerId", SearchCriteria.Op.EQ, loadBalancerId);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/384eeaf7/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapVO.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerVMMapVO.java
index 0a67106..08b9184 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;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/384eeaf7/server/src/com/cloud/network/NetworkServiceImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java
index 9238a1e..e255976 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<LoadBalancerVMMapVO> 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);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/384eeaf7/server/src/com/cloud/network/as/AutoScaleManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/as/AutoScaleManagerImpl.java b/server/src/com/cloud/network/as/AutoScaleManagerImpl.java
index 99189fe..b6e917d 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<Type> extends ManagerBase implements AutoScale
             }
         }
         lstVmId.add(new Long(vmId));
-        return _loadBalancingRulesService.assignToLoadBalancer(lbId, lstVmId);
+        return _loadBalancingRulesService.assignToLoadBalancer(lbId, lstVmId, null);
 
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/384eeaf7/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
index 9f280ef..8a7e029 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<Type> 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<Type> 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<Long> instanceIds) {
+    public boolean assignToLoadBalancer(long loadBalancerId, List<Long> instanceIds, Map<Long, List<String>> vmIdIpMap) {
         CallContext ctx = CallContext.current();
         Account caller = ctx.getCallingAccount();
 
@@ -932,22 +936,68 @@ public class LoadBalancingRulesManagerImpl<Type> 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<Long, List<String>>();
+            for (long instanceId: instanceIds){
+                vmIdIpMap.put(instanceId, null);
+            }
+        }
+
         List<LoadBalancerVMMapVO> mappedInstances = _lb2VmMapDao.listByLoadBalancerId(loadBalancerId, false);
         Set<Long> mappedInstanceIds = new HashSet<Long>();
         for (LoadBalancerVMMapVO mappedInstance : mappedInstances) {
             mappedInstanceIds.add(Long.valueOf(mappedInstance.getInstanceId()));
         }
 
-        final List<UserVm> vmsToAdd = new ArrayList<UserVm>();
+        Map<Long, List<String>> existingVmIdIps = new HashMap<Long, List<String>>();
+        // 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<String> ipsList = null;
+            if (existingVmIdIps.containsKey(mappedInstance.getInstanceId())) {
+                ipsList = existingVmIdIps.get(mappedInstance.getInstanceId());
+            } else {
+                ipsList = new ArrayList<String>();
+            }
+            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<UserVm> vmsToAdd = new ArrayList<UserVm>();
+
+        // check for conflict
+        Set<Long> passedInstanceIds = vmIdIpMap.keySet();
+        for (Long instanceId : passedInstanceIds) {
+            if (existingVmIdIps.containsKey(instanceId)) {
+                // now check for ip address
+                List<String> mappedIps = existingVmIdIps.get(instanceId);
+                List<String> 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<Type> extends ManagerBase implements
                 throw ex;
             }
 
+            String priIp = nicInSameNetwork.getIp4Address();
+            List<String> vmIpsList = vmIdIpMap.get(instanceId);
+            String vmLbIp = null;
+
+            if (vmIpsList == null) {
+                vmIpsList = new ArrayList<String>();
+                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<Long> vmIds = vmIdIpMap.keySet();
+        final Map<Long, List<String>> 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<String> 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<Type> 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<Type> 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);
         }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/384eeaf7/setup/db/db/schema-430to440.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-430to440.sql b/setup/db/db/schema-430to440.sql
index 9a44835..ed86387 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