Changes to add AffinityGroupprocessor, deployVM changes

This commit is contained in:
Prachi Damle 2013-03-13 13:57:47 -07:00
parent 1aed5bf9c2
commit fe2a86871f
20 changed files with 755 additions and 166 deletions

View File

@ -386,6 +386,7 @@ public class EventTypes {
public static final String EVENT_AFFINITY_GROUP_DELETE = "AG.DELETE"; public static final String EVENT_AFFINITY_GROUP_DELETE = "AG.DELETE";
public static final String EVENT_AFFINITY_GROUP_ASSIGN = "AG.ASSIGN"; public static final String EVENT_AFFINITY_GROUP_ASSIGN = "AG.ASSIGN";
public static final String EVENT_AFFINITY_GROUP_REMOVE = "AG.REMOVE"; public static final String EVENT_AFFINITY_GROUP_REMOVE = "AG.REMOVE";
public static final String EVENT_VM_AFFINITY_GROUP_UPDATE = "VM.AG.UPDATE";
static { static {

View File

@ -0,0 +1,18 @@
package com.cloud.exception;
import com.cloud.exception.CloudException;
import com.cloud.utils.SerialVersionUID;
public class AffinityConflictException extends CloudException {
private static final long serialVersionUID = SerialVersionUID.AffinityConflictException;
public AffinityConflictException(String message) {
super(message);
}
public AffinityConflictException(String message, Throwable th) {
super(message, th);
}
}

View File

@ -26,9 +26,6 @@ import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
import org.apache.cloudstack.api.command.user.vm.*; import org.apache.cloudstack.api.command.user.vm.*;
import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter;
import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InsufficientCapacityException;
@ -42,7 +39,6 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.Network.IpAddresses; import com.cloud.network.Network.IpAddresses;
import com.cloud.offering.ServiceOffering; import com.cloud.offering.ServiceOffering;
import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePool;
import com.cloud.storage.Volume;
import com.cloud.template.VirtualMachineTemplate; import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.uservm.UserVm; import com.cloud.uservm.UserVm;
@ -123,7 +119,8 @@ public interface UserVmService {
/** /**
* Creates a Basic Zone User VM in the database and returns the VM to the caller. * Creates a Basic Zone User VM in the database and returns the VM to the
* caller.
* *
* @param zone * @param zone
* - availability zone for the virtual machine * - availability zone for the virtual machine
@ -132,61 +129,69 @@ public interface UserVmService {
* @param template * @param template
* - the template for the virtual machine * - the template for the virtual machine
* @param securityGroupIdList * @param securityGroupIdList
* - comma separated list of security groups id that going to be applied to the virtual machine * - comma separated list of security groups id that going to be
* applied to the virtual machine
* @param hostName * @param hostName
* - host name for the virtual machine * - host name for the virtual machine
* @param displayName * @param displayName
* - an optional user generated name for the virtual machine * - an optional user generated name for the virtual machine
* @param diskOfferingId * @param diskOfferingId
* - the ID of the disk offering for the virtual machine. If the template is of ISO format, the * - the ID of the disk offering for the virtual machine. If the
* diskOfferingId is * template is of ISO format, the diskOfferingId is for the root
* for the root disk volume. Otherwise this parameter is used to indicate the offering for the data disk * disk volume. Otherwise this parameter is used to indicate the
* volume. * offering for the data disk volume. If the templateId parameter
* If the templateId parameter passed is from a Template object, the diskOfferingId refers to a DATA Disk * passed is from a Template object, the diskOfferingId refers to
* Volume * a DATA Disk Volume created. If the templateId parameter passed
* created. If the templateId parameter passed is from an ISO object, the diskOfferingId refers to a ROOT * is from an ISO object, the diskOfferingId refers to a ROOT
* Disk * Disk Volume created
* Volume created
* @param diskSize * @param diskSize
* - the arbitrary size for the DATADISK volume. Mutually exclusive with diskOfferingId * - the arbitrary size for the DATADISK volume. Mutually
* exclusive with diskOfferingId
* @param group * @param group
* - an optional group for the virtual machine * - an optional group for the virtual machine
* @param hypervisor * @param hypervisor
* - the hypervisor on which to deploy the virtual machine * - the hypervisor on which to deploy the virtual machine
* @param userData * @param userData
* - an optional binary data that can be sent to the virtual machine upon a successful deployment. This * - an optional binary data that can be sent to the virtual
* binary * machine upon a successful deployment. This binary data must be
* data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported. * base64 encoded before adding it to the request. Currently only
* Using HTTP * HTTP GET is supported. Using HTTP GET (via querystring), you
* GET (via querystring), you can send up to 2KB of data after base64 encoding * can send up to 2KB of data after base64 encoding
* @param sshKeyPair * @param sshKeyPair
* - name of the ssh key pair used to login to the virtual machine * - name of the ssh key pair used to login to the virtual
* machine
* @param requestedIps * @param requestedIps
* TODO * TODO
* @param defaultIp * @param defaultIp
* TODO * TODO
* @param affinityGroupIdList
* @param accountName * @param accountName
* - an optional account for the virtual machine. Must be used with domainId * - an optional account for the virtual machine. Must be used
* with domainId
* @param domainId * @param domainId
* - an optional domainId for the virtual machine. If the account parameter is used, domainId must also * - an optional domainId for the virtual machine. If the account
* be used * parameter is used, domainId must also be used
* @return UserVm object if successful. * @return UserVm object if successful.
* *
* @throws InsufficientCapacityException * @throws InsufficientCapacityException
* if there is insufficient capacity to deploy the VM. * if there is insufficient capacity to deploy the VM.
* @throws ConcurrentOperationException * @throws ConcurrentOperationException
* if there are multiple users working on the same VM or in the same environment. * if there are multiple users working on the same VM or in the
* same environment.
* @throws ResourceUnavailableException * @throws ResourceUnavailableException
* if the resources required to deploy the VM is not currently available. * if the resources required to deploy the VM is not currently
* available.
* @throws InsufficientResourcesException * @throws InsufficientResourcesException
*/ */
UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList, Account owner, String hostName, UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList, Account owner, String hostName,
String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp, String keyboard) String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp,
String keyboard, List<Long> affinityGroupIdList)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
/** /**
* Creates a User VM in Advanced Zone (Security Group feature is enabled) in the database and returns the VM to the * Creates a User VM in Advanced Zone (Security Group feature is enabled) in
* caller. * the database and returns the VM to the caller.
* *
* @param zone * @param zone
* - availability zone for the virtual machine * - availability zone for the virtual machine
@ -197,62 +202,68 @@ public interface UserVmService {
* @param networkIdList * @param networkIdList
* - list of network ids used by virtual machine * - list of network ids used by virtual machine
* @param securityGroupIdList * @param securityGroupIdList
* - comma separated list of security groups id that going to be applied to the virtual machine * - comma separated list of security groups id that going to be
* applied to the virtual machine
* @param hostName * @param hostName
* - host name for the virtual machine * - host name for the virtual machine
* @param displayName * @param displayName
* - an optional user generated name for the virtual machine * - an optional user generated name for the virtual machine
* @param diskOfferingId * @param diskOfferingId
* - the ID of the disk offering for the virtual machine. If the template is of ISO format, the * - the ID of the disk offering for the virtual machine. If the
* diskOfferingId is * template is of ISO format, the diskOfferingId is for the root
* for the root disk volume. Otherwise this parameter is used to indicate the offering for the data disk * disk volume. Otherwise this parameter is used to indicate the
* volume. * offering for the data disk volume. If the templateId parameter
* If the templateId parameter passed is from a Template object, the diskOfferingId refers to a DATA Disk * passed is from a Template object, the diskOfferingId refers to
* Volume * a DATA Disk Volume created. If the templateId parameter passed
* created. If the templateId parameter passed is from an ISO object, the diskOfferingId refers to a ROOT * is from an ISO object, the diskOfferingId refers to a ROOT
* Disk * Disk Volume created
* Volume created
* @param diskSize * @param diskSize
* - the arbitrary size for the DATADISK volume. Mutually exclusive with diskOfferingId * - the arbitrary size for the DATADISK volume. Mutually
* exclusive with diskOfferingId
* @param group * @param group
* - an optional group for the virtual machine * - an optional group for the virtual machine
* @param hypervisor * @param hypervisor
* - the hypervisor on which to deploy the virtual machine * - the hypervisor on which to deploy the virtual machine
* @param userData * @param userData
* - an optional binary data that can be sent to the virtual machine upon a successful deployment. This * - an optional binary data that can be sent to the virtual
* binary * machine upon a successful deployment. This binary data must be
* data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported. * base64 encoded before adding it to the request. Currently only
* Using HTTP * HTTP GET is supported. Using HTTP GET (via querystring), you
* GET (via querystring), you can send up to 2KB of data after base64 encoding * can send up to 2KB of data after base64 encoding
* @param sshKeyPair * @param sshKeyPair
* - name of the ssh key pair used to login to the virtual machine * - name of the ssh key pair used to login to the virtual
* machine
* @param requestedIps * @param requestedIps
* TODO * TODO
* @param defaultIps * @param defaultIps
* TODO * TODO
* @param affinityGroupIdList
* @param accountName * @param accountName
* - an optional account for the virtual machine. Must be used with domainId * - an optional account for the virtual machine. Must be used
* with domainId
* @param domainId * @param domainId
* - an optional domainId for the virtual machine. If the account parameter is used, domainId must also * - an optional domainId for the virtual machine. If the account
* be used * parameter is used, domainId must also be used
* @return UserVm object if successful. * @return UserVm object if successful.
* *
* @throws InsufficientCapacityException * @throws InsufficientCapacityException
* if there is insufficient capacity to deploy the VM. * if there is insufficient capacity to deploy the VM.
* @throws ConcurrentOperationException * @throws ConcurrentOperationException
* if there are multiple users working on the same VM or in the same environment. * if there are multiple users working on the same VM or in the
* same environment.
* @throws ResourceUnavailableException * @throws ResourceUnavailableException
* if the resources required to deploy the VM is not currently available. * if the resources required to deploy the VM is not currently
* available.
* @throws InsufficientResourcesException * @throws InsufficientResourcesException
*/ */
UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, List<Long> securityGroupIdList, UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, List<Long> securityGroupIdList,
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps,
IpAddresses defaultIps, String keyboard) IpAddresses defaultIps, String keyboard, List<Long> affinityGroupIdList)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
/** /**
* Creates a User VM in Advanced Zone (Security Group feature is disabled) in the database and returns the VM to the * Creates a User VM in Advanced Zone (Security Group feature is disabled)
* caller. * in the database and returns the VM to the caller.
* *
* @param zone * @param zone
* - availability zone for the virtual machine * - availability zone for the virtual machine
@ -267,49 +278,57 @@ public interface UserVmService {
* @param displayName * @param displayName
* - an optional user generated name for the virtual machine * - an optional user generated name for the virtual machine
* @param diskOfferingId * @param diskOfferingId
* - the ID of the disk offering for the virtual machine. If the template is of ISO format, the * - the ID of the disk offering for the virtual machine. If the
* diskOfferingId is * template is of ISO format, the diskOfferingId is for the root
* for the root disk volume. Otherwise this parameter is used to indicate the offering for the data disk * disk volume. Otherwise this parameter is used to indicate the
* volume. * offering for the data disk volume. If the templateId parameter
* If the templateId parameter passed is from a Template object, the diskOfferingId refers to a DATA Disk * passed is from a Template object, the diskOfferingId refers to
* Volume * a DATA Disk Volume created. If the templateId parameter passed
* created. If the templateId parameter passed is from an ISO object, the diskOfferingId refers to a ROOT * is from an ISO object, the diskOfferingId refers to a ROOT
* Disk * Disk Volume created
* Volume created
* @param diskSize * @param diskSize
* - the arbitrary size for the DATADISK volume. Mutually exclusive with diskOfferingId * - the arbitrary size for the DATADISK volume. Mutually
* exclusive with diskOfferingId
* @param group * @param group
* - an optional group for the virtual machine * - an optional group for the virtual machine
* @param hypervisor * @param hypervisor
* - the hypervisor on which to deploy the virtual machine * - the hypervisor on which to deploy the virtual machine
* @param userData * @param userData
* - an optional binary data that can be sent to the virtual machine upon a successful deployment. This * - an optional binary data that can be sent to the virtual
* binary * machine upon a successful deployment. This binary data must be
* data must be base64 encoded before adding it to the request. Currently only HTTP GET is supported. * base64 encoded before adding it to the request. Currently only
* Using HTTP * HTTP GET is supported. Using HTTP GET (via querystring), you
* GET (via querystring), you can send up to 2KB of data after base64 encoding * can send up to 2KB of data after base64 encoding
* @param sshKeyPair * @param sshKeyPair
* - name of the ssh key pair used to login to the virtual machine * - name of the ssh key pair used to login to the virtual
* machine
* @param requestedIps * @param requestedIps
* TODO * TODO
* @param defaultIps TODO * @param defaultIps
* TODO
* @param affinityGroupIdList
* @param accountName * @param accountName
* - an optional account for the virtual machine. Must be used with domainId * - an optional account for the virtual machine. Must be used
* with domainId
* @param domainId * @param domainId
* - an optional domainId for the virtual machine. If the account parameter is used, domainId must also * - an optional domainId for the virtual machine. If the account
* be used * parameter is used, domainId must also be used
* @return UserVm object if successful. * @return UserVm object if successful.
* *
* @throws InsufficientCapacityException * @throws InsufficientCapacityException
* if there is insufficient capacity to deploy the VM. * if there is insufficient capacity to deploy the VM.
* @throws ConcurrentOperationException * @throws ConcurrentOperationException
* if there are multiple users working on the same VM or in the same environment. * if there are multiple users working on the same VM or in the
* same environment.
* @throws ResourceUnavailableException * @throws ResourceUnavailableException
* if the resources required to deploy the VM is not currently available. * if the resources required to deploy the VM is not currently
* available.
* @throws InsufficientResourcesException * @throws InsufficientResourcesException
*/ */
UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner, String hostName, UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner, String hostName,
String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, String keyboard) String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps,
String keyboard, List<Long> affinityGroupIdList)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException; throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
/** /**

View File

@ -0,0 +1,14 @@
package org.apache.cloudstack.affinity;
import org.apache.cloudstack.deploy.UserPreferrenceProcessor;
public interface AffinityGroupProcessor extends UserPreferrenceProcessor {
/**
* getType() should return the affinity/anti-affinity group being
* implemented
*
* @return String Affinity/Anti-affinity type
*/
String getType();
}

