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
