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/31 01:42:25 UTC

git commit: refs/heads/master - Summary: add/remove/update default nics feature

Updated Branches:
  refs/heads/master 99556a4f3 -> 15906c03c


Summary: add/remove/update default nics feature

Description: Adds API calls updateDefaultNicForVirtualMachine,
addNicToVirtualMachine, and removeNicFromVirtualMachine. These are
intended to allow a user to modify a VM's configuration post
deployment, to adjust the networks to which the VM belongs.

BUG-ID: CLOUDSTACK-645
Submitted-by: Brian Angus <bl...@betterservers.com>
Submitted-by: Ryan Dietrich <ry...@betterservers.com>
Signed-off-by: Marcus Sorensen <ma...@betterservers.com> 1359494800 -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/15906c03
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/15906c03
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/15906c03

Branch: refs/heads/master
Commit: 15906c03ca74c8a4d4ca41eec922f80b0613564d
Parents: 99556a4
Author: Marcus Sorensen <ma...@betterservers.com>
Authored: Wed Jan 30 17:40:20 2013 -0700
Committer: Marcus Sorensen <ma...@betterservers.com>
Committed: Wed Jan 30 17:43:21 2013 -0700

----------------------------------------------------------------------
 api/src/com/cloud/event/EventTypes.java            |    5 +
 api/src/com/cloud/vm/UserVmService.java            |   21 +
 .../org/apache/cloudstack/api/ApiConstants.java    |    1 +
 .../api/command/user/vm/AddNicToVMCmd.java         |  121 ++++++
 .../api/command/user/vm/RemoveNicFromVMCmd.java    |  115 +++++
 .../command/user/vm/UpdateDefaultNicForVMCmd.java  |  115 +++++
 .../cloudstack/api/response/NicResponse.java       |    3 +
 client/tomcatconf/commands.properties.in           |    5 +
 server/src/com/cloud/network/NetworkManager.java   |    2 +-
 .../src/com/cloud/network/NetworkManagerImpl.java  |    8 +-
 server/src/com/cloud/network/NetworkModelImpl.java |    5 +-
 .../network/element/VirtualRouterElement.java      |    2 +-
 server/src/com/cloud/vm/UserVmManagerImpl.java     |  286 ++++++++++++-
 server/src/com/cloud/vm/VirtualMachineManager.java |    9 +
 .../com/cloud/vm/VirtualMachineManagerImpl.java    |   98 ++++-
 .../com/cloud/network/MockNetworkManagerImpl.java  |    2 +-
 .../test/com/cloud/vm/MockUserVmManagerImpl.java   |   21 +
 .../cloud/vm/MockVirtualMachineManagerImpl.java    |    9 +
 .../test/com/cloud/vpc/MockNetworkManagerImpl.java |    4 +-
 test/integration/smoke/test_nic.py                 |  335 +++++++++++++++
 tools/marvin/marvin/integration/lib/base.py        |   21 +
 21 files changed, 1163 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/api/src/com/cloud/event/EventTypes.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index 63b7cd0..a797988 100755
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -63,6 +63,11 @@ public class EventTypes {
     public static final String EVENT_FIREWALL_OPEN = "FIREWALL.OPEN";
     public static final String EVENT_FIREWALL_CLOSE = "FIREWALL.CLOSE";
 
+    //NIC Events
+    public static final String EVENT_NIC_CREATE = "NIC.CREATE";
+    public static final String EVENT_NIC_DELETE = "NIC.DELETE";
+    public static final String EVENT_NIC_UPDATE = "NIC.UPDATE";
+
     // Load Balancers
     public static final String EVENT_ASSIGN_TO_LOAD_BALANCER_RULE = "LB.ASSIGN.TO.RULE";
     public static final String EVENT_REMOVE_FROM_LOAD_BALANCER_RULE = "LB.REMOVE.FROM.RULE";

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/api/src/com/cloud/vm/UserVmService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java
index b1ebe10..e211692 100755
--- a/api/src/com/cloud/vm/UserVmService.java
+++ b/api/src/com/cloud/vm/UserVmService.java
@@ -113,6 +113,27 @@ public interface UserVmService {
 
     UserVm updateVirtualMachine(UpdateVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException;
 
+    /**
+     * Adds a NIC on the given network to the virtual machine
+     * @param cmd the command object that defines the vm and the given network
+     * @return the vm object if successful, null otherwise
+     */
+    UserVm addNicToVirtualMachine(AddNicToVMCmd cmd);
+    
+    /**
+     * Removes a NIC on the given network from the virtual machine
+     * @param cmd the command object that defines the vm and the given network
+     * @return the vm object if successful, null otherwise
+     */
+    UserVm removeNicFromVirtualMachine(RemoveNicFromVMCmd cmd);
+    
+    /**
+     * Updates default Nic to the given network for given virtual machine
+     * @param cmd the command object that defines the vm and the given network
+     * @return the vm object if successful, null otherwise
+     */
+    UserVm updateDefaultNicForVirtualMachine(UpdateDefaultNicForVMCmd cmd);
+
     UserVm recoverVirtualMachine(RecoverVMCmd cmd) throws ResourceAllocationException;
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/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 d084271..d242830 100755
--- 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/15906c03/api/src/org/apache/cloudstack/api/command/user/vm/AddNicToVMCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/AddNicToVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/AddNicToVMCmd.java
new file mode 100644
index 0000000..4334000
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/user/vm/AddNicToVMCmd.java
@@ -0,0 +1,121 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.user.vm;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+
+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 com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.user.Account;
+import com.cloud.user.UserContext;
+import com.cloud.uservm.UserVm;
+
+@APICommand(name = "addNicToVirtualMachine", description="Adds VM to specified network by creating a NIC", responseObject=UserVmResponse.class)
+
+public class AddNicToVMCmd extends BaseAsyncCmd {
+    public static final Logger s_logger = Logger.getLogger(AddNicToVMCmd.class);
+    private static final String s_name = "addnictovirtualmachineresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.UUID, entityType=UserVmResponse.class,
+            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.IP_ADDRESS, type=CommandType.STRING, description="IP Address for the new network")
+    private String ipaddr;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getVmId() {
+        return vmId;
+    }
+    
+    public Long getNetworkId() {
+        return netId;
+    }
+
+    public String getIpAddress() {
+        return ipaddr;
+    }
+    
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+    
+    public static String getResultObjectName() {
+        return "virtualmachine";
+    }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_NIC_CREATE;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return  "Adding network " + getNetworkId() + " to user vm: " + getVmId();
+    }
+    
+    @Override
+    public long getEntityOwnerId() {
+        UserVm vm = _responseGenerator.findUserVmById(getVmId());
+        if (vm == null) {
+             return Account.ACCOUNT_ID_SYSTEM; // bad id given, parent this command to SYSTEM so ERROR events are tracked
+        }
+        return vm.getAccountId();
+    }
+
+    @Override
+    public void execute(){
+        UserContext.current().setEventDetails("Vm Id: " + getVmId() + " Network Id: " + getNetworkId());
+        UserVm result = _userVmService.addNicToVirtualMachine(this);
+        ArrayList<VMDetails> dc = new ArrayList<VMDetails>();
+        dc.add(VMDetails.valueOf("nics"));
+        EnumSet<VMDetails> details = EnumSet.copyOf(dc);
+        if (result != null){
+            UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", details, result).get(0);
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);
+        } else {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add NIC to vm. Refer to server logs for details.");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/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
new file mode 100644
index 0000000..b1a870e
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/user/vm/RemoveNicFromVMCmd.java
@@ -0,0 +1,115 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.user.vm;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+
+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.NicResponse;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.user.Account;
+import com.cloud.user.UserContext;
+import com.cloud.uservm.UserVm;
+
+@APICommand(name = "removeNicFromVirtualMachine", description="Removes VM from specified network by deleting a NIC", responseObject=UserVmResponse.class)
+
+public class RemoveNicFromVMCmd extends BaseAsyncCmd {
+    public static final Logger s_logger = Logger.getLogger(RemoveNicFromVMCmd.class);
+    private static final String s_name = "removenicfromvirtualmachineresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.UUID, entityType=UserVmResponse.class,
+            required=true, description="Virtual Machine ID")
+    private Long vmId;
+
+    @Parameter(name=ApiConstants.NIC_ID, type=CommandType.UUID, entityType=NicResponse.class,
+            required=true, description="NIC ID")
+    private Long nicId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getVmId() {
+        return vmId;
+    }
+    
+    public Long getNicId() {
+        return nicId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+    
+    public static String getResultObjectName() {
+        return "virtualmachine";
+    }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_NIC_DELETE;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return  "Removing NIC " + getNicId() + " from user vm: " + getVmId();
+    }
+    
+    
+    @Override
+    public long getEntityOwnerId() {
+        UserVm vm = _responseGenerator.findUserVmById(getVmId());
+        if (vm == null) {
+             return Account.ACCOUNT_ID_SYSTEM; // bad id given, parent this command to SYSTEM so ERROR events are tracked
+        }
+        return vm.getAccountId();
+    }
+
+    @Override
+    public void execute(){
+        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"));
+        EnumSet<VMDetails> details = EnumSet.copyOf(dc);
+        if (result != null){
+            UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", details, result).get(0);
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);
+        } else {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to remove NIC from vm, see error log for details");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/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
new file mode 100644
index 0000000..07518c9
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateDefaultNicForVMCmd.java
@@ -0,0 +1,115 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.user.vm;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+
+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.NicResponse;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.user.Account;
+import com.cloud.user.UserContext;
+import com.cloud.uservm.UserVm;
+
+@APICommand(name = "updateDefaultNicForVirtualMachine", description="Changes the default NIC on a VM", responseObject=UserVmResponse.class)
+
+public class UpdateDefaultNicForVMCmd extends BaseAsyncCmd {
+    public static final Logger s_logger = Logger.getLogger(UpdateDefaultNicForVMCmd.class);
+    private static final String s_name = "updatedefaultnicforvirtualmachineresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.UUID, entityType=UserVmResponse.class,
+            required=true, description="Virtual Machine ID")
+    private Long vmId;
+
+    @Parameter(name=ApiConstants.NIC_ID, type=CommandType.UUID, entityType=NicResponse.class,
+            required=true, description="NIC ID")
+    private Long nicId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getVmId() {
+        return vmId;
+    }
+
+    public Long getNicId() {
+        return nicId;
+    }
+    
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+    
+    public static String getResultObjectName() {
+        return "virtualmachine";
+    }
+    
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_NIC_UPDATE;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return  "Updating NIC " + getNicId() + " on user vm: " + getVmId();
+    }
+    
+    
+    @Override
+    public long getEntityOwnerId() {
+        UserVm vm = _responseGenerator.findUserVmById(getVmId());
+        if (vm == null) {
+             return Account.ACCOUNT_ID_SYSTEM; // bad id given, parent this command to SYSTEM so ERROR events are tracked
+        }
+        return vm.getAccountId();
+    }
+
+    @Override
+    public void execute(){
+        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"));
+        EnumSet<VMDetails> details = EnumSet.copyOf(dc);
+        if (result != null){
+            UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", details, result).get(0);
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);                                                                                                                                                                                                                                                                              
+        } else {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to set default nic for VM. Refer to server logs for details.");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/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/15906c03/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index 3740fb0..8face84 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -320,6 +320,11 @@ listNetworks=15
 restartNetwork=15
 updateNetwork=15
 
+#### nic commands ####
+addNicToVirtualMachine=15
+removeNicFromVirtualMachine=15
+updateDefaultNicForVirtualMachine=15
+
 #### SSH key pair commands
 registerSSHKeyPair=15
 createSSHKeyPair=15

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/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 546f1bf..c0065dd 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, VirtualMachineProfileImpl<VMInstanceVO> vmProfile, boolean prepare) throws InsufficientVirtualNetworkCapcityException,
+    NicProfile createNicForVm(Network network, NicProfile requested, ReservationContext context, VirtualMachineProfile<? extends VMInstanceVO> vmProfile, boolean prepare) throws InsufficientVirtualNetworkCapcityException,
             InsufficientAddressCapacityException, ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException;
 
 

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/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 bb60dcf..2dd6818 100755
--- a/server/src/com/cloud/network/NetworkManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkManagerImpl.java
@@ -3355,20 +3355,19 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener {
     }
     
     @Override
-    public NicProfile createNicForVm(Network network, NicProfile requested, ReservationContext context, VirtualMachineProfileImpl<VMInstanceVO> vmProfile, boolean prepare)
+    public NicProfile createNicForVm(Network network, NicProfile requested, ReservationContext context, VirtualMachineProfile<? extends VMInstanceVO> vmProfile, boolean prepare)
             throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException,
             ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
                 
                 VirtualMachine vm = vmProfile.getVirtualMachine();
-                NetworkVO networkVO = _networksDao.findById(network.getId());
                 DataCenter dc = _configMgr.getZone(network.getDataCenterId());
                 Host host = _hostDao.findById(vm.getHostId()); 
                 DeployDestination dest = new DeployDestination(dc, null, null, host);
                 
                 NicProfile nic = getNicProfileForVm(network, requested, vm);
                 
-                //1) allocate nic (if needed)
-                if (nic == null) {
+                //1) allocate nic (if needed) Always allocate if it is a user vm
+                if (nic == null || (vmProfile.getType() == VirtualMachine.Type.User)) {
                     int deviceId = _nicDao.countNics(vm.getId());
                     
                     nic = allocateNic(requested, network, false, 
@@ -3383,6 +3382,7 @@ public class NetworkManagerImpl implements NetworkManager, Manager, Listener {
                 
                 //2) prepare nic
                 if (prepare) {
+                    NetworkVO networkVO = _networksDao.findById(network.getId());
                     nic = prepareNic(vmProfile, dest, context, nic.getId(), networkVO);
                     s_logger.debug("Nic is prepared successfully for vm " + vm + " in network " + network);
                 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/server/src/com/cloud/network/NetworkModelImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java
index a99e9c5..ce53d6b 100644
--- a/server/src/com/cloud/network/NetworkModelImpl.java
+++ b/server/src/com/cloud/network/NetworkModelImpl.java
@@ -1692,6 +1692,9 @@ public class NetworkModelImpl  implements NetworkModel, Manager{
         } else {
            nic =  _nicDao.findByInstanceIdAndNetworkId(networkId, vm.getId());
         }
+        if (nic == null) {
+           return null;
+        }
         NetworkVO network = _networksDao.findById(networkId);
         Integer networkRate = getNetworkRate(network.getId(), vm.getId());
     
@@ -1836,4 +1839,4 @@ public class NetworkModelImpl  implements NetworkModel, Manager{
         return offering.isInline();
     }
 
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/server/src/com/cloud/network/element/VirtualRouterElement.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java
index 2b54ae0..cc64c15 100755
--- a/server/src/com/cloud/network/element/VirtualRouterElement.java
+++ b/server/src/com/cloud/network/element/VirtualRouterElement.java
@@ -860,8 +860,8 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl
 
         // for Basic zone, add all Running routers - we have to send Dhcp/vmData/password info to them when
         // network.dns.basiczone.updates is set to "all"
-        Long podId = dest.getPod().getId();
         if (isPodBased && _routerMgr.getDnsBasicZoneUpdate().equalsIgnoreCase("all")) {
+            Long podId = dest.getPod().getId();
             List<DomainRouterVO> allRunningRoutersOutsideThePod = _routerDao.findByNetworkOutsideThePod(network.getId(),
                     podId, State.Running, Role.VIRTUAL_ROUTER);
             routers.addAll(allRunningRoutersOutsideThePod);

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/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 ecf1242..82a8e25 100644
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -17,11 +17,16 @@
 package com.cloud.vm;
 
 import com.cloud.agent.AgentManager;
+import com.cloud.agent.AgentManager.OnError;
 import com.cloud.agent.api.*;
 import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
 import com.cloud.agent.api.to.NicTO;
 import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.agent.api.PlugNicAnswer;
+import com.cloud.agent.api.PlugNicCommand;
+import com.cloud.agent.api.UnPlugNicAnswer;
+import com.cloud.agent.api.UnPlugNicCommand;
 import com.cloud.agent.manager.Commands;
 import com.cloud.alert.AlertManager;
 import com.cloud.api.ApiDBUtils;
@@ -916,6 +921,237 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
         return _vmDao.findById(vmInstance.getId());
     }
 
+    @Override
+    public UserVm addNicToVirtualMachine(AddNicToVMCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, CloudRuntimeException {
+        Long vmId = cmd.getVmId();
+        Long networkId = cmd.getNetworkId();
+        String ipAddress = cmd.getIpAddress();
+        Account caller = UserContext.current().getCaller();
+
+        UserVmVO vmInstance = _vmDao.findById(vmId);
+        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);
+
+        // Verify that zone is not Basic
+        DataCenterVO dc = _dcDao.findById(vmInstance.getDataCenterIdToDeployIn());
+        if (dc.getNetworkType() == DataCenter.NetworkType.Basic) {
+            throw new CloudRuntimeException("Zone " + vmInstance.getDataCenterIdToDeployIn() + ", has a NetworkType of Basic. Can't add a new NIC to a VM on a Basic Network");
+        }
+
+        // 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() ) && caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
+                throw new PermissionDeniedException("Unable to modify a vm using network with id " + network.getId() + ", permission denied");
+            }
+        }
+        
+        //ensure network belongs in zone
+        if (network.getDataCenterId() != vmInstance.getDataCenterIdToDeployIn()) {
+            throw new CloudRuntimeException(vmInstance + " is in zone:" + vmInstance.getDataCenterIdToDeployIn() + " but " + network + " is in zone:" + network.getDataCenterId());
+        }
+
+        if(_networkModel.getNicInNetwork(vmInstance.getId(),network.getId()) != null){
+            s_logger.debug(vmInstance + " already in " + network + " going to add another NIC");
+        } else {
+            //* get all vms hostNames in the network
+            List<String> hostNames = _vmInstanceDao.listDistinctHostNames(network.getId());
+            //* verify that there are no duplicates
+            if (hostNames.contains(vmInstance.getHostName())) {
+                throw new CloudRuntimeException(network + " already has a vm with host name: '" + vmInstance.getHostName());
+            }
+        }
+        
+        NicProfile guestNic = null;
+
+        try {
+            guestNic = _itMgr.addVmToNetwork(vmInstance, network, profile);
+        } catch (ResourceUnavailableException e) {
+            throw new CloudRuntimeException("Unable to add NIC to " + vmInstance + ": " + e);
+        } catch (InsufficientCapacityException e) {
+            throw new CloudRuntimeException("Insufficient capacity when adding NIC to " + vmInstance + ": " + e);
+        } catch (ConcurrentOperationException e) {
+            throw new CloudRuntimeException("Concurrent operations on adding NIC to " + vmInstance + ": " +e);
+        }
+        if (guestNic == null) {
+            throw new CloudRuntimeException("Unable to add NIC to " + vmInstance);
+        }
+
+        s_logger.debug("Successful addition of " + network + " from " + vmInstance);
+        return _vmDao.findById(vmInstance.getId());
+    }
+
+    @Override
+    public UserVm removeNicFromVirtualMachine(RemoveNicFromVMCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, CloudRuntimeException {
+        Long vmId = cmd.getVmId();
+        Long nicId = cmd.getNicId();
+        Account caller = UserContext.current().getCaller();
+
+        UserVmVO vmInstance = _vmDao.findById(vmId);
+        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 " + nic.getNetworkId());
+        }
+
+        // Perform permission check on VM
+        _accountMgr.checkAccess(caller, null, true, vmInstance);
+
+        // Verify that zone is not Basic
+        DataCenterVO dc = _dcDao.findById(vmInstance.getDataCenterIdToDeployIn());
+        if (dc.getNetworkType() == DataCenter.NetworkType.Basic) {
+            throw new CloudRuntimeException("Zone " + vmInstance.getDataCenterIdToDeployIn() + ", has a NetworkType of Basic. Can't remove a NIC from a VM on a Basic Network");
+        }
+
+        //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() ) && caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
+                throw new PermissionDeniedException("Unable to modify a vm using network with id " + network.getId() + ", permission denied");
+            }
+        }
+        
+        boolean nicremoved = false;
+
+        try {
+            nicremoved = _itMgr.removeNicFromVm(vmInstance, nic);
+        } catch (ResourceUnavailableException e) {
+            throw new CloudRuntimeException("Unable to remove " + network + " from " + vmInstance +": " + e);
+            
+        } catch (ConcurrentOperationException e) {
+            throw new CloudRuntimeException("Concurrent operations on removing " + network + " from " + vmInstance + ": " + e);
+        }
+
+        if (!nicremoved) {
+            throw new CloudRuntimeException("Unable to remove " + network +  " from " + vmInstance );
+        }
+            
+        s_logger.debug("Successful removal of " + network + " from " + vmInstance);
+        return _vmDao.findById(vmInstance.getId());
+
+        
+    }
+    
+    @Override
+    public UserVm updateDefaultNicForVirtualMachine(UpdateDefaultNicForVMCmd cmd) throws InvalidParameterValueException, CloudRuntimeException {
+        Long vmId = cmd.getVmId();
+        Long nicId = cmd.getNicId();
+        Account caller = UserContext.current().getCaller();
+        
+        UserVmVO vmInstance = _vmDao.findById(vmId);
+        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 " + nic.getNetworkId());
+        }
+        
+        // Perform permission check on VM
+        _accountMgr.checkAccess(caller, null, true, vmInstance);
+
+        // Verify that zone is not Basic
+        DataCenterVO dc = _dcDao.findById(vmInstance.getDataCenterIdToDeployIn());
+        if (dc.getNetworkType() == DataCenter.NetworkType.Basic) {
+            throw new CloudRuntimeException("Zone " + vmInstance.getDataCenterIdToDeployIn() + ", has a NetworkType of Basic. Can't change default NIC on a Basic Network");
+        }
+
+        // no need to check permissions for network, we'll enumerate the ones they already have access to
+        Network existingdefaultnet = _networkModel.getDefaultNetworkForVm(vmId);
+        
+        //check to see if nic is attached to VM
+        if (nic.getInstanceId() != vmId) {
+            throw new InvalidParameterValueException(nic + " is not a nic on  " + vmInstance);
+        }
+        // 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");
+        }
+
+        //make sure the VM is Running or Stopped
+        if ((vmInstance.getState() != State.Running) && (vmInstance.getState() != State.Stopped)) {
+            throw new CloudRuntimeException("refusing to set default " + vmInstance + " is not Running or Stopped");
+        }
+        
+        NicProfile existing = null;
+        List<NicProfile> nicProfiles = _networkMgr.getNicProfiles(vmInstance);
+        for (NicProfile nicProfile : nicProfiles) {
+            if(nicProfile.isDefaultNic() && nicProfile.getNetworkId() == existingdefaultnet.getId()){
+                existing = nicProfile;
+                continue;
+            }
+        }
+
+        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 existingVO = _nicDao.findById(existing.id);
+        Integer chosenID = nic.getDeviceId();
+        Integer existingID = existing.getDeviceId();
+
+        nic.setDefaultNic(true);
+        nic.setDeviceId(existingID);
+        existingVO.setDefaultNic(false);
+        existingVO.setDeviceId(chosenID);
+
+        nic = _nicDao.persist(nic);
+        existingVO = _nicDao.persist(existingVO);
+
+        Network newdefault = null;
+        newdefault = _networkModel.getDefaultNetworkForVm(vmId);
+        
+        if (newdefault == null){
+             nic.setDefaultNic(false);
+             nic.setDeviceId(chosenID);
+             existingVO.setDefaultNic(true);
+             existingVO.setDeviceId(existingID);
+
+             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 " + 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 network(" + newdefault.getId() + ") is not null, and is not equal to the network(" + nic.getNetworkId() + ") of the chosen nic");
+    }
 
     @Override
     public HashMap<Long, VmStatsEntry> getVirtualMachineStatistics(long hostId, String hostName, List<Long> vmIds) throws CloudRuntimeException {
@@ -3671,16 +3907,58 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
     public boolean plugNic(Network network, NicTO nic, VirtualMachineTO vm,
             ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, ResourceUnavailableException,
             InsufficientCapacityException {
-        //not supported
-        throw new UnsupportedOperationException("Plug nic is not supported for vm of type " + vm.getType());
+        UserVmVO vmVO = _vmDao.findById(vm.getId());
+        if (vmVO.getState() == State.Running) {
+            try {
+                PlugNicCommand plugNicCmd = new PlugNicCommand(nic,vm.getName());
+                Commands cmds = new Commands(OnError.Stop);
+                cmds.addCommand("plugnic",plugNicCmd);
+                _agentMgr.send(dest.getHost().getId(),cmds);
+                PlugNicAnswer plugNicAnswer = cmds.getAnswer(PlugNicAnswer.class);
+                if (!(plugNicAnswer != null && plugNicAnswer.getResult())) {
+                    s_logger.warn("Unable to plug nic for " + vmVO);
+                    return false;
+                }
+            } catch (OperationTimedoutException e) {
+                throw new AgentUnavailableException("Unable to plug nic for " + vmVO + " in network " + network, dest.getHost().getId(), e);
+            }
+        } else if (vmVO.getState() == State.Stopped || vmVO.getState() == State.Stopping) {
+            s_logger.warn(vmVO + " is Stopped, not sending PlugNicCommand.  Currently " + vmVO.getState());
+        } else {
+            s_logger.warn("Unable to plug nic, " + vmVO + " is not in the right state " + vmVO.getState());
+            throw new ResourceUnavailableException("Unable to plug nic on the backend," +
+                    vmVO + " is not in the right state", DataCenter.class, vmVO.getDataCenterIdToDeployIn());
+        }
+        return true;
     }
 
 
     @Override
     public boolean unplugNic(Network network, NicTO nic, VirtualMachineTO vm,
             ReservationContext context, DeployDestination dest) throws ConcurrentOperationException, ResourceUnavailableException {
-        //not supported
-        throw new UnsupportedOperationException("Unplug nic is not supported for vm of type " + vm.getType());
+        UserVmVO vmVO = _vmDao.findById(vm.getId());
+        if (vmVO.getState() == State.Running) {
+            try {
+                UnPlugNicCommand unplugNicCmd = new UnPlugNicCommand(nic,vm.getName());
+                Commands cmds = new Commands(OnError.Stop);
+                cmds.addCommand("unplugnic",unplugNicCmd);
+                _agentMgr.send(dest.getHost().getId(),cmds);
+                UnPlugNicAnswer unplugNicAnswer = cmds.getAnswer(UnPlugNicAnswer.class);
+                if (!(unplugNicAnswer != null && unplugNicAnswer.getResult())) {
+                    s_logger.warn("Unable to unplug nic for " + vmVO);
+                    return false;
+                }
+            } catch (OperationTimedoutException e) {
+                throw new AgentUnavailableException("Unable to unplug nic for " + vmVO + " in network " + network, dest.getHost().getId(), e);
+            }
+        } else if (vmVO.getState() == State.Stopped || vmVO.getState() == State.Stopping) {
+            s_logger.warn(vmVO + " is Stopped, not sending UnPlugNicCommand.  Currently " + vmVO.getState());
+        } else {
+            s_logger.warn("Unable to unplug nic, " + vmVO + " is not in the right state " + vmVO.getState());
+            throw new ResourceUnavailableException("Unable to unplug nic on the backend," +
+                    vmVO + " is not in the right state", DataCenter.class, vmVO.getDataCenterIdToDeployIn());
+        }
+        return true;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/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 4f04617..53bd442 100644
--- a/server/src/com/cloud/vm/VirtualMachineManager.java
+++ b/server/src/com/cloud/vm/VirtualMachineManager.java
@@ -154,6 +154,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/15906c03/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 e0647bb..19756ad 100755
--- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -2462,7 +2462,12 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
                                                     ResourceUnavailableException, InsufficientCapacityException {
         
         s_logger.debug("Adding vm " + vm + " to network " + network + "; requested nic profile " + requested);
-        VMInstanceVO vmVO = _vmDao.findById(vm.getId());
+        VMInstanceVO vmVO;
+        if (vm.getType() == VirtualMachine.Type.User) {
+            vmVO = _userVmDao.findById(vm.getId());
+        } else {
+            vmVO = _vmDao.findById(vm.getId());
+        }
         ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(User.UID_SYSTEM), 
                 _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM));
         
@@ -2506,7 +2511,6 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
         }
     }
 
-
     @Override
     public NicTO toNicTO(NicProfile nic, HypervisorType hypervisorType) {
         HypervisorGuru hvGuru = _hvGuruMgr.getGuru(hypervisorType);
@@ -2516,6 +2520,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), 
@@ -2538,21 +2597,38 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
         } else {
             nic = _networkModel.getNicInNetwork(vm.getId(), network.getId());
         }
+
+        if (nic == null){
+            s_logger.warn("Could not get a nic with " + network);
+            return false;
+        }
         
+        // 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
-        NicTO nicTO = toNicTO(nicProfile, vmProfile.getVirtualMachine().getHypervisorType());
-        s_logger.debug("Un-plugging 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;
+        if (vm.getState() == State.Running) {
+            NicTO nicTO = toNicTO(nicProfile, vmProfile.getVirtualMachine().getHypervisorType());
+            s_logger.debug("Un-plugging 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
@@ -2561,7 +2637,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
         
         //3) Remove the nic
         _networkMgr.removeNic(vmProfile, nic);
-        return result;
+        return true;
     }
    
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/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 ef5b9c9..c9446bb 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,
-            VirtualMachineProfileImpl<VMInstanceVO> vmProfile, boolean prepare)
+            VirtualMachineProfile<? extends VMInstanceVO> vmProfile, boolean prepare)
             throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException,
             ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
         // TODO Auto-generated method stub

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/server/test/com/cloud/vm/MockUserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vm/MockUserVmManagerImpl.java b/server/test/com/cloud/vm/MockUserVmManagerImpl.java
index 27508b1..f424e65 100644
--- a/server/test/com/cloud/vm/MockUserVmManagerImpl.java
+++ b/server/test/com/cloud/vm/MockUserVmManagerImpl.java
@@ -55,6 +55,8 @@ import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.exception.StorageUnavailableException;
 import com.cloud.exception.VirtualMachineMigrationException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.PermissionDeniedException;
 import com.cloud.host.Host;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.network.Network;
@@ -69,6 +71,7 @@ import com.cloud.uservm.UserVm;
 import com.cloud.utils.Pair;
 import com.cloud.utils.component.Manager;
 import com.cloud.utils.exception.ExecutionException;
+import com.cloud.utils.exception.CloudRuntimeException;
 
 @Local(value = { UserVmManager.class, UserVmService.class })
 public class MockUserVmManagerImpl implements UserVmManager, UserVmService, Manager {
@@ -277,6 +280,24 @@ public class MockUserVmManagerImpl implements UserVmManager, UserVmService, Mana
     }
 
     @Override
+    public UserVm addNicToVirtualMachine(AddNicToVMCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, CloudRuntimeException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+    
+    @Override
+    public UserVm removeNicFromVirtualMachine(RemoveNicFromVMCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, CloudRuntimeException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+    
+    @Override
+    public UserVm updateDefaultNicForVirtualMachine(UpdateDefaultNicForVMCmd cmd) throws InvalidParameterValueException, CloudRuntimeException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
     public UserVm recoverVirtualMachine(RecoverVMCmd cmd) throws ResourceAllocationException {
         // TODO Auto-generated method stub
         return null;

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/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 6723198..862bb25 100755
--- a/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java
+++ b/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java
@@ -274,6 +274,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/15906c03/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 b4e1794..a5a9938 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,
-            VirtualMachineProfileImpl<VMInstanceVO> vmProfile, boolean prepare)
+            VirtualMachineProfile<? extends VMInstanceVO> vmProfile, boolean prepare)
             throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException,
             ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
         // TODO Auto-generated method stub

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/test/integration/smoke/test_nic.py
----------------------------------------------------------------------
diff --git a/test/integration/smoke/test_nic.py b/test/integration/smoke/test_nic.py
new file mode 100644
index 0000000..6cf73ac
--- /dev/null
+++ b/test/integration/smoke/test_nic.py
@@ -0,0 +1,335 @@
+""" NIC tests for VM """
+import marvin
+from marvin.cloudstackTestCase import *
+from marvin.cloudstackAPI import *
+from marvin.remoteSSHClient import remoteSSHClient
+from marvin.integration.lib.utils import *
+from marvin.integration.lib.base import *
+from marvin.integration.lib.common import *
+from nose.plugins.attrib import attr
+
+import signal
+import sys
+import time
+
+class Services:
+    def __init__(self):
+        self.services = {
+            "disk_offering":{
+                "displaytext": "Small",
+                "name": "Small",
+                "disksize": 1
+            },
+            "account": {
+                "email": "test@test.com",
+                "firstname": "Test",
+                "lastname": "User",
+                "username": "test",
+                # Random characters are appended in create account to
+                # ensure unique username generated each time
+                "password": "password",
+            },
+            # Create a small virtual machine instance with disk offering
+            "small": {
+                "displayname": "testserver",
+                "username": "root", # VM creds for SSH
+                "password": "password",
+                "ssh_port": 22,
+                "hypervisor": 'XenServer',
+                "privateport": 22,
+                "publicport": 22,
+                "protocol": 'TCP',
+            },
+            "service_offerings": {
+                "tiny": {
+                    "name": "Tiny Instance",
+                    "displaytext": "Tiny Instance",
+                    "cpunumber": 1,
+                    "cpuspeed": 100, # in MHz
+                    "memory": 128, # In MBs
+                },
+            },
+            "network_offering": {
+                "name": 'Test Network offering',
+                "displaytext": 'Test Network offering',
+                "guestiptype": 'Isolated',
+                "supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding',
+                "traffictype": 'GUEST',
+                "availability": 'Optional',
+                "serviceProviderList" : {
+                    "Dhcp": 'VirtualRouter',
+                    "Dns": 'VirtualRouter',
+                    "SourceNat": 'VirtualRouter',
+                    "PortForwarding": 'VirtualRouter',
+                },
+            },
+            "network": {
+                "name": "Test Network",
+                "displaytext": "Test Network",
+                "acltype": "Account",
+            },
+            # ISO settings for Attach/Detach ISO tests
+            "iso": {
+                "displaytext": "Test ISO",
+                "name": "testISO",
+                "url": "http://iso.linuxquestions.org/download/504/1819/http/gd4.tuwien.ac.at/dsl-4.4.10.iso",
+                 # Source URL where ISO is located
+                "ostype": 'CentOS 5.3 (64-bit)',
+                "mode": 'HTTP_DOWNLOAD', # Downloading existing ISO 
+            },
+            "template": {
+                "displaytext": "Cent OS Template",
+                "name": "Cent OS Template",
+                "passwordenabled": True,
+            },
+            "diskdevice": '/dev/xvdd',
+            # Disk device where ISO is attached to instance
+            "mount_dir": "/mnt/tmp",
+            "sleep": 60,
+            "timeout": 10,
+            #Migrate VM to hostid
+            "ostype": 'CentOS 5.3 (64-bit)',
+            # CentOS 5.3 (64-bit)
+        }
+
+class TestDeployVM(cloudstackTestCase):
+
+    def setUp(self):
+        self.cleanup = []
+        self.cleaning_up = 0
+
+        def signal_handler(signal, frame):
+            self.tearDown()
+            sys.exit(0)
+
+        # assign the signal handler immediately
+        signal.signal(signal.SIGINT, signal_handler)
+
+        try:
+            self.apiclient = self.testClient.getApiClient()
+            self.dbclient  = self.testClient.getDbConnection()
+            self.services  = Services().services
+
+            # Get Zone, Domain and templates
+            domain = get_domain(self.apiclient, self.services)
+            zone = get_zone(self.apiclient, self.services)
+            self.services['mode'] = zone.networktype
+
+            if self.services['mode'] != 'Advanced':
+                self.debug("Cannot run this test with a basic zone, please use advanced!")
+                return
+
+            #if local storage is enabled, alter the offerings to use localstorage
+            #this step is needed for devcloud
+            if zone.localstorageenabled == True:
+                self.services["service_offerings"]["tiny"]["storagetype"] = 'local'
+
+            template = get_template(
+                                self.apiclient,
+                                zone.id,
+                                self.services["ostype"]
+                                )
+            # Set Zones and disk offerings
+            self.services["small"]["zoneid"] = zone.id
+            self.services["small"]["template"] = template.id
+
+            self.services["iso"]["zoneid"] = zone.id
+            self.services["network"]["zoneid"] = zone.id
+
+            # Create Account, VMs, NAT Rules etc
+            self.account = Account.create(
+                                self.apiclient,
+                                self.services["account"],
+                                domainid=domain.id
+                                )
+            self.cleanup.insert(0, self.account)
+
+            self.service_offering = ServiceOffering.create(
+                                        self.apiclient,
+                                        self.services["service_offerings"]["tiny"]
+                                        )
+            self.cleanup.insert(0, self.service_offering)
+
+            ####################
+            ### Network offering
+            self.network_offering = NetworkOffering.create(
+                                        self.apiclient,
+                                        self.services["network_offering"],
+                                        )
+            self.cleanup.insert(0, self.network_offering)
+            self.network_offering.update(self.apiclient, state='Enabled') # Enable Network offering
+            self.services["network"]["networkoffering"] = self.network_offering.id
+
+            ################
+            ### Test Network
+            self.test_network = Network.create(
+                                                 self.apiclient,
+                                                 self.services["network"],
+                                                 self.account.account.name,
+                                                 self.account.account.domainid,
+                                                 )
+            self.cleanup.insert(0, self.test_network)
+        except Exception as ex:
+            self.debug("Exception during NIC test SETUP!: " + str(ex))
+            self.assertEqual(True, False, "Exception during NIC test SETUP!: " + str(ex))
+
+    @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"])
+    def test_01_nic(self):
+        if self.services['mode'] != 'Advanced':
+            self.debug("Cannot run this test with a basic zone, please use advanced!")
+            return
+        try:
+            self.virtual_machine = VirtualMachine.create(
+                                        self.apiclient,
+                                        self.services["small"],
+                                        accountid=self.account.account.name,
+                                        domainid=self.account.account.domainid,
+                                        serviceofferingid=self.service_offering.id,
+                                        mode=self.services['mode']
+                                    )
+            self.cleanup.insert(0, self.virtual_machine)
+
+            list_vm_response = list_virtual_machines(
+                                                     self.apiclient,
+                                                     id=self.virtual_machine.id
+                                                     )
+
+            self.debug(
+                    "Verify listVirtualMachines response for virtual machine: %s" \
+                    % self.virtual_machine.id
+                )
+
+            self.assertEqual(
+                                isinstance(list_vm_response, list),
+                                True,
+                                "Check list response returns a valid list"
+                            )
+
+            self.assertNotEqual(
+                                len(list_vm_response),
+                                0,
+                                "Check VM available in List Virtual Machines"
+                            )
+            vm_response = list_vm_response[0]
+
+            self.assertEqual(
+
+                                vm_response.id,
+                                self.virtual_machine.id,
+                                "Check virtual machine id in listVirtualMachines"
+                            )
+
+            self.assertEqual(
+                        vm_response.name,
+                        self.virtual_machine.name,
+                        "Check virtual machine name in listVirtualMachines"
+                        )
+
+            self.assertEqual(
+                        len(vm_response.nic),
+                        1,
+                        "Verify we only start with one nic"
+                        )
+
+            self.assertEqual(
+                vm_response.nic[0].isdefault,
+                True,
+                "Verify initial adapter is set to default"
+            )
+            existing_nic_ip = vm_response.nic[0].ipaddress
+            existing_nic_id = vm_response.nic[0].id
+
+            # 1. add a nic
+            add_response = self.virtual_machine.add_nic(self.apiclient, self.test_network.id)
+
+            time.sleep(5)
+            # now go get the vm list?
+
+            list_vm_response = list_virtual_machines(
+                                                self.apiclient,
+                                                id=self.virtual_machine.id
+                                                )
+
+            self.assertEqual(
+                        len(list_vm_response[0].nic),
+                        2,
+                        "Verify we have 2 NIC's now"
+                        )
+
+            new_nic_id = ""
+            for nc in list_vm_response[0].nic:
+                if nc.ipaddress != existing_nic_ip:
+                    new_nic_id = nc.id
+
+            self.virtual_machine.update_default_nic(self.apiclient, new_nic_id)
+
+            time.sleep(5)
+
+            list_vm_response = list_virtual_machines(
+                                                self.apiclient,
+                                                id=self.virtual_machine.id
+                                                )
+
+            # iterate as we don't know for sure what order our NIC's will be returned to us.
+            for nc in list_vm_response[0].nic:
+                if nc.ipaddress == existing_nic_ip:
+                    self.assertEqual(
+                        nc.isdefault,
+                        False,
+                        "Verify initial adapter is NOT set to default"
+                    )
+                else:
+                    self.assertEqual(
+                        nc.isdefault,
+                        True,
+                        "Verify second adapter is set to default"
+                    )
+
+            sawException = False
+            try:
+                self.virtual_machine.remove_nic(self.apiclient, new_nic_id)
+            except Exception as ex:
+                sawException = True
+
+            self.assertEqual(sawException, True, "Make sure we cannot delete the default NIC")
+
+            self.virtual_machine.remove_nic(self.apiclient, existing_nic_id)
+            time.sleep(5)
+
+            list_vm_response = list_virtual_machines(
+                                                self.apiclient,
+                                                id=self.virtual_machine.id
+                                                )
+
+            self.assertEqual(
+                        len(list_vm_response[0].nic),
+                        1,
+                        "Verify we are back to a signle NIC"
+                        )
+
+            return
+        except Exception as ex:
+            self.debug("Exception during NIC test!: " + str(ex))
+            self.assertEqual(True, False, "Exception during NIC test!: " + str(ex))
+
+    def tearDown(self):
+        if self.services['mode'] != 'Advanced':
+            self.debug("Cannot run this test with a basic zone, please use advanced!")
+            return
+
+        if self.cleaning_up == 1:
+            return
+
+        self.cleaning_up = 1
+        try:
+            for obj in self.cleanup:
+                try:
+                    obj.delete(self.apiclient)
+                    time.sleep(10)
+                except Exception as ex:
+                    self.debug("Error deleting: " + str(obj) + ", exception: " + str(ex))
+
+        except Exception as e:
+            self.debug("Warning! Exception in tearDown: %s" % e)
+        self.cleaning_up = 0
+

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/15906c03/tools/marvin/marvin/integration/lib/base.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py
index 87b0bbb..830914c 100644
--- a/tools/marvin/marvin/integration/lib/base.py
+++ b/tools/marvin/marvin/integration/lib/base.py
@@ -389,6 +389,27 @@ class VirtualMachine:
         cmd.id = volume.id
         return apiclient.detachVolume(cmd)
 
+    def add_nic(self, apiclient, networkId):
+        """Add a NIC to a VM"""
+        cmd = addNicToVirtualMachine.addNicToVirtualMachineCmd();
+        cmd.virtualmachineid = self.id
+        cmd.networkid = networkId
+        return apiclient.addNicToVirtualMachine(cmd)
+
+    def remove_nic(self, apiclient, nicId):
+        """Remove a NIC to a VM"""
+        cmd = removeNicFromVirtualMachine.removeNicFromVirtualMachineCmd()
+        cmd.nicid = nicId
+        cmd.virtualmachineid = self.id
+        return apiclient.removeNicFromVirtualMachine(cmd)
+
+    def update_default_nic(self, apiclient, nicId):
+        """Set a NIC to be the default network adapter for a VM"""
+        cmd = updateDefaultNicForVirtualMachine.updateDefaultNicForVirtualMachineCmd()
+        cmd.nicid = nicId
+        cmd.virtualmachineid = self.id
+        return apiclient.updateDefaultNicForVirtualMachine(cmd)
+
     @classmethod
     def list(cls, apiclient, **kwargs):
         """List all VMs matching criteria"""