View File

@ -3,6 +3,7 @@ package org.apache.cloudstack.affinity;
import java.util.List; import java.util.List;
import com.cloud.exception.ResourceInUseException; import com.cloud.exception.ResourceInUseException;
import com.cloud.uservm.UserVm;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
public interface AffinityGroupService { public interface AffinityGroupService {
@ -57,4 +58,6 @@ public interface AffinityGroupService {
AffinityGroup getAffinityGroup(Long groupId); AffinityGroup getAffinityGroup(Long groupId);
UserVm updateVMAffinityGroups(Long vmId, List<Long> affinityGroupIds);
} }

View File

@ -473,6 +473,8 @@ public class ApiConstants {
public static final String HEALTHCHECK_HEALTHY_THRESHOLD = "healthythreshold"; public static final String HEALTHCHECK_HEALTHY_THRESHOLD = "healthythreshold";
public static final String HEALTHCHECK_UNHEALTHY_THRESHOLD = "unhealthythreshold"; public static final String HEALTHCHECK_UNHEALTHY_THRESHOLD = "unhealthythreshold";
public static final String HEALTHCHECK_PINGPATH = "pingpath"; public static final String HEALTHCHECK_PINGPATH = "pingpath";
public static final String AFFINITY_GROUP_IDS = "affinitygroupids";
public static final String AFFINITY_GROUP_NAMES = "affinitygroupnames";
public enum HostDetails { public enum HostDetails {
all, capacity, events, stats, min; all, capacity, events, stats, min;

View File

@ -83,7 +83,8 @@ public class ListAffinityGroupsCmd extends BaseListCmd {
@Override @Override
public void execute(){ public void execute(){
Pair<List<AffinityGroup>, Integer> result = _affinityGroupService.listAffinityGroups(id, affinityGroupName, Pair<List<? extends AffinityGroup>, Integer> result = _affinityGroupService.listAffinityGroups(id,
affinityGroupName,
affinityGroupType, virtualMachineId, this.getStartIndex(), this.getPageSizeVal()); affinityGroupType, virtualMachineId, this.getStartIndex(), this.getPageSizeVal());
if (result != null) { if (result != null) {
ListResponse<AffinityGroupResponse> response = new ListResponse<AffinityGroupResponse>(); ListResponse<AffinityGroupResponse> response = new ListResponse<AffinityGroupResponse>();

View File

@ -0,0 +1,158 @@
// 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.affinitygroup;
import java.util.ArrayList;
import java.util.List;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
import org.apache.cloudstack.api.ACL;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.log4j.Logger;
import com.cloud.async.AsyncJob;
import com.cloud.event.EventTypes;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import com.cloud.uservm.UserVm;
@APICommand(name = "updateVMAffinityGroup", description = "Updates the affinity/anti-affinity group associations of a virtual machine. The VM has to be stopped and restarted for the "
+ "new properties to take effect.", responseObject = UserVmResponse.class)
public class UpdateVMAffinityGroupCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(UpdateVMAffinityGroupCmd.class.getName());
private static final String s_name = "updatevirtualmachineresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@ACL
@Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=UserVmResponse.class,
required=true, description="The ID of the virtual machine")
private Long id;
@ACL
@Parameter(name = ApiConstants.AFFINITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups id that are 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 securitygroupnames parameter")
private List<Long> affinityGroupIdList;
@ACL
@Parameter(name = ApiConstants.AFFINITY_GROUP_NAMES, type = CommandType.LIST, collectionType = CommandType.STRING, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups names that are 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> affinityGroupNameList;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getId() {
return id;
}
public List<Long> getAffinityGroupIdList() {
if (affinityGroupNameList != null && affinityGroupIdList != null) {
throw new InvalidParameterValueException(
"affinitygroupids parameter is mutually exclusive with affinitygroupnames parameter");
}
// transform group names to ids here
if (affinityGroupNameList != null) {
List<Long> affinityGroupIds = new ArrayList<Long>();
for (String groupName : affinityGroupNameList) {
Long groupId = _responseGenerator.getAffinityGroupId(groupName, getEntityOwnerId());
if (groupId == null) {
throw new InvalidParameterValueException("Unable to find group by name " + groupName
+ " for account " + getEntityOwnerId());
} else {
affinityGroupIds.add(groupId);
}
}
return affinityGroupIds;
} else {
return affinityGroupIdList;
}
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public String getCommandName() {
return s_name;
}
public static String getResultObjectName() {
return "virtualmachine";
}
@Override
public long getEntityOwnerId() {
UserVm userVm = _entityMgr.findById(UserVm.class, getId());
if (userVm != null) {
return userVm.getAccountId();
}
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
}
@Override
public void execute() throws ResourceUnavailableException,
InsufficientCapacityException, ServerApiException {
UserContext.current().setEventDetails("Vm Id: "+getId());
UserVm result = _affinityGroupService.updateVMAffinityGroups(getId(), getAffinityGroupIdList());
if (result != null){
UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", result).get(0);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update vm's affinity groups");
}
}
@Override
public String getEventType() {
return EventTypes.EVENT_VM_AFFINITY_GROUP_UPDATE;
}
@Override
public String getEventDescription() {
return "updating VM Affinity Group";
}
@Override
public AsyncJob.Type getInstanceType() {
return AsyncJob.Type.AffinityGroup;
}
}

View File

@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
import org.apache.cloudstack.api.ACL; import org.apache.cloudstack.api.ACL;
import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants;
@ -172,6 +173,18 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
@Parameter(name=ApiConstants.START_VM, type=CommandType.BOOLEAN, description="true if network offering supports specifying ip ranges; defaulted to true if not specified") @Parameter(name=ApiConstants.START_VM, type=CommandType.BOOLEAN, description="true if network offering supports specifying ip ranges; defaulted to true if not specified")
private Boolean startVm; private Boolean startVm;
@ACL
@Parameter(name = ApiConstants.AFFINITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups id that are 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 securitygroupnames parameter")
private List<Long> affinityGroupIdList;
@ACL
@Parameter(name = ApiConstants.AFFINITY_GROUP_NAMES, type = CommandType.LIST, collectionType = CommandType.STRING, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups names that are 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> affinityGroupNameList;
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
/////////////////// Accessors /////////////////////// /////////////////// Accessors ///////////////////////
@ -321,6 +334,30 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
return ip6Address.toLowerCase(); return ip6Address.toLowerCase();
} }
public List<Long> getAffinityGroupIdList() {
if (affinityGroupNameList != null && affinityGroupIdList != null) {
throw new InvalidParameterValueException(
"affinitygroupids parameter is mutually exclusive with affinitygroupnames parameter");
}
// transform group names to ids here
if (affinityGroupNameList != null) {
List<Long> affinityGroupIds = new ArrayList<Long>();
for (String groupName : affinityGroupNameList) {
Long groupId = _responseGenerator.getAffinityGroupId(groupName, getEntityOwnerId());
if (groupId == null) {
throw new InvalidParameterValueException("Unable to find group by name " + groupName
+ " for account " + getEntityOwnerId());
} else {
affinityGroupIds.add(groupId);
}
}
return affinityGroupIds;
} else {
return affinityGroupIdList;
}
}
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
/////////////// API Implementation/////////////////// /////////////// API Implementation///////////////////
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
@ -447,18 +484,18 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
throw new InvalidParameterValueException("Can't specify network Ids in Basic zone"); throw new InvalidParameterValueException("Can't specify network Ids in Basic zone");
} else { } else {
vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(), owner, name, vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(), owner, name,
displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard); displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList());
} }
} else { } else {
if (zone.isSecurityGroupEnabled()) { if (zone.isSecurityGroupEnabled()) {
vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), getSecurityGroupIdList(), vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), getSecurityGroupIdList(),
owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard); owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList());
} else { } else {
if (getSecurityGroupIdList() != null && !getSecurityGroupIdList().isEmpty()) { if (getSecurityGroupIdList() != null && !getSecurityGroupIdList().isEmpty()) {
throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone"); 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, vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, getNetworkIds(), owner, name, displayName,
diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard); diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName, getIpToNetworkMap(), addrs, keyboard, getAffinityGroupIdList());
} }
} }

