From 58772934344d2b0316ddb479a977b15b6e97c015 Mon Sep 17 00:00:00 2001 From: Loic Lambiel Date: Fri, 15 May 2015 15:15:26 +0200 Subject: [PATCH] CLOUDSTACK-9203 security group update on running instance cherry-picked from a exoscale internal fix: Implement security group move on updateVM API call Prevent security group update while instance is running Conflicts: api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java server/src/com/cloud/vm/UserVmManager.java server/src/com/cloud/vm/UserVmManagerImpl.java --- .../api/command/user/vm/UpdateVMCmd.java | 16 ++++++- server/src/com/cloud/vm/UserVmManager.java | 2 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 46 +++++++++++++++++-- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java index 458122d6d7b..9a8bdc2aa39 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/UpdateVMCmd.java @@ -29,6 +29,7 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ResponseObject.ResponseView; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.GuestOSResponse; +import org.apache.cloudstack.api.response.SecurityGroupResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.context.CallContext; @@ -39,6 +40,7 @@ import com.cloud.uservm.UserVm; import com.cloud.vm.VirtualMachine; import java.util.Collection; +import java.util.List; import java.util.Map; @APICommand(name = "updateVirtualMachine", description="Updates properties of a virtual machine. The VM has to be stopped and restarted for the " + @@ -96,6 +98,14 @@ public class UpdateVMCmd extends BaseCustomIdCmd { @Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, description = "Details in key/value pairs.") protected Map details; + @ACL + @Parameter(name = ApiConstants.SECURITY_GROUP_IDS, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = SecurityGroupResponse.class, + description = "list of security group ids to be applied on the virtual machine.") + private List securityGroupIdList; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -145,7 +155,11 @@ public class UpdateVMCmd extends BaseCustomIdCmd { return (Map) (paramsCollection.toArray())[0]; } -///////////////////////////////////////////////////// + public List getSecurityGroupIdList() { + return securityGroupIdList; + } + + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/server/src/com/cloud/vm/UserVmManager.java b/server/src/com/cloud/vm/UserVmManager.java index fe0e98c8cd5..411fd9b669f 100644 --- a/server/src/com/cloud/vm/UserVmManager.java +++ b/server/src/com/cloud/vm/UserVmManager.java @@ -103,7 +103,7 @@ public interface UserVmManager extends UserVmService { void collectVmDiskStatistics(UserVmVO userVm); UserVm updateVirtualMachine(long id, String displayName, String group, Boolean ha, Boolean isDisplayVmEnabled, Long osTypeId, String userData, - Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName) throws ResourceUnavailableException, InsufficientCapacityException; + Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName, List securityGroupIdList) throws ResourceUnavailableException, InsufficientCapacityException; //the validateCustomParameters, save and remove CustomOfferingDetils functions can be removed from the interface once we can //find a common place for all the scaling and upgrading code of both user and systemvms. diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 83ee2489c61..a253fdd6f8d 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2289,6 +2289,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir String hostName = cmd.getHostName(); Map details = cmd.getDetails(); Account caller = CallContext.current().getCallingAccount(); + List securityGroupIdList = cmd.getSecurityGroupIdList(); // Input validation and permission checks UserVmVO vmInstance = _vmDao.findById(id); @@ -2339,7 +2340,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } return updateVirtualMachine(id, displayName, group, ha, isDisplayVm, osTypeId, userData, isDynamicallyScalable, - cmd.getHttpMethod(), cmd.getCustomId(), hostName, cmd.getInstanceName()); + cmd.getHttpMethod(), cmd.getCustomId(), hostName, cmd.getInstanceName(), securityGroupIdList); } private void saveUsageEvent(UserVmVO vm) { @@ -2389,10 +2390,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir @Override public UserVm updateVirtualMachine(long id, String displayName, String group, Boolean ha, Boolean isDisplayVmEnabled, Long osTypeId, String userData, - Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName) throws ResourceUnavailableException, InsufficientCapacityException { + Boolean isDynamicallyScalable, HTTPMethod httpMethod, String customId, String hostName, String instanceName, List securityGroupIdList) + throws ResourceUnavailableException, InsufficientCapacityException { UserVmVO vm = _vmDao.findById(id); if (vm == null) { - throw new CloudRuntimeException("Unable to find virual machine with id " + id); + throw new CloudRuntimeException("Unable to find virtual machine with id " + id); } if(instanceName != null){ @@ -2451,6 +2453,44 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir isDynamicallyScalable = vm.isDynamicallyScalable(); } + boolean isVMware = (vm.getHypervisorType() == HypervisorType.VMware); + + if (securityGroupIdList != null && isVMware) { + throw new InvalidParameterValueException("Security group feature is not supported for vmWare hypervisor"); + } else { + // Get default guest network in Basic zone + Network defaultNetwork = null; + try { + DataCenterVO zone = _dcDao.findById(vm.getDataCenterId()); + + if (zone.getNetworkType() == NetworkType.Basic) { + // Get default guest network in Basic zone + defaultNetwork = _networkModel.getExclusiveGuestNetwork(zone.getId()); + } else if (zone.isSecurityGroupEnabled()) { + NicVO defaultNic = _nicDao.findDefaultNicForVM(vm.getId()); + if (defaultNic != null) { + defaultNetwork = _networkDao.findById(defaultNic.getNetworkId()); + } + } + } catch (InvalidParameterValueException e) { + if(s_logger.isDebugEnabled()) { + s_logger.debug(e.getMessage(),e); + } + defaultNetwork = _networkModel.getDefaultNetworkForVm(id); + } + + if (securityGroupIdList != null && _networkModel.isSecurityGroupSupportedInNetwork(defaultNetwork) && _networkModel.canAddDefaultSecurityGroup()) { + if (vm.getState() == State.Stopped) { + // Remove instance from security groups + _securityGroupMgr.removeInstanceFromGroups(id); + // Add instance in provided groups + _securityGroupMgr.addInstanceToGroups(id, securityGroupIdList); + } else { + throw new InvalidParameterValueException("Virtual machine must be stopped prior to update security groups "); + } + } + } + if (hostName != null) { // Check is hostName is RFC compliant checkNameForRFCCompliance(hostName);