Updated Branches:
  refs/heads/add_remove_nics [created] c093d650c

Summary: Initial code commit, applying https://reviews.apache.org/r/9011/

Signed-off-by: Marcus Sorensen <[email protected]> 1358452852 -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/c093d650
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/c093d650
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/c093d650

Branch: refs/heads/add_remove_nics
Commit: c093d650c716e57a9e5f1aecd0b54d6e4b73e9be
Parents: e37a823
Author: Marcus Sorensen <[email protected]>
Authored: Thu Jan 17 13:00:52 2013 -0700
Committer: Marcus Sorensen <[email protected]>
Committed: Thu Jan 17 13:00:52 2013 -0700

----------------------------------------------------------------------
 api/src/com/cloud/vm/UserVmService.java            |   21 ++
 .../api/command/user/vm/AddNicToVMCmd.java         |  111 +++++++
 .../api/command/user/vm/RemoveNicFromVMCmd.java    |  104 +++++++
 .../command/user/vm/UpdateDefaultNicForVMCmd.java  |  104 +++++++
 client/tomcatconf/commands.properties.in           |    4 +
 .../src/com/cloud/network/NetworkManagerImpl.java  |    3 +
 server/src/com/cloud/vm/UserVmManagerImpl.java     |  226 +++++++++++++++
 server/src/com/cloud/vm/VirtualMachineManager.java |   12 +
 .../com/cloud/vm/VirtualMachineManagerImpl.java    |   57 +++-
 .../test/com/cloud/vm/MockUserVmManagerImpl.java   |   21 ++
 .../cloud/vm/MockVirtualMachineManagerImpl.java    |    9 +
 11 files changed, 663 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c093d650/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/c093d650/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..af73328
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/user/vm/AddNicToVMCmd.java
@@ -0,0 +1,111 @@
+// 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 BaseCmd {
+    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 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());
+        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/c093d650/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..aea953a
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/user/vm/RemoveNicFromVMCmd.java
@@ -0,0 +1,104 @@
+// 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 = "removeNicFromVirtualMachine", description="Removes VM from 
specified network by deleting a NIC", responseObject=UserVmResponse.class)
+
+public class RemoveNicFromVMCmd extends BaseCmd {
+    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.NETWORK_ID, type=CommandType.UUID, 
entityType=NetworkResponse.class,
+            required=true, description="Network ID")
+    private Long netId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getVmId() {
+        return vmId;
+    }
+    
+    public Long getNetworkId() {
+        return netId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+    
+    public static String getResultObjectName() {
+        return "virtualmachine";
+    }
+    
+    @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());
+        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/c093d650/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..19d3bdb
--- /dev/null
+++ 
b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateDefaultNicForVMCmd.java
@@ -0,0 +1,104 @@
+// 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 = "updateDefaultNicForVirtualMachine", description="Changes 
the default NIC on a VM", responseObject=UserVmResponse.class)
+
+public class UpdateDefaultNicForVMCmd extends BaseCmd {
+    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.NETWORK_ID, type=CommandType.UUID, 
entityType=NetworkResponse.class,
+            required=true, description="Network ID")
+    private Long netId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getVmId() {
+        return vmId;
+    }
+    
+    public Long getNetworkId() {
+        return netId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+    
+    public static String getResultObjectName() {
+        return "virtualmachine";
+    }
+    
+    @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());
+        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/c093d650/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in 
b/client/tomcatconf/commands.properties.in
index 182cbd8..91b99dd 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -257,6 +257,10 @@ extractVolume=15
 migrateVolume=15
 resizeVolume=15
 
+addNicToVirtualMachine=15
+removeNicFromVirtualMachine=15
+updateDefaultNicForVirtualMachine=15
+
 #### registration command:  FIXME -- this really should be something in 
management server that
 ####                                 generates a new key for the user and they 
just have to
 ####                                 use that key...the key is stored in the 