View File

@ -0,0 +1,27 @@
package org.apache.cloudstack.deploy;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.exception.AffinityConflictException;
import com.cloud.utils.component.Adapter;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
public interface UserPreferrenceProcessor extends Adapter {
/**
* process() is called to apply any user preferences to the deployment plan
* and avoid set for the given VM placement.
*
* @param vm
* virtual machine.
* @param plan
* deployment plan that tells you where it's being deployed to.
* @param avoid
* avoid these data centers, pods, clusters, or hosts.
*/
void process(VirtualMachineProfile<? extends VirtualMachine> vm, DeploymentPlan plan, ExcludeList avoid)
throws AffinityConflictException;
}

View File

@ -0,0 +1,29 @@
package com.cloud.deploy;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.exception.AffinityConflictException;
import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.utils.component.Manager;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
public interface DeploymentPlanningManager extends Manager {
/**
* Manages vm deployment stages: First Process Affinity/Anti-affinity - Call
* the chain of AffinityGroupProcessor adapters to set deploymentplan scope
* and exclude list Secondly, Call DeploymentPlanner - to use heuristics to
* find the best spot to place the vm/volume. Planner will drill down to the
* write set of clusters to look for placement based on various heuristics.
* Lastly, Call Allocators - Given a cluster, allocators matches the
* requirements to capabilities of the physical resource (host, storage
* pool).
*
* @throws AffinityConflictException
*
*
*
*/
DeployDestination planDeployment(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan,
ExcludeList avoids) throws InsufficientServerCapacityException, AffinityConflictException;
}

