You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ml...@apache.org on 2013/01/24 22:42:39 UTC

git commit: Summary: Allow adding of more than one nic on the same network

Updated Branches:
  refs/heads/add_remove_nics ed12b2304 -> bdbbbc36e


Summary: Allow adding of more than one nic on the same network

Detail: Cloudstack allows you to launch a VM with two or more nics on the
same network, so this allows you to add more than one nic on the same network
after deployment

Submitted-by: Brian Angus <bl...@betterservers.com>
Signed-off-by: Marcus Sorensen <ma...@betterservers.com> 1359063744 -0700


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

Branch: refs/heads/add_remove_nics
Commit: bdbbbc36e7407ac2e2847d590d1f861e92f42c8e
Parents: ed12b23
Author: Marcus Sorensen <ma...@betterservers.com>
Authored: Thu Jan 24 14:42:24 2013 -0700
Committer: Marcus Sorensen <ma...@betterservers.com>
Committed: Thu Jan 24 14:42:24 2013 -0700

----------------------------------------------------------------------
 .../org/apache/cloudstack/api/ApiConstants.java    |    1 +
 .../api/command/user/vm/RemoveNicFromVMCmd.java    |   14 +-
 .../command/user/vm/UpdateDefaultNicForVMCmd.java  |   18 ++--
 .../cloudstack/api/response/NicResponse.java       |    3 +
 server/src/com/cloud/network/NetworkManager.java   |    2 +-
 .../src/com/cloud/network/NetworkManagerImpl.java  |    4 +-
 server/src/com/cloud/vm/UserVmManagerImpl.java     |  103 ++++++---------
 server/src/com/cloud/vm/VirtualMachineManager.java |    9 ++
 .../com/cloud/vm/VirtualMachineManagerImpl.java    |   64 ++++++++-
 .../com/cloud/network/MockNetworkManagerImpl.java  |    2 +-
 .../cloud/vm/MockVirtualMachineManagerImpl.java    |    9 ++
 .../test/com/cloud/vpc/MockNetworkManagerImpl.java |    4 +-
 12 files changed, 146 insertions(+), 87 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bdbbbc36/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 58a7831..abcab05 100644
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -224,6 +224,7 @@ public class ApiConstants {
     public static final String NETWORK_OFFERING_ID = "networkofferingid";
     public static final String NETWORK_IDS = "networkids";
     public static final String NETWORK_ID = "networkid";
+    public static final String NIC_ID = "nicid";
     public static final String SPECIFY_VLAN = "specifyvlan";
     public static final String IS_DEFAULT = "isdefault";
     public static final String IS_SYSTEM = "issystem";

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bdbbbc36/api/src/org/apache/cloudstack/api/command/user/vm/RemoveNicFromVMCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/RemoveNicFromVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/RemoveNicFromVMCmd.java
index aea953a..b728f91 100644
--- a/api/src/org/apache/cloudstack/api/command/user/vm/RemoveNicFromVMCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/vm/RemoveNicFromVMCmd.java
@@ -24,7 +24,7 @@ import org.apache.log4j.Logger;
 import org.apache.cloudstack.api.*;
 import org.apache.cloudstack.api.ApiConstants.VMDetails;
 import org.apache.cloudstack.api.response.UserVmResponse;
-import org.apache.cloudstack.api.response.NetworkResponse;
+import org.apache.cloudstack.api.response.NicResponse;
 import com.cloud.event.EventTypes;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientCapacityException;
@@ -48,9 +48,9 @@ public class RemoveNicFromVMCmd extends BaseCmd {
             required=true, description="Virtual Machine ID")
     private Long vmId;
 
-    @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType=NetworkResponse.class,
-            required=true, description="Network ID")
-    private Long netId;
+    @Parameter(name=ApiConstants.NIC_ID, type=CommandType.UUID, entityType=NicResponse.class,
+            required=true, description="NIC ID")
+    private Long nicId;
 
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
@@ -60,8 +60,8 @@ public class RemoveNicFromVMCmd extends BaseCmd {
         return vmId;
     }
     