db associated w/

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c093d650/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 0a1fcd7..fbb019a 100755
--- a/server/src/com/cloud/network/NetworkManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkManagerImpl.java
@@ -2227,6 +2227,9 @@ public class NetworkManagerImpl implements 
NetworkManager, NetworkService, Manag
         } else {
            nic =  _nicDao.findByInstanceIdAndNetworkId(networkId, vm.getId());
         }
+        if (nic == null) {
+            return null;
+        }
         NetworkVO network = _networksDao.findById(networkId);
         Integer networkRate = getNetworkRate(network.getId(), vm.getId());
 

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c093d650/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 a6fbdb1..81008ee 100755
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -914,6 +914,232 @@ 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);
+        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);
+        }
+
+        if(network == null) {
+            throw new InvalidParameterValueException("unable to find a network 
with id " + networkId);
+        }
+
+        // Perform permission check on VM
+        _accountMgr.checkAccess(caller, null, true, 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");
+            }
+        }
+        
+        if (vmInstance.getState() != State.Stopped) {
+            s_logger.warn("VM is running, needs to be stopped in order to add 
nic");
+            throw new CloudRuntimeException(vmInstance + " currently in " + 
vmInstance.getState() + " state, operation can only execute when VM is 
Stopped");
+        }
+
+        //todo: any security group related checks
+        //todo: ensure network belongs in zone
+        //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(_networkMgr.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 {
+            guestNic = _itMgr.addUserVmToNetwork(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 networkId = cmd.getNetworkId();
+        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);
+        }
+
+        if(network == null) {
+            throw new InvalidParameterValueException("unable to find a network 
with id " + networkId);
+        }
+
+        // Perform permission check on VM
+        _accountMgr.checkAccess(caller, null, true, 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");
+            }
+        }
+        
+        if (vmInstance.getState() != State.Stopped) {
+            s_logger.warn("VM is running, needs to be stopped in order to 
remove nic");
+            throw new CloudRuntimeException(vmInstance + " currently in " + 
vmInstance.getState() + " state, operation can only execute when VM is 
Stopped");
+        }
+
+        //todo: any security group related checks
+        //todo: ensure network belongs in zone
+        //todo: check other nics for VPC networks (can only belong to one?)
+        //todo: verify unique hostname in network domain?
+        boolean nicremoved = false;
+
+        try {
+            nicremoved = _itMgr.removeVmFromNetwork(vmInstance, network, null);
+        } 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 networkId = cmd.getNetworkId();
+        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);
+        }
+
+        if (network == null){
+            throw new InvalidParameterValueException("unable to find a network 
with id " + networkId);
+        }
+        
+        // Perform permission check on VM
+        _accountMgr.checkAccess(caller, null, true, vmInstance);
+
+        if(vmInstance.getState() != State.Stopped){
+            s_logger.warn("VM is running, needs to be stopped in order to 
change default nic");
+            throw new CloudRuntimeException(vmInstance + " currently in " + 
vmInstance.getState() + " state, operation can only execute when VM is 
Stopped");
+        }
+
+        // no need to check permissions for network, we'll enumerate the ones 
they already have access to
+        Network existingdefaultnet = _networkMgr.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());
+        }
+        else {
+            s_logger.debug("looks like we want to change from " + 
existingdefaultnet + " to " + network);
+        }
+        
+        NicProfile chosen = _networkMgr.getNicProfile(vmInstance, 
network.getId(), null);
+        NicProfile existing = _networkMgr.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 existingID = existing.getDeviceId();
+
+        chosenVO.setDefaultNic(true);
+        chosenVO.setDeviceId(existingID);
+        existingVO.setDefaultNic(false);
+        existingVO.setDeviceId(chosenID);
+
+        chosenVO = _nicDao.persist(chosenVO);
+        existingVO = _nicDao.persist(existingVO);
+
+        Network newdefault = null;
+        newdefault = _networkMgr.getDefaultNetworkForVm(vmId);
+        
+        if (newdefault == null){
+             chosenVO.setDefaultNic(false);
+             chosenVO.setDeviceId(chosenID);
+             existingVO.setDefaultNic(true);
+             existingVO.setDeviceId(existingID);
+
+             chosenVO = _nicDao.persist(chosenVO);
+             existingVO = _nicDao.persist(existingVO);
+             
+             newdefault = _networkMgr.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 ) {
+            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");
+    }
 
     @Override
     public HashMap<Long, VmStatsEntry> getVirtualMachineStatistics(long 
hostId, String hostName, List<Long> vmIds) throws CloudRuntimeException {

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c093d650/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..aa7e166 100644
--- a/server/src/com/cloud/vm/VirtualMachineManager.java
+++ b/server/src/com/cloud/vm/VirtualMachineManager.java
@@ -155,6 +155,18 @@ public interface VirtualMachineManager extends Manager {
     /**
      * @param vm
      * @param network
+     * @param requested TODO
+     * @return
+     * @throws ConcurrentOperationException
+     * @throws ResourceUnavailableException
+     * @throws InsufficientCapacityException
+     */
+    NicProfile addUserVmToNetwork(VirtualMachine vm, Network network, 
NicProfile requested) throws ConcurrentOperationException,
+                ResourceUnavailableException, InsufficientCapacityException;
+
+    /**
+     * @param vm
+     * @param network
      * @param broadcastUri TODO
      * @return
      * @throws ResourceUnavailableException 

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c093d650/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 4d94fc5..c1a9b3a 100755
--- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -2503,6 +2503,27 @@ public class VirtualMachineManagerImpl implements 
VirtualMachineManager, Listene
         }
     }
 
+    @Override
+    public NicProfile addUserVmToNetwork(VirtualMachine vm, Network network, 
NicProfile requested) throws ConcurrentOperationException,
+                                                    
ResourceUnavailableException, InsufficientCapacityException {
+
+        s_logger.debug("Adding vm " + vm + " to network " + network + "; 
requested nic profile " + requested);
+        VMInstanceVO vmVO = _vmDao.findById(vm.getId());
+        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);
+
+        if (vm.getState() == State.Stopped) {
+            //1) allocate nic
+            return _networkMgr.createNicForVm(network, requested, context, 
vmProfile, 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",
+                    DataCenter.class, vm.getDataCenterIdToDeployIn());
+        }
+    }
 
     @Override
     public NicTO toNicTO(NicProfile nic, HypervisorType hypervisorType) {
@@ -2535,21 +2556,38 @@ public class VirtualMachineManagerImpl implements 
VirtualMachineManager, Listene
         } else {
             nic = _networkMgr.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(), 
                 _networkMgr.getNetworkRate(network.getId(), vm.getId()), 
                 _networkMgr.isSecurityGroupSupportedInNetwork(network), 
                 
_networkMgr.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
@@ -2558,7 +2596,8 @@ public class VirtualMachineManagerImpl implements 
VirtualMachineManager, Listene
         
         //3) Remove the nic
         _networkMgr.removeNic(vmProfile, nic);
-        return result;
+        _nicsDao.expunge(nic.getId());
+        return true;
     }
    
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/c093d650/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/c093d650/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..75d90aa 100755
--- a/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java
+++ b/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java
@@ -271,6 +271,15 @@ public class MockVirtualMachineManagerImpl implements 
VirtualMachineManager {
     }
 
     /* (non-Javadoc)
+     * @see 
com.cloud.vm.VirtualMachineManager#addVmToNetwork(com.cloud.vm.VirtualMachine, 
com.cloud.network.Network, com.cloud.vm.NicProfile)
+     */
+    @Override
+    public NicProfile addUserVmToNetwork(VirtualMachine vm, Network network, 
NicProfile requested) throws ConcurrentOperationException, 
ResourceUnavailableException, InsufficientCapacityException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    /* (non-Javadoc)
      * @see 
com.cloud.vm.VirtualMachineManager#removeVmFromNetwork(com.cloud.vm.VirtualMachine,
 com.cloud.network.Network, java.net.URI)
      */
     @Override

Reply via email to