View File

@ -0,0 +1,80 @@
package com.cloud.deploy;
import java.util.List;
import javax.ejb.Local;
import javax.inject.Inject;
import org.apache.cloudstack.affinity.AffinityGroupProcessor;
import org.apache.cloudstack.affinity.AffinityGroupVMMapVO;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
import org.apache.log4j.Logger;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.exception.AffinityConflictException;
import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.utils.component.Manager;
import com.cloud.utils.component.ManagerBase;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
@Local(value = { DeploymentPlanningManager.class })
public class DeploymentPlanningManagerImpl extends ManagerBase implements DeploymentPlanningManager, Manager {
private static final Logger s_logger = Logger.getLogger(DeploymentPlanningManagerImpl.class);
@Inject
protected UserVmDao _vmDao;
@Inject
protected VMInstanceDao _vmInstanceDao;
@Inject
protected AffinityGroupDao _affinityGroupDao;
@Inject
protected AffinityGroupVMMapDao _affinityGroupVMMapDao;
@Inject
protected List<DeploymentPlanner> _planners;
@Inject
protected List<AffinityGroupProcessor> _affinityProcessors;
@Override
public DeployDestination planDeployment(VirtualMachineProfile<? extends VirtualMachine> vmProfile,
DeploymentPlan plan, ExcludeList avoids) throws InsufficientServerCapacityException,
AffinityConflictException {
// call affinitygroup chain
VirtualMachine vm = vmProfile.getVirtualMachine();
long vmGroupCount = _affinityGroupVMMapDao.countAffinityGroupsForVm(vm.getId());
if (vmGroupCount > 0) {
for (AffinityGroupProcessor processor : _affinityProcessors) {
processor.process(vmProfile, plan, avoids);
}
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Deploy avoids pods: " + avoids.getPodsToAvoid() + ", clusters: "
+ avoids.getClustersToAvoid() + ", hosts: " + avoids.getHostsToAvoid());
}
// call planners
DeployDestination dest = null;
for (DeploymentPlanner planner : _planners) {
if (planner.canHandle(vmProfile, plan, avoids)) {
dest = planner.plan(vmProfile, plan, avoids);
} else {
continue;
}
if (dest != null) {
avoids.addHost(dest.getHost().getId());
break;
}
}
return dest;
}
}

