mirror of https://github.com/apache/cloudstack.git
Merge pull request #1297 from DaanHoogland/CLOUDSTACK-9203
CLOUDSTACK-9203 Implement security group move on updateVM API call cherry-picked from a exoscale internal fix 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 * pr/1297: CLOUDSTACK-9203 refactorred DeployVM code to be used by UpdateVM as well CLOUDSTACK-9203 security group update on running instance Signed-off-by: Will Stevens <williamstevens@gmail.com>
This commit is contained in:
commit
de205c5805
|
|
@ -16,25 +16,14 @@
|
|||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.vm;
|
||||
|
||||
import com.cloud.dc.DataCenter;
|
||||
import com.cloud.dc.DataCenter.NetworkType;
|
||||
import com.cloud.event.EventTypes;
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.InsufficientServerCapacityException;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.network.Network;
|
||||
import com.cloud.network.Network.IpAddresses;
|
||||
import com.cloud.offering.DiskOffering;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
import com.cloud.template.VirtualMachineTemplate;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.net.NetUtils;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
||||
import org.apache.cloudstack.api.ACL;
|
||||
|
|
@ -59,17 +48,23 @@ import org.apache.cloudstack.api.response.ZoneResponse;
|
|||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.cloud.event.EventTypes;
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.InsufficientServerCapacityException;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.network.Network;
|
||||
import com.cloud.network.Network.IpAddresses;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.net.NetUtils;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
|
||||
@APICommand(name = "deployVirtualMachine", description = "Creates and automatically starts a virtual machine based on a service offering, disk offering, and template.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class},
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true)
|
||||
public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd {
|
||||
public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityGroupAction {
|
||||
public static final Logger s_logger = Logger.getLogger(DeployVMCmd.class.getName());
|
||||
|
||||
private static final String s_name = "deployvirtualmachineresponse";
|
||||
|
|
@ -257,26 +252,12 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd {
|
|||
return displayVm;
|
||||
}
|
||||
|
||||
public List<Long> getSecurityGroupIdList() {
|
||||
if (securityGroupNameList != null && securityGroupIdList != null) {
|
||||
throw new InvalidParameterValueException("securitygroupids parameter is mutually exclusive with securitygroupnames parameter");
|
||||
}
|
||||
public List<String> getSecurityGroupNameList() {
|
||||
return securityGroupNameList;
|
||||
}
|
||||
|
||||
//transform group names to ids here
|
||||
if (securityGroupNameList != null) {
|
||||
List<Long> securityGroupIds = new ArrayList<Long>();
|
||||
for (String groupName : securityGroupNameList) {
|
||||
Long groupId = _responseGenerator.getSecurityGroupId(groupName, getEntityOwnerId());
|
||||
if (groupId == null) {
|
||||
throw new InvalidParameterValueException("Unable to find group by name " + groupName);
|
||||
} else {
|
||||
securityGroupIds.add(groupId);
|
||||
}
|
||||
}
|
||||
return securityGroupIds;
|
||||
} else {
|
||||
return securityGroupIdList;
|
||||
}
|
||||
public List<Long> getSecurityGroupIdList() {
|
||||
return securityGroupIdList;
|
||||
}
|
||||
|
||||
public Long getServiceOfferingId() {
|
||||
|
|
@ -328,7 +309,7 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd {
|
|||
return startVm == null ? true : startVm;
|
||||
}
|
||||
|
||||
private Map<Long, IpAddresses> getIpToNetworkMap() {
|
||||
public Map<Long, IpAddresses> getIpToNetworkMap() {
|
||||
if ((networkIds != null || ipAddress != null || getIp6Address() != null) && ipToNetworkList != null) {
|
||||
throw new InvalidParameterValueException("NetworkIds and ipAddress can't be specified along with ipToNetworkMap parameter");
|
||||
}
|
||||
|
|
@ -363,6 +344,10 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd {
|
|||
return ipToNetworkMap;
|
||||
}
|
||||
|
||||
public String getIpAddress() {
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
public String getIp6Address() {
|
||||
if (ip6Address == null) {
|
||||
return null;
|
||||
|
|
@ -392,6 +377,11 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd {
|
|||
}
|
||||
}
|
||||
|
||||
public String getKeyboard() {
|
||||
// TODO Auto-generated method stub
|
||||
return keyboard;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -478,137 +468,11 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd {
|
|||
}
|
||||
}
|
||||
|
||||
// this is an opportunity to verify that parameters that came in via the Details Map are OK
|
||||
// for example, minIops and maxIops should either both be specified or neither be specified and,
|
||||
// if specified, minIops should be <= maxIops
|
||||
private void verifyDetails() {
|
||||
Map<String, String> map = getDetails();
|
||||
|
||||
if (map != null) {
|
||||
String minIops = (String)map.get("minIops");
|
||||
String maxIops = (String)map.get("maxIops");
|
||||
|
||||
verifyMinAndMaxIops(minIops, maxIops);
|
||||
|
||||
minIops = (String)map.get("minIopsDo");
|
||||
maxIops = (String)map.get("maxIopsDo");
|
||||
|
||||
verifyMinAndMaxIops(minIops, maxIops);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyMinAndMaxIops(String minIops, String maxIops) {
|
||||
if ((minIops != null && maxIops == null) || (minIops == null && maxIops != null)) {
|
||||
throw new InvalidParameterValueException("Either 'Min IOPS' and 'Max IOPS' must both be specified or neither be specified.");
|
||||
}
|
||||
|
||||
long lMinIops;
|
||||
|
||||
try {
|
||||
if (minIops != null) {
|
||||
lMinIops = Long.parseLong(minIops);
|
||||
}
|
||||
else {
|
||||
lMinIops = 0;
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
throw new InvalidParameterValueException("'Min IOPS' must be a whole number.");
|
||||
}
|
||||
|
||||
long lMaxIops;
|
||||
|
||||
try {
|
||||
if (maxIops != null) {
|
||||
lMaxIops = Long.parseLong(maxIops);
|
||||
}
|
||||
else {
|
||||
lMaxIops = 0;
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
throw new InvalidParameterValueException("'Max IOPS' must be a whole number.");
|
||||
}
|
||||
|
||||
if (lMinIops > lMaxIops) {
|
||||
throw new InvalidParameterValueException("'Min IOPS' must be less than or equal to 'Max IOPS'.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create() throws ResourceAllocationException {
|
||||
try {
|
||||
//Verify that all objects exist before passing them to the service
|
||||
Account owner = _accountService.getActiveAccountById(getEntityOwnerId());
|
||||
|
||||
verifyDetails();
|
||||
|
||||
DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId);
|
||||
if (zone == null) {
|
||||
throw new InvalidParameterValueException("Unable to find zone by id=" + zoneId);
|
||||
}
|
||||
|
||||
ServiceOffering serviceOffering = _entityMgr.findById(ServiceOffering.class, serviceOfferingId);
|
||||
if (serviceOffering == null) {
|
||||
throw new InvalidParameterValueException("Unable to find service offering: " + serviceOfferingId);
|
||||
}
|
||||
|
||||
if(!serviceOffering.isDynamic()) {
|
||||
for(String detail: getDetails().keySet()) {
|
||||
if(detail.equalsIgnoreCase("cpuNumber") || detail.equalsIgnoreCase("cpuSpeed") || detail.equalsIgnoreCase("memory")) {
|
||||
throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, templateId);
|
||||
// Make sure a valid template ID was specified
|
||||
if (template == null) {
|
||||
throw new InvalidParameterValueException("Unable to find the template " + templateId);
|
||||
}
|
||||
|
||||
DiskOffering diskOffering = null;
|
||||
if (diskOfferingId != null) {
|
||||
diskOffering = _entityMgr.findById(DiskOffering.class, diskOfferingId);
|
||||
if (diskOffering == null) {
|
||||
throw new InvalidParameterValueException("Unable to find disk offering " + diskOfferingId);
|
||||
}
|
||||
}
|
||||
|
||||
if (!zone.isLocalStorageEnabled()) {
|
||||
if (serviceOffering.getUseLocalStorage()) {
|
||||
throw new InvalidParameterValueException("Zone is not configured to use local storage but service offering " + serviceOffering.getName() + " uses it");
|
||||
}
|
||||
if (diskOffering != null && diskOffering.getUseLocalStorage()) {
|
||||
throw new InvalidParameterValueException("Zone is not configured to use local storage but disk offering " + diskOffering.getName() + " uses it");
|
||||
}
|
||||
}
|
||||
|
||||
UserVm vm = null;
|
||||
IpAddresses addrs = new IpAddresses(ipAddress, getIp6Address());
|
||||
if (zone.getNetworkType() == NetworkType.Basic) {
|
||||
if (getNetworkIds() != null) {
|
||||
throw new InvalidParameterValueException("Can't specify network Ids in Basic zone");
|
||||
} else {
|
||||
vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(), owner, name, displayName, diskOfferingId,
|
||||
size, group, getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, getAffinityGroupIdList(),
|
||||
getDetails(), getCustomId());
|
||||
}
|
||||
} else {
|
||||
if (zone.isSecurityGroupEnabled()) {
|
||||
vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), getSecurityGroupIdList(), owner, name,
|
||||
displayName, diskOfferingId, size, group, getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard,
|
||||
getAffinityGroupIdList(), getDetails(), getCustomId());
|
||||
|
||||
} else {
|
||||
if (getSecurityGroupIdList() != null && !getSecurityGroupIdList().isEmpty()) {
|
||||
throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone");
|
||||
}
|
||||
vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, getNetworkIds(), owner, name, displayName, diskOfferingId, size, group,
|
||||
getHypervisor(), getHttpMethod(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, displayVm, keyboard, getAffinityGroupIdList(), getDetails(),
|
||||
getCustomId());
|
||||
}
|
||||
}
|
||||
UserVm vm = _userVmService.createVirtualMachine(this);
|
||||
|
||||
if (vm != null) {
|
||||
setEntityId(vm.getId());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
// 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.List;
|
||||
|
||||
public interface SecurityGroupAction {
|
||||
List<Long> getSecurityGroupIdList();
|
||||
List<String> getSecurityGroupNameList();
|
||||
long getEntityOwnerId();
|
||||
}
|
||||
|
|
@ -16,7 +16,9 @@
|
|||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.vm;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||
|
|
@ -29,8 +31,10 @@ 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;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
|
|
@ -38,14 +42,11 @@ import com.cloud.user.Account;
|
|||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
@APICommand(name = "updateVirtualMachine", description="Updates properties of a virtual machine. The VM has to be stopped and restarted for the " +
|
||||
"new properties to take effect. UpdateVirtualMachine does not first check whether the VM is stopped. " +
|
||||
"Therefore, stop the VM manually before issuing this call.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class},
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true)
|
||||
public class UpdateVMCmd extends BaseCustomIdCmd {
|
||||
public class UpdateVMCmd extends BaseCustomIdCmd implements SecurityGroupAction {
|
||||
public static final Logger s_logger = Logger.getLogger(UpdateVMCmd.class.getName());
|
||||
private static final String s_name = "updatevirtualmachineresponse";
|
||||
|
||||
|
|
@ -96,6 +97,25 @@ public class UpdateVMCmd extends BaseCustomIdCmd {
|
|||
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, description = "Details in key/value pairs.")
|
||||
protected Map<String, String> 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<Long> securityGroupIdList;
|
||||
|
||||
@ACL
|
||||
@Parameter(name = ApiConstants.SECURITY_GROUP_NAMES,
|
||||
type = CommandType.LIST,
|
||||
collectionType = CommandType.STRING,
|
||||
entityType = SecurityGroupResponse.class,
|
||||
description = "comma separated list of security groups names that going to be applied to the virtual machine. " +
|
||||
"Should be passed only when vm is created from a zone with Basic Network support. " +
|
||||
"Mutually exclusive with securitygroupids parameter"
|
||||
)
|
||||
private List<String> securityGroupNameList;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -145,7 +165,15 @@ public class UpdateVMCmd extends BaseCustomIdCmd {
|
|||
return (Map<String, String>) (paramsCollection.toArray())[0];
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
public List<Long> getSecurityGroupIdList() {
|
||||
return securityGroupIdList;
|
||||
}
|
||||
|
||||
public List<String> getSecurityGroupNameList() {
|
||||
return securityGroupNameList;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Long> 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.
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd;
|
|||
import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.SecurityGroupAction;
|
||||
import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd;
|
||||
import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
|
||||
|
|
@ -194,6 +195,7 @@ import com.cloud.network.security.dao.SecurityGroupDao;
|
|||
import com.cloud.network.security.dao.SecurityGroupVMMapDao;
|
||||
import com.cloud.network.vpc.VpcManager;
|
||||
import com.cloud.network.vpc.dao.VpcDao;
|
||||
import com.cloud.offering.DiskOffering;
|
||||
import com.cloud.offering.NetworkOffering;
|
||||
import com.cloud.offering.NetworkOffering.Availability;
|
||||
import com.cloud.offering.ServiceOffering;
|
||||
|
|
@ -2289,6 +2291,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
String hostName = cmd.getHostName();
|
||||
Map<String,String> details = cmd.getDetails();
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
List<Long> securityGroupIdList = getSecurityGroupIdList(cmd);
|
||||
|
||||
// Input validation and permission checks
|
||||
UserVmVO vmInstance = _vmDao.findById(id);
|
||||
|
|
@ -2339,7 +2342,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 +2392,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<Long> 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 +2455,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);
|
||||
|
|
@ -4280,8 +4322,172 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
@Override
|
||||
public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException,
|
||||
StorageUnavailableException, ResourceAllocationException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
//Verify that all objects exist before passing them to the service
|
||||
Account owner = _accountService.getActiveAccountById(cmd.getEntityOwnerId());
|
||||
|
||||
verifyDetails(cmd.getDetails());
|
||||
|
||||
Long zoneId = cmd.getZoneId();
|
||||
|
||||
DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId);
|
||||
if (zone == null) {
|
||||
throw new InvalidParameterValueException("Unable to find zone by id=" + zoneId);
|
||||
}
|
||||
|
||||
Long serviceOfferingId = cmd.getServiceOfferingId();
|
||||
|
||||
ServiceOffering serviceOffering = _entityMgr.findById(ServiceOffering.class, serviceOfferingId);
|
||||
if (serviceOffering == null) {
|
||||
throw new InvalidParameterValueException("Unable to find service offering: " + serviceOfferingId);
|
||||
}
|
||||
|
||||
Long templateId = cmd.getTemplateId();
|
||||
|
||||
if(!serviceOffering.isDynamic()) {
|
||||
for(String detail: cmd.getDetails().keySet()) {
|
||||
if(detail.equalsIgnoreCase("cpuNumber") || detail.equalsIgnoreCase("cpuSpeed") || detail.equalsIgnoreCase("memory")) {
|
||||
throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, templateId);
|
||||
// Make sure a valid template ID was specified
|
||||
if (template == null) {
|
||||
throw new InvalidParameterValueException("Unable to use template " + templateId);
|
||||
}
|
||||
|
||||
Long diskOfferingId = cmd.getDiskOfferingId();
|
||||
DiskOffering diskOffering = null;
|
||||
if (diskOfferingId != null) {
|
||||
diskOffering = _entityMgr.findById(DiskOffering.class, diskOfferingId);
|
||||
if (diskOffering == null) {
|
||||
throw new InvalidParameterValueException("Unable to find disk offering " + diskOfferingId);
|
||||
}
|
||||
}
|
||||
|
||||
if (!zone.isLocalStorageEnabled()) {
|
||||
if (serviceOffering.getUseLocalStorage()) {
|
||||
throw new InvalidParameterValueException("Zone is not configured to use local storage but service offering " + serviceOffering.getName() + " uses it");
|
||||
}
|
||||
if (diskOffering != null && diskOffering.getUseLocalStorage()) {
|
||||
throw new InvalidParameterValueException("Zone is not configured to use local storage but disk offering " + diskOffering.getName() + " uses it");
|
||||
}
|
||||
}
|
||||
|
||||
String ipAddress = cmd.getIpAddress();
|
||||
String ip6Address = cmd.getIp6Address();
|
||||
String name = cmd.getName();
|
||||
String displayName = cmd.getDisplayName();
|
||||
UserVm vm = null;
|
||||
IpAddresses addrs = new IpAddresses(ipAddress, ip6Address);
|
||||
Long size = cmd.getSize();
|
||||
String group = cmd.getGroup();
|
||||
String userData = cmd.getUserData();
|
||||
String sshKeyPairName = cmd.getSSHKeyPairName();
|
||||
Boolean displayVm = cmd.getDisplayVm();
|
||||
String keyboard = cmd.getKeyboard();
|
||||
if (zone.getNetworkType() == NetworkType.Basic) {
|
||||
if (cmd.getNetworkIds() != null) {
|
||||
throw new InvalidParameterValueException("Can't specify network Ids in Basic zone");
|
||||
} else {
|
||||
vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd), owner, name, displayName, diskOfferingId,
|
||||
size , group , cmd.getHypervisor(), cmd.getHttpMethod(), userData , sshKeyPairName , cmd.getIpToNetworkMap(), addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(),
|
||||
cmd.getDetails(), cmd.getCustomId());
|
||||
}
|
||||
} else {
|
||||
if (zone.isSecurityGroupEnabled()) {
|
||||
vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, cmd.getNetworkIds(), getSecurityGroupIdList(cmd), owner, name,
|
||||
displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairName, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard,
|
||||
cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId());
|
||||
|
||||
} else {
|
||||
if (cmd.getSecurityGroupIdList() != null && !cmd.getSecurityGroupIdList().isEmpty()) {
|
||||
throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone");
|
||||
}
|
||||
vm = createAdvancedVirtualMachine(zone, serviceOffering, template, cmd.getNetworkIds(), owner, name, displayName, diskOfferingId, size, group,
|
||||
cmd.getHypervisor(), cmd.getHttpMethod(), userData, sshKeyPairName, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(),
|
||||
cmd.getCustomId());
|
||||
}
|
||||
}
|
||||
return vm;
|
||||
}
|
||||
|
||||
private List<Long> getSecurityGroupIdList(SecurityGroupAction cmd) {
|
||||
if (cmd.getSecurityGroupNameList() != null && cmd.getSecurityGroupIdList() != null) {
|
||||
throw new InvalidParameterValueException("securitygroupids parameter is mutually exclusive with securitygroupnames parameter");
|
||||
}
|
||||
|
||||
//transform group names to ids here
|
||||
if (cmd.getSecurityGroupNameList() != null) {
|
||||
List<Long> securityGroupIds = new ArrayList<Long>();
|
||||
for (String groupName : cmd.getSecurityGroupNameList()) {
|
||||
SecurityGroup sg = _securityGroupMgr.getSecurityGroup(groupName, cmd.getEntityOwnerId());
|
||||
if (sg == null) {
|
||||
throw new InvalidParameterValueException("Unable to find group by name " + groupName);
|
||||
} else {
|
||||
securityGroupIds.add(sg.getId());
|
||||
}
|
||||
}
|
||||
return securityGroupIds;
|
||||
} else {
|
||||
return cmd.getSecurityGroupIdList();
|
||||
}
|
||||
}
|
||||
|
||||
// this is an opportunity to verify that parameters that came in via the Details Map are OK
|
||||
// for example, minIops and maxIops should either both be specified or neither be specified and,
|
||||
// if specified, minIops should be <= maxIops
|
||||
private void verifyDetails(Map<String,String> details) {
|
||||
if (details != null) {
|
||||
String minIops = (String)details.get("minIops");
|
||||
String maxIops = (String)details.get("maxIops");
|
||||
|
||||
verifyMinAndMaxIops(minIops, maxIops);
|
||||
|
||||
minIops = (String)details.get("minIopsDo");
|
||||
maxIops = (String)details.get("maxIopsDo");
|
||||
|
||||
verifyMinAndMaxIops(minIops, maxIops);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyMinAndMaxIops(String minIops, String maxIops) {
|
||||
if ((minIops != null && maxIops == null) || (minIops == null && maxIops != null)) {
|
||||
throw new InvalidParameterValueException("Either 'Min IOPS' and 'Max IOPS' must both be specified or neither be specified.");
|
||||
}
|
||||
|
||||
long lMinIops;
|
||||
|
||||
try {
|
||||
if (minIops != null) {
|
||||
lMinIops = Long.parseLong(minIops);
|
||||
}
|
||||
else {
|
||||
lMinIops = 0;
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
throw new InvalidParameterValueException("'Min IOPS' must be a whole number.");
|
||||
}
|
||||
|
||||
long lMaxIops;
|
||||
|
||||
try {
|
||||
if (maxIops != null) {
|
||||
lMaxIops = Long.parseLong(maxIops);
|
||||
}
|
||||
else {
|
||||
lMaxIops = 0;
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException ex) {
|
||||
throw new InvalidParameterValueException("'Max IOPS' must be a whole number.");
|
||||
}
|
||||
|
||||
if (lMinIops > lMaxIops) {
|
||||
throw new InvalidParameterValueException("'Min IOPS' must be less than or equal to 'Max IOPS'.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
Loading…
Reference in New Issue