-    public Long getNetworkId() {
-        return netId;
+    public Long getNicId() {
+        return nicId;
     }
 
     /////////////////////////////////////////////////////
@@ -88,7 +88,7 @@ public class RemoveNicFromVMCmd extends BaseCmd {
 
     @Override
     public void execute(){
-        UserContext.current().setEventDetails("Vm Id: "+getVmId());
+        UserContext.current().setEventDetails("Vm Id: "+getVmId() + " Nic Id: " + getNicId());
         UserVm result = _userVmService.removeNicFromVirtualMachine(this);
         ArrayList<VMDetails> dc = new ArrayList<VMDetails>();
         dc.add(VMDetails.valueOf("nics"));

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bdbbbc36/api/src/org/apache/cloudstack/api/command/user/vm/UpdateDefaultNicForVMCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateDefaultNicForVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateDefaultNicForVMCmd.java
index 19d3bdb..f7a8a0b 100644
--- a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateDefaultNicForVMCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateDefaultNicForVMCmd.java
@@ -24,7 +24,7 @@ import org.apache.log4j.Logger;
 import org.apache.cloudstack.api.*;
 import org.apache.cloudstack.api.ApiConstants.VMDetails;
 import org.apache.cloudstack.api.response.UserVmResponse;
-import org.apache.cloudstack.api.response.NetworkResponse;
+import org.apache.cloudstack.api.response.NicResponse;
 import com.cloud.event.EventTypes;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientCapacityException;
@@ -48,9 +48,9 @@ public class UpdateDefaultNicForVMCmd extends BaseCmd {
             required=true, description="Virtual Machine ID")
     private Long vmId;
 
-    @Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType=NetworkResponse.class,
-            required=true, description="Network ID")
-    private Long netId;
+    @Parameter(name=ApiConstants.NIC_ID, type=CommandType.UUID, entityType=NicResponse.class,
+            required=true, description="NIC ID")
+    private Long nicId;
 
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
@@ -59,11 +59,11 @@ public class UpdateDefaultNicForVMCmd extends BaseCmd {
     public Long getVmId() {
         return vmId;
     }
-    
-    public Long getNetworkId() {
-        return netId;
-    }
 
+    public Long getNicId() {
+        return nicId;
+    }
+    
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
@@ -88,7 +88,7 @@ public class UpdateDefaultNicForVMCmd extends BaseCmd {
 
     @Override
     public void execute(){
-        UserContext.current().setEventDetails("Vm Id: "+getVmId());
+        UserContext.current().setEventDetails("Vm Id: "+getVmId() + " Nic Id: " + getNicId());
         UserVm result = _userVmService.updateDefaultNicForVirtualMachine(this);
         ArrayList<VMDetails> dc = new ArrayList<VMDetails>();
         dc.add(VMDetails.valueOf("nics"));

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bdbbbc36/api/src/org/apache/cloudstack/api/response/NicResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/NicResponse.java b/api/src/org/apache/cloudstack/api/response/NicResponse.java
index a6ca5b8..7e200ae 100644
--- a/api/src/org/apache/cloudstack/api/response/NicResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/NicResponse.java
@@ -17,11 +17,14 @@
 package org.apache.cloudstack.api.response;
 
 import org.apache.cloudstack.api.ApiConstants;
+import com.cloud.vm.Nic;
 import com.cloud.serializer.Param;
 import com.google.gson.annotations.SerializedName;
 import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.api.EntityReference;
 
 @SuppressWarnings("unused")
+@EntityReference(value=Nic.class)
 public class NicResponse extends BaseResponse {
 
     @SerializedName("id") @Param(description="the ID of the nic")

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bdbbbc36/server/src/com/cloud/network/NetworkManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java
index c0065dd..695a8f0 100755
--- a/server/src/com/cloud/network/NetworkManager.java
+++ b/server/src/com/cloud/network/NetworkManager.java
@@ -262,7 +262,7 @@ public interface NetworkManager  {
      * @throws InsufficientCapacityException
      * @throws ResourceUnavailableException
      */
-    NicProfile createNicForVm(Network network, NicProfile requested, ReservationContext context, VirtualMachineProfile<? extends VMInstanceVO> vmProfile, boolean prepare) throws InsufficientVirtualNetworkCapcityException,
+    NicProfile createNicForVm(Network network, NicProfile requested, ReservationContext context, VirtualMachineProfile<? extends VMInstanceVO> vmProfile, boolean prepare, boolean alwayscreate) throws InsufficientVirtualNetworkCapcityException,
             InsufficientAddressCapacityException, ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException;
 
 

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bdbbbc36/server/src/com/cloud/network/NetworkManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java
index 241c07f..d1c3181 100755
--- a/server/src/com/cloud/network/NetworkManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkManagerImpl.java
@@ -3355,7 +3355,7 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener {
     }
     
     @Override
-    public NicProfile createNicForVm(Network network, NicProfile requested, ReservationContext context, VirtualMachineProfile<? extends VMInstanceVO> vmProfile, boolean prepare)
+    public NicProfile createNicForVm(Network network, NicProfile requested, ReservationContext context, VirtualMachineProfile<? extends VMInstanceVO> vmProfile, boolean prepare, boolean alwayscreate)
             throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException,
             ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
                 
@@ -3367,7 +3367,7 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener {
                 NicProfile nic = getNicProfileForVm(network, requested, vm);
                 
                 //1) allocate nic (if needed)
-                if (nic == null) {
+                if (nic == null || alwayscreate) {
                     int deviceId = _nicDao.countNics(vm.getId());
                     
                     nic = allocateNic(requested, network, false, 

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bdbbbc36/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java
index b1fa323..d2e85a0 100644
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -929,20 +929,17 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
         Account caller = UserContext.current().getCaller();
 
         UserVmVO vmInstance = _vmDao.findById(vmId);
-        NetworkVO network = _networkDao.findById(networkId);
-
-        NicProfile profile = new NicProfile(null);
-        if(ipAddress != null) {
-          profile = new NicProfile(ipAddress);
-        }
-
         if(vmInstance == null) {
             throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId);
         }
-
+        NetworkVO network = _networkDao.findById(networkId);
         if(network == null) {
             throw new InvalidParameterValueException("unable to find a network with id " + networkId);
         }
+        NicProfile profile = new NicProfile(null);
+        if(ipAddress != null) {
+          profile = new NicProfile(ipAddress);
+        }
 
         // Perform permission check on VM
         _accountMgr.checkAccess(caller, null, true, vmInstance);
@@ -952,7 +949,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
             // Check account permissions
             List<NetworkVO> networkMap = _networkDao.listBy(caller.getId(), network.getId());
             if (networkMap == null || networkMap.isEmpty()) {
-                throw new PermissionDeniedException("Unable to create a vm using network with id " + network.getId() + ", permission denied");
+                throw new PermissionDeniedException("Unable to modify a vm using network with id " + network.getId() + ", permission denied");
             }
         }
         
@@ -961,11 +958,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
         //todo: check other nics for VPC networks (can only belong to one?)
         //todo: verify unique hostname in network domain?
         
-        //verify that there isn't a NIC attached to network
-        if(_networkModel.getNicInNetwork(vmInstance.getId(),network.getId()) != null){
-            throw new CloudRuntimeException("Unable to add NIC to " + vmInstance + " because it already has a NIC attached to " + network);
-        }
-
         NicProfile guestNic = null;
 
         try {
@@ -988,29 +980,36 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
     @Override
     public UserVm removeNicFromVirtualMachine(RemoveNicFromVMCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, CloudRuntimeException {
         Long vmId = cmd.getVmId();
-        Long networkId = cmd.getNetworkId();
+        Long nicId = cmd.getNicId();
         Account caller = UserContext.current().getCaller();
 
         UserVmVO vmInstance = _vmDao.findById(vmId);
-        NetworkVO network = _networkDao.findById(networkId);
-
         if(vmInstance == null) {
             throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId);
         }
-
+        NicVO nic = _nicDao.findById(nicId);
+        if (nic == null){
+            throw new InvalidParameterValueException("unable to find a nic with id " + nicId);
+        }
+        NetworkVO network = _networkDao.findById(nic.getNetworkId());
         if(network == null) {
-            throw new InvalidParameterValueException("unable to find a network with id " + networkId);
+            throw new InvalidParameterValueException("unable to find a network with id " + nic.getNetworkId());
         }
 
         // Perform permission check on VM
         _accountMgr.checkAccess(caller, null, true, vmInstance);
 
+        //check to see if nic is attached to VM
+        if (nic.getInstanceId() != vmId) {
+            throw new InvalidParameterValueException(nic + " is not a nic on  " + vmInstance);
+        }
+
         // Perform account permission check on network
         if (network.getGuestType() != Network.GuestType.Shared) {
             // Check account permissions
             List<NetworkVO> networkMap = _networkDao.listBy(caller.getId(), network.getId());
             if (networkMap == null || networkMap.isEmpty()) {
-                throw new PermissionDeniedException("Unable to create a vm using network with id " + network.getId() + ", permission denied");
+                throw new PermissionDeniedException("Unable to modify a vm using network with id " + network.getId() + ", permission denied");
             }
         }
         
@@ -1021,7 +1020,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
         boolean nicremoved = false;
 
         try {
-            nicremoved = _itMgr.removeVmFromNetwork(vmInstance, network, null);
+            nicremoved = _itMgr.removeNicFromVm(vmInstance, nic);
         } catch (ResourceUnavailableException e) {
             throw new CloudRuntimeException("Unable to remove " + network + " from " + vmInstance +": " + e);
             
@@ -1042,19 +1041,20 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
     @Override
     public UserVm updateDefaultNicForVirtualMachine(UpdateDefaultNicForVMCmd cmd) throws InvalidParameterValueException, CloudRuntimeException {
         Long vmId = cmd.getVmId();
-        Long networkId = cmd.getNetworkId();
+        Long nicId = cmd.getNicId();
         Account caller = UserContext.current().getCaller();
         
         UserVmVO vmInstance = _vmDao.findById(vmId);
-        NetworkVO network = _networkDao.findById(networkId);
-        
-        
         if (vmInstance == null){
             throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId);
         }
-
+        NicVO nic = _nicDao.findById(nicId);
+        if (nic == null){
+            throw new InvalidParameterValueException("unable to find a nic with id " + nicId);
+        }
+        NetworkVO network = _networkDao.findById(nic.getNetworkId());
         if (network == null){
-            throw new InvalidParameterValueException("unable to find a network with id " + networkId);
+            throw new InvalidParameterValueException("unable to find a network with id " + nic.getNetworkId());
         }
         
         // Perform permission check on VM
@@ -1063,74 +1063,57 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
         // no need to check permissions for network, we'll enumerate the ones they already have access to
         Network existingdefaultnet = _networkModel.getDefaultNetworkForVm(vmId);
         
-        // if current default equals chosen new default, return and do nothing
-        if (existingdefaultnet == network){
-            s_logger.warn("Skipping updateDefaultNicForVirtualMachine, selected network matches existing default");
-            return _vmDao.findById(vmInstance.getId());
+        //check to see if nic is attached to VM
+        if (nic.getInstanceId() != vmId) {
+            throw new InvalidParameterValueException(nic + " is not a nic on  " + vmInstance);
         }
-        else {
-            s_logger.debug("looks like we want to change from " + existingdefaultnet + " to " + network);
+        // if current default equals chosen new default, Throw an exception
+        if (nic.isDefaultNic()){
+            throw new CloudRuntimeException("refusing to set default nic because chosen nic is already the default");
         }
         
-        NicProfile chosen = _networkModel.getNicProfile(vmInstance, network.getId(), null);
         NicProfile existing = _networkModel.getNicProfile(vmInstance, existingdefaultnet.getId(), null);
         
-        // if we can't find the chosen nic, fail!
-        if (chosen == null){
-            throw new CloudRuntimeException("Failed to find an existing nic for " + vmInstance +" on " + network);
-        }
-        else if (chosen.id == existing.id){
-            throw new CloudRuntimeException("refusing to set default nic because chosen network is already the default");
-        }
-        else {
-            s_logger.debug("chosen nic profile found was "+chosen+" with dev id "+chosen.deviceId+" and nic id "+chosen.id);
-        }
         if (existing == null){
             s_logger.warn("Failed to update default nic, no nic profile found for existing default network");
             throw new CloudRuntimeException("Failed to find a nic profile for the existing default network. This is bad and probably means some sort of configuration corruption");
         }
 
-        NicVO chosenVO = _nicDao.findById(chosen.id);
         NicVO existingVO = _nicDao.findById(existing.id);
-        Integer chosenID = chosen.getDeviceId();
+        Integer chosenID = nic.getDeviceId();
         Integer existingID = existing.getDeviceId();
 
-        chosenVO.setDefaultNic(true);
-        chosenVO.setDeviceId(existingID);
+        nic.setDefaultNic(true);
+        nic.setDeviceId(existingID);
         existingVO.setDefaultNic(false);
         existingVO.setDeviceId(chosenID);
 
-        chosenVO = _nicDao.persist(chosenVO);
+        nic = _nicDao.persist(nic);
         existingVO = _nicDao.persist(existingVO);
 
         Network newdefault = null;
         newdefault = _networkModel.getDefaultNetworkForVm(vmId);
         
         if (newdefault == null){
-             chosenVO.setDefaultNic(false);
-             chosenVO.setDeviceId(chosenID);
+             nic.setDefaultNic(false);
+             nic.setDeviceId(chosenID);
              existingVO.setDefaultNic(true);
              existingVO.setDeviceId(existingID);
 
-             chosenVO = _nicDao.persist(chosenVO);
+             nic = _nicDao.persist(nic);
              existingVO = _nicDao.persist(existingVO);
              
              newdefault = _networkModel.getDefaultNetworkForVm(vmId);
              if (newdefault.getId() == existingdefaultnet.getId()) {
                     throw new CloudRuntimeException("Setting a default nic failed, and we had no default nic, but we were able to set it back to the original");
              }
-             throw new CloudRuntimeException("Failed to change default nic to " + network + " and now we have no default");
-        } else if (newdefault.getId() != networkId){
-            if(newdefault.getId() == existingdefaultnet.getId()) {
-                throw new CloudRuntimeException("Default nic did not change from previous setting");
-            }
-            throw new CloudRuntimeException("Failed to change default nic to " + network + " with id "+ networkId + ", current default is " + newdefault+ " id " + newdefault.getId());
-        } else if (newdefault.getId() == networkId ) {
+             throw new CloudRuntimeException("Failed to change default nic to " + nic + " and now we have no default");
+        } else if (newdefault.getId() == nic.getNetworkId()) {
             s_logger.debug("successfully set default network to " + network + " for " + vmInstance);
             return _vmDao.findById(vmInstance.getId());
         }
  
-        throw new CloudRuntimeException("something strange happened, new default net is not null, not equal to chosen network, not NOT equal to chosen net");
+        throw new CloudRuntimeException("something strange happened, new default network(" + newdefault.getId() + ") is not null, and is not equal to the network(" + nic.getNetworkId() + ") of the chosen nic");
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bdbbbc36/server/src/com/cloud/vm/VirtualMachineManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/VirtualMachineManager.java b/server/src/com/cloud/vm/VirtualMachineManager.java
index a9c161e..2d70166 100644
--- a/server/src/com/cloud/vm/VirtualMachineManager.java
+++ b/server/src/com/cloud/vm/VirtualMachineManager.java
@@ -166,6 +166,15 @@ public interface VirtualMachineManager extends Manager {
 
     /**
      * @param vm
+     * @param nic
+     * @return
+     * @throws ResourceUnavailableException 
+     * @throws ConcurrentOperationException 
+     */
+    boolean removeNicFromVm(VirtualMachine vm, NicVO nic) throws ConcurrentOperationException, ResourceUnavailableException;
+
+    /**
+     * @param vm
      * @param network
      * @param broadcastUri TODO
      * @return

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bdbbbc36/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
index 8546467..7ab9309 100755
--- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -2476,7 +2476,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
         //check vm state
         if (vm.getState() == State.Running) {
             //1) allocate and prepare nic
-            NicProfile nic = _networkMgr.createNicForVm(network, requested, context, vmProfile, true);
+            NicProfile nic = _networkMgr.createNicForVm(network, requested, context, vmProfile, true, false);
             
             //2) Convert vmProfile to vmTO
             HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vmProfile.getVirtualMachine().getHypervisorType());
@@ -2498,7 +2498,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
             }
         } else if (vm.getState() == State.Stopped) {
             //1) allocate nic
-            return _networkMgr.createNicForVm(network, requested, context, vmProfile, false);
+            return _networkMgr.createNicForVm(network, requested, context, vmProfile, false, false);
         } else {
             s_logger.warn("Unable to add vm " + vm + " to network  " + network);
             throw new ResourceUnavailableException("Unable to add vm " + vm + " to network, is not in the right state",
@@ -2524,7 +2524,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
         //check vm state
         if (vm.getState() == State.Running) {
             //1) allocate and prepare nic
-            NicProfile nic = _networkMgr.createNicForVm(network, requested, context, vmProfile, true);
+            NicProfile nic = _networkMgr.createNicForVm(network, requested, context, vmProfile, true, true);
             
             //2) Convert vmProfile to vmTO
             HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vmProfile.getVirtualMachine().getHypervisorType());
@@ -2546,7 +2546,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
             }
         } else if (vm.getState() == State.Stopped) {
             //1) allocate nic
-            return _networkMgr.createNicForVm(network, requested, context, vmProfile, false);
+            return _networkMgr.createNicForVm(network, requested, context, vmProfile, false, true);
         } else {
             s_logger.warn("Unable to add vm " + vm + " to network  " + network);
             throw new ResourceUnavailableException("Unable to add vm " + vm + " to network, is not in the right state",
@@ -2563,6 +2563,61 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
     }
     
     @Override
+    public boolean removeNicFromVm(VirtualMachine vm, NicVO nic) throws ConcurrentOperationException, ResourceUnavailableException {
+        VMInstanceVO vmVO = _vmDao.findById(vm.getId());
+        NetworkVO network = _networkDao.findById(nic.getNetworkId());
+        ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM), 
+                _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM));
+
+        VirtualMachineProfileImpl<VMInstanceVO> vmProfile = new VirtualMachineProfileImpl<VMInstanceVO>(vmVO, null, 
+                null, null, null);
+
+        DataCenter dc = _configMgr.getZone(network.getDataCenterId());
+        Host host = _hostDao.findById(vm.getHostId()); 
+        DeployDestination dest = new DeployDestination(dc, null, null, host);
+        VirtualMachineGuru<VMInstanceVO> vmGuru = getVmGuru(vmVO);
+        HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vmProfile.getVirtualMachine().getHypervisorType());
+        VirtualMachineTO vmTO = hvGuru.implement(vmProfile);
+
+        // don't delete default NIC on a user VM
+        if (nic.isDefaultNic() && vm.getType() == VirtualMachine.Type.User ) {
+            s_logger.warn("Failed to remove nic from " + vm + " in " + network + ", nic is default.");
+            throw new CloudRuntimeException("Failed to remove nic from " + vm + " in " + network + ", nic is default.");
+        }
+
+        NicProfile nicProfile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), 
+                _networkModel.getNetworkRate(network.getId(), vm.getId()), 
+                _networkModel.isSecurityGroupSupportedInNetwork(network), 
+                _networkModel.getNetworkTag(vmProfile.getVirtualMachine().getHypervisorType(), network));
+        
+        //1) Unplug the nic
+        if (vm.getState() == State.Running) {
+            NicTO nicTO = toNicTO(nicProfile, vmProfile.getVirtualMachine().getHypervisorType());
+            s_logger.debug("Un-plugging nic " + nic + " for vm " + vm + " from network " + network);
+            boolean result = vmGuru.unplugNic(network, nicTO, vmTO, context, dest);
+            if (result) {
+                s_logger.debug("Nic is unplugged successfully for vm " + vm + " in network " + network );
+            } else {
+                s_logger.warn("Failed to unplug nic for the vm " + vm + " from network " + network);
+                return false;
+            }
+        } else if (vm.getState() != State.Stopped) {
+            s_logger.warn("Unable to remove vm " + vm + " from network  " + network);
+            throw new ResourceUnavailableException("Unable to remove vm " + vm + " from network, is not in the right state",
+                    DataCenter.class, vm.getDataCenterIdToDeployIn());
+        }
+        
+        //2) Release the nic
+        _networkMgr.releaseNic(vmProfile, nic);
+        s_logger.debug("Successfully released nic " + nic +  "for vm " + vm);
+        
+        //3) Remove the nic
+        _networkMgr.removeNic(vmProfile, nic);
+        _nicsDao.expunge(nic.getId());
+        return true;
+    }
+
+    @Override
     public boolean removeVmFromNetwork(VirtualMachine vm, Network network, URI broadcastUri) throws ConcurrentOperationException, ResourceUnavailableException {
         VMInstanceVO vmVO = _vmDao.findById(vm.getId());
         ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM), 
@@ -2625,7 +2680,6 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
         
         //3) Remove the nic
         _networkMgr.removeNic(vmProfile, nic);
-        _nicsDao.expunge(nic.getId());
         return true;
     }
    

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bdbbbc36/server/test/com/cloud/network/MockNetworkManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java
index c9446bb..850d92a 100755
--- a/server/test/com/cloud/network/MockNetworkManagerImpl.java
+++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java
@@ -733,7 +733,7 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager, NetworkS
      */
     @Override
     public NicProfile createNicForVm(Network network, NicProfile requested, ReservationContext context,
-            VirtualMachineProfile<? extends VMInstanceVO> vmProfile, boolean prepare)
+            VirtualMachineProfile<? extends VMInstanceVO> vmProfile, boolean prepare, boolean alwayscreate)
             throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException,
             ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
         // TODO Auto-generated method stub

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bdbbbc36/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java b/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java
index 6ff0a53..403055b 100755
--- a/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java
+++ b/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java
@@ -283,6 +283,15 @@ public class MockVirtualMachineManagerImpl implements VirtualMachineManager {
      * @see com.cloud.vm.VirtualMachineManager#removeVmFromNetwork(com.cloud.vm.VirtualMachine, com.cloud.network.Network, java.net.URI)
      */
     @Override
+    public boolean removeNicFromVm(VirtualMachine vm, NicVO nic) throws ConcurrentOperationException, ResourceUnavailableException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    /* (non-Javadoc)
+     * @see com.cloud.vm.VirtualMachineManager#removeVmFromNetwork(com.cloud.vm.VirtualMachine, com.cloud.network.Network, java.net.URI)
+     */
+    @Override
     public boolean removeVmFromNetwork(VirtualMachine vm, Network network, URI broadcastUri) throws ConcurrentOperationException, ResourceUnavailableException {
         // TODO Auto-generated method stub
         return false;

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/bdbbbc36/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
index 63bc752..c55b4c0 100644
--- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
@@ -1123,11 +1123,11 @@ public class MockNetworkManagerImpl implements NetworkManager, NetworkService, M
 
 
     /* (non-Javadoc)
-     * @see com.cloud.network.NetworkManager#createNicForVm(com.cloud.network.Network, com.cloud.vm.NicProfile, com.cloud.vm.ReservationContext, com.cloud.vm.VirtualMachineProfileImpl, boolean)
+     * @see com.cloud.network.NetworkManager#createNicForVm(com.cloud.network.Network, com.cloud.vm.NicProfile, com.cloud.vm.ReservationContext, com.cloud.vm.VirtualMachineProfileImpl, boolean, boolean)
      */
     @Override
     public NicProfile createNicForVm(Network network, NicProfile requested, ReservationContext context,
-            VirtualMachineProfile<? extends VMInstanceVO> vmProfile, boolean prepare)
+            VirtualMachineProfile<? extends VMInstanceVO> vmProfile, boolean prepare, boolean alwayscreate)
             throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException,
             ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
         // TODO Auto-generated method stub