View File

@ -35,6 +35,9 @@ import javax.naming.ConfigurationException;
import com.cloud.api.ApiDBUtils; import com.cloud.api.ApiDBUtils;
import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.affinity.AffinityGroupVO;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
import org.apache.cloudstack.api.command.user.vm.*; import org.apache.cloudstack.api.command.user.vm.*;
@ -378,6 +381,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
@Inject @Inject
protected VMSnapshotManager _vmSnapshotMgr; protected VMSnapshotManager _vmSnapshotMgr;
@Inject
AffinityGroupVMMapDao _affinityGroupVMMapDao;
@Inject
AffinityGroupDao _affinityGroupDao;
@Inject @Inject
List<DeployPlannerSelector> plannerSelectors; List<DeployPlannerSelector> plannerSelectors;
@ -1916,7 +1924,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
@Override @Override
public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList, Account owner, public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList, Account owner,
String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, String keyboard) String hostName,
String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps,
String keyboard, List<Long> affinityGroupIdList)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException {
Account caller = UserContext.current().getCaller(); Account caller = UserContext.current().getCaller();
@ -1966,13 +1977,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
} }
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId,
diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, keyboard); diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller,
requestedIps, defaultIps, keyboard, affinityGroupIdList);
} }
@Override @Override
public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList,
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData,
String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, String sshKeyPair, Map<Long, IpAddresses> requestedIps,
IpAddresses defaultIps, String keyboard, List<Long> affinityGroupIdList)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
StorageUnavailableException,
ResourceAllocationException { ResourceAllocationException {
Account caller = UserContext.current().getCaller(); Account caller = UserContext.current().getCaller();
@ -2079,12 +2094,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
} }
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId,
diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, keyboard); diskSize, networkList, securityGroupIdList, group, userData, sshKeyPair, hypervisor, caller,
requestedIps, defaultIps, keyboard, affinityGroupIdList);
} }
@Override @Override
public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner, String hostName, public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner, String hostName,
String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, String keyboard) String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps,
String keyboard, List<Long> affinityGroupIdList)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException {
Account caller = UserContext.current().getCaller(); Account caller = UserContext.current().getCaller();
@ -2192,7 +2210,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
} }
} }
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps, keyboard); return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId,
diskSize, networkList, null, group, userData, sshKeyPair, hypervisor, caller, requestedIps, defaultIps,
keyboard, affinityGroupIdList);
} }
@ -2205,7 +2225,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
@DB @ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true) @DB @ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true)
protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, String hostName, String displayName, Account owner, Long diskOfferingId, protected UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, String hostName, String displayName, Account owner, Long diskOfferingId,
Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, String userData, String sshKeyPair, HypervisorType hypervisor, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, String keyboard) Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, String userData,
String sshKeyPair, HypervisorType hypervisor, Account caller, Map<Long, IpAddresses> requestedIps,
IpAddresses defaultIps, String keyboard, List<Long> affinityGroupIdList)
throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException { throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException {
_accountMgr.checkAccess(caller, null, true, owner); _accountMgr.checkAccess(caller, null, true, owner);
@ -2261,6 +2283,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
} }
} }
// check that the affinity groups exist
for (Long affinityGroupId : affinityGroupIdList) {
AffinityGroupVO ag = _affinityGroupDao.findById(affinityGroupId);
if (ag == null) {
throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId);
}
}
if (template.getHypervisorType() != null && template.getHypervisorType() != HypervisorType.BareMetal) { if (template.getHypervisorType() != null && template.getHypervisorType() != HypervisorType.BareMetal) {
// check if we have available pools for vm deployment // check if we have available pools for vm deployment
long availablePools = _storagePoolDao.countPoolsByStatus(StoragePoolStatus.Up); long availablePools = _storagePoolDao.countPoolsByStatus(StoragePoolStatus.Up);
@ -2552,6 +2582,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
_securityGroupMgr.addInstanceToGroups(vm.getId(), securityGroupIdList); _securityGroupMgr.addInstanceToGroups(vm.getId(), securityGroupIdList);
_affinityGroupVMMapDao.updateMap(vm.getId(), affinityGroupIdList);
return vm; return vm;
} }

View File

@ -68,7 +68,9 @@ import com.cloud.deploy.DeployDestination;
import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner; import com.cloud.deploy.DeploymentPlanner;
import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.deploy.DeploymentPlanningManager;
import com.cloud.domain.dao.DomainDao; import com.cloud.domain.dao.DomainDao;
import com.cloud.exception.AffinityConflictException;
import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.ConnectionException; import com.cloud.exception.ConnectionException;
@ -239,6 +241,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
@Inject @Inject
VolumeManager volumeMgr; VolumeManager volumeMgr;
@Inject
DeploymentPlanningManager _dpMgr;
Map<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>> _vmGurus = new HashMap<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>>(); Map<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>> _vmGurus = new HashMap<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>>();
protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine; protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine;
@ -695,17 +700,11 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
VirtualMachineProfileImpl<T> vmProfile = new VirtualMachineProfileImpl<T>(vm, template, offering, account, params); VirtualMachineProfileImpl<T> vmProfile = new VirtualMachineProfileImpl<T>(vm, template, offering, account, params);
DeployDestination dest = null; DeployDestination dest = null;
for (DeploymentPlanner planner : _planners) { try {
if (planner.canHandle(vmProfile, plan, avoids)) { dest = _dpMgr.planDeployment(vmProfile, plan, avoids);
dest = planner.plan(vmProfile, plan, avoids); } catch (AffinityConflictException e2) {
} else { // TODO Auto-generated catch block
continue; e2.printStackTrace();
}
if (dest != null) {
avoids.addHost(dest.getHost().getId());
journal.record("Deployment found ", vmProfile, dest);
break;
}
} }
if (dest == null) { if (dest == null) {

View File

@ -1,6 +1,5 @@
package org.apache.cloudstack.affinity; package org.apache.cloudstack.affinity;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -13,36 +12,34 @@ import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import com.cloud.api.query.vo.SecurityGroupJoinVO;
import com.cloud.event.ActionEvent; import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes; import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceInUseException; import com.cloud.exception.ResourceInUseException;
import com.cloud.network.PhysicalNetwork; import com.cloud.network.security.SecurityGroup;
import com.cloud.network.dao.PhysicalNetworkVO;
import com.cloud.network.security.SecurityGroupManager;
import com.cloud.network.security.SecurityGroupRuleVO;
import com.cloud.network.security.SecurityGroupVMMapVO;
import com.cloud.network.security.SecurityGroupVO;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.user.AccountManager; import com.cloud.user.AccountManager;
import com.cloud.user.UserContext; import com.cloud.user.UserContext;
import com.cloud.uservm.UserVm;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.utils.component.Manager; import com.cloud.utils.component.Manager;
import com.cloud.utils.component.ManagerBase; import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.DB; import com.cloud.utils.db.DB;
import com.cloud.utils.db.Filter; import com.cloud.utils.db.Filter;
import com.cloud.utils.db.JoinBuilder.JoinType;
import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction; import com.cloud.utils.db.Transaction;
import com.cloud.utils.fsm.StateListener;
import com.cloud.vm.UserVmVO; import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.Event;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDao;
@Local(value = { AffinityGroupService.class }) @Local(value = { AffinityGroupService.class })
public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGroupService, Manager { public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGroupService, Manager,
StateListener<State, VirtualMachine.Event, VirtualMachine> {
public static final Logger s_logger = Logger.getLogger(AffinityGroupServiceImpl.class); public static final Logger s_logger = Logger.getLogger(AffinityGroupServiceImpl.class);
private String _name; private String _name;
@ -221,4 +218,56 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
return _affinityGroupDao.findById(groupId); return _affinityGroupDao.findById(groupId);
} }
@Override
public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo,
boolean status, Object opaque) {
return true;
}
@Override
public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo,
boolean status, Object opaque) {
if (!status) {
return false;
}
if ((newState == State.Expunging)) {
// cleanup all affinity groups associated to the Expunged VM
SearchCriteria<AffinityGroupVMMapVO> sc = _affinityGroupVMMapDao.createSearchCriteria();
sc.addAnd("instanceId", SearchCriteria.Op.EQ, vo.getId());
_affinityGroupVMMapDao.expunge(sc);
}
return true;
}
@Override
public UserVm updateVMAffinityGroups(Long vmId, List<Long> affinityGroupIds) {
// Verify input parameters
UserVmVO vmInstance = _userVmDao.findById(vmId);
if (vmInstance == null) {
throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId);
}
// Check that the VM is stopped
if (!vmInstance.getState().equals(State.Stopped)) {
s_logger.warn("Unable to update affinity groups of the virtual machine " + vmInstance.toString()
+ " in state " + vmInstance.getState());
throw new InvalidParameterValueException("Unable update affinity groups of the virtual machine "
+ vmInstance.toString() + " " + "in state " + vmInstance.getState()
+ "; make sure the virtual machine is stopped and not in an error state before updating.");
}
// check that the affinity groups exist
for (Long affinityGroupId : affinityGroupIds) {
AffinityGroupVO ag = _affinityGroupDao.findById(affinityGroupId);
if (ag == null) {
throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId);
}
}
_affinityGroupVMMapDao.updateMap(vmId, affinityGroupIds);
// APIResponseHelper will pull out the updated affinitygroups.
return vmInstance;
}
} }

View File

@ -0,0 +1,66 @@
package org.apache.cloudstack.affinity;
import java.util.List;
import javax.ejb.Local;
import javax.inject.Inject;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
import org.apache.log4j.Logger;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.exception.AffinityConflictException;
import com.cloud.utils.component.AdapterBase;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
@Local(value = AffinityGroupProcessor.class)
public class HostAntiAffinityProcessor extends AdapterBase implements AffinityGroupProcessor {
private static final Logger s_logger = Logger.getLogger(HostAntiAffinityProcessor.class);
@Inject
protected UserVmDao _vmDao;
@Inject
protected VMInstanceDao _vmInstanceDao;
@Inject
protected AffinityGroupDao _affinityGroupDao;
@Inject
protected AffinityGroupVMMapDao _affinityGroupVMMapDao;
@Override
public void process(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan,
ExcludeList avoid)
throws AffinityConflictException {
VirtualMachine vm = vmProfile.getVirtualMachine();
AffinityGroupVMMapVO vmGroupMapping = _affinityGroupVMMapDao.findByVmIdType(vm.getId(), getType());
if (vmGroupMapping != null) {
AffinityGroupVO group = _affinityGroupDao.findById(vmGroupMapping.getAffinityGroupId());
if (s_logger.isDebugEnabled()) {
s_logger.debug("Processing affinity group " + group.getName() + " for VM Id: " + vm.getId());
}
List<Long> groupVMIds = _affinityGroupVMMapDao.listVmIdsByAffinityGroup(group.getId());
for (Long groupVMId : groupVMIds) {
VMInstanceVO groupVM = _vmInstanceDao.findById(groupVMId);
if (groupVM != null && !groupVM.isRemoved() && groupVM.getHostId() != null) {
avoid.addHost(groupVM.getHostId());
}
}
}
}
@Override
public String getType() {
return "HostAntiAffinity";
}
}

View File

@ -40,4 +40,8 @@ public interface AffinityGroupVMMapDao extends GenericDao<AffinityGroupVMMapVO,
long countAffinityGroupsForVm(long instanceId); long countAffinityGroupsForVm(long instanceId);
int deleteVM(long instanceId); int deleteVM(long instanceId);
AffinityGroupVMMapVO findByVmIdType(long instanceId, String type);
void updateMap(Long vmId, List<Long> affinityGroupIds);
} }

View File

@ -19,17 +19,22 @@ package org.apache.cloudstack.affinity.dao;
import java.util.List; import java.util.List;
import javax.ejb.Local; import javax.ejb.Local;
import javax.inject.Inject;
import org.apache.cloudstack.affinity.AffinityGroupVMMapVO; import org.apache.cloudstack.affinity.AffinityGroupVMMapVO;
import org.apache.cloudstack.affinity.AffinityGroupVO;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.cloud.host.HostTagVO;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter; import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.JoinBuilder.JoinType;
import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Func; import com.cloud.utils.db.SearchCriteria.Func;
import com.cloud.utils.db.Transaction;
@Component @Component
@Local(value = { AffinityGroupVMMapDao.class }) @Local(value = { AffinityGroupVMMapDao.class })
@ -40,6 +45,10 @@ public class AffinityGroupVMMapDaoImpl extends GenericDaoBase<AffinityGroupVMMap
protected GenericSearchBuilder<AffinityGroupVMMapVO, Long> CountSGForVm; protected GenericSearchBuilder<AffinityGroupVMMapVO, Long> CountSGForVm;
private GenericSearchBuilder<AffinityGroupVMMapVO, Long> ListVmIdByAffinityGroup; private GenericSearchBuilder<AffinityGroupVMMapVO, Long> ListVmIdByAffinityGroup;
private SearchBuilder<AffinityGroupVMMapVO> ListByAffinityGroup; private SearchBuilder<AffinityGroupVMMapVO> ListByAffinityGroup;
private SearchBuilder<AffinityGroupVMMapVO> ListByVmIdType;
@Inject
protected AffinityGroupDao _affinityGroupDao;
protected AffinityGroupVMMapDaoImpl() { protected AffinityGroupVMMapDaoImpl() {
ListVmIdByAffinityGroup = createSearchBuilder(Long.class); ListVmIdByAffinityGroup = createSearchBuilder(Long.class);
@ -62,6 +71,14 @@ public class AffinityGroupVMMapDaoImpl extends GenericDaoBase<AffinityGroupVMMap
ListByVmIdGroupId.and("affinityGroupId", ListByVmIdGroupId.entity().getAffinityGroupId(), SearchCriteria.Op.EQ); ListByVmIdGroupId.and("affinityGroupId", ListByVmIdGroupId.entity().getAffinityGroupId(), SearchCriteria.Op.EQ);
ListByVmIdGroupId.done(); ListByVmIdGroupId.done();
ListByVmIdType = createSearchBuilder();
ListByVmIdType.and("instanceId", ListByVmIdType.entity().getInstanceId(), SearchCriteria.Op.EQ);
SearchBuilder<AffinityGroupVO> groupSearch = _affinityGroupDao.createSearchBuilder();
groupSearch.and("type", groupSearch.entity().getType(), SearchCriteria.Op.EQ);
ListByVmIdType.join("groupSearch", groupSearch, ListByVmIdType.entity().getAffinityGroupId(), groupSearch
.entity().getId(), JoinType.INNER);
ListByVmIdType.done();
CountSGForVm = createSearchBuilder(Long.class); CountSGForVm = createSearchBuilder(Long.class);
CountSGForVm.select(null, Func.COUNT, null); CountSGForVm.select(null, Func.COUNT, null);
CountSGForVm.and("vmId", CountSGForVm.entity().getInstanceId(), SearchCriteria.Op.EQ); CountSGForVm.and("vmId", CountSGForVm.entity().getInstanceId(), SearchCriteria.Op.EQ);
@ -117,4 +134,30 @@ public class AffinityGroupVMMapDaoImpl extends GenericDaoBase<AffinityGroupVMMap
sc.setParameters("vmId", instanceId); sc.setParameters("vmId", instanceId);
return customSearch(sc, null).get(0); return customSearch(sc, null).get(0);
} }
@Override
public AffinityGroupVMMapVO findByVmIdType(long instanceId, String type) {
SearchCriteria<AffinityGroupVMMapVO> sc = ListByVmIdType.create();
sc.setParameters("instanceId", instanceId);
sc.setJoinParameters("groupSearch", "type", type);
return customSearch(sc, null).get(0);
}
@Override
public void updateMap(Long vmId, List<Long> affinityGroupIds) {
Transaction txn = Transaction.currentTxn();
txn.start();
SearchCriteria<AffinityGroupVMMapVO> sc = createSearchCriteria();
sc.addAnd("instanceId", SearchCriteria.Op.EQ, vmId);
expunge(sc);
for (Long groupId : affinityGroupIds) {
AffinityGroupVMMapVO vo = new AffinityGroupVMMapVO(groupId, vmId);
persist(vo);
}
txn.commit();
}
} }

View File

@ -330,7 +330,9 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager,
@Override @Override
public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList, Account owner, public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList, Account owner,
String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps,
IpAddresses defaultIp, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, IpAddresses defaultIp,
String keyboard, List<Long> affinityGroupIdList) throws InsufficientCapacityException,
ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException,
ResourceAllocationException { ResourceAllocationException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return null; return null;
@ -339,7 +341,9 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager,
@Override @Override
public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList,
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData,
String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, String sshKeyPair, Map<Long, IpAddresses> requestedIps,
IpAddresses defaultIps, String keyboard, List<Long> affinityGroupIdList)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
StorageUnavailableException, ResourceAllocationException { StorageUnavailableException, ResourceAllocationException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return null; return null;
@ -348,7 +352,9 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager,
@Override @Override
public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner, String hostName, public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner, String hostName,
String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, String userData, String sshKeyPair, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps,
String keyboard) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException { String keyboard, List<Long> affinityGroupIdList) throws InsufficientCapacityException,
ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException,
ResourceAllocationException {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return null; return null;
} }

View File

@ -61,4 +61,5 @@ public interface SerialVersionUID {
public static final long CloudExecutionException = Base | 0x27; public static final long CloudExecutionException = Base | 0x27;
public static final long CallFailedException = Base | 0x28; public static final long CallFailedException = Base | 0x28;
public static final long UnableDeleteHostException = Base | 0x29; public static final long UnableDeleteHostException = Base | 0x29;
public static final long AffinityConflictException = Base | 0x2a;
} }