CLOUDSTACK-6276 Fixing affinity groups for projects

This commit is contained in:
Patrick Dube 2015-11-27 14:12:28 -05:00
parent 92913a154c
commit c76d317150
23 changed files with 1976 additions and 448 deletions

View File

@ -56,12 +56,20 @@ public class AffinityGroupResponse extends BaseResponse implements ControlledVie
@Param(description = "the domain name of the affinity group")
private String domainName;
@SerializedName(ApiConstants.PROJECT_ID)
@Param(description = "the project ID of the affinity group")
private String projectId;
@SerializedName(ApiConstants.PROJECT)
@Param(description = "the project name of the affinity group")
private String projectName;
@SerializedName(ApiConstants.TYPE)
@Param(description = "the type of the affinity group")
private String type;
@SerializedName("virtualmachineIds")
@Param(description = "virtual machine Ids associated with this affinity group ")
@Param(description = "virtual machine IDs associated with this affinity group")
private List<String> vmIdList;
public AffinityGroupResponse() {
@ -134,14 +142,12 @@ public class AffinityGroupResponse extends BaseResponse implements ControlledVie
@Override
public void setProjectId(String projectId) {
// TODO Auto-generated method stub
this.projectId = projectId;
}
@Override
public void setProjectName(String projectName) {
// TODO Auto-generated method stub
this.projectName = projectName;
}
public void setVMIdList(List<String> vmIdList) {

View File

@ -18,47 +18,36 @@ package org.apache.cloudstack.affinity;
import java.util.List;
import org.apache.cloudstack.api.command.user.affinitygroup.CreateAffinityGroupCmd;
import com.cloud.uservm.UserVm;
import com.cloud.utils.Pair;
public interface AffinityGroupService {
/**
* Creates an affinity/anti-affinity group for the given account/domain.
*
* @param account
* @param accountName
* @param projectId
* @param domainId
* @param name
* @param type
* @param affinityGroupName
* @param affinityGroupType
* @param description
* @return AffinityGroup
*/
AffinityGroup createAffinityGroup(String accountName, Long projectId, Long domainId, String affinityGroupName, String affinityGroupType, String description);
AffinityGroup createAffinityGroup(String account, Long domainId, String affinityGroupName, String affinityGroupType, String description);
AffinityGroup createAffinityGroup(CreateAffinityGroupCmd createAffinityGroupCmd);
/**
* Creates an affinity/anti-affinity group.
*
* @param affinityGroupId
* @param account
* @param accountName
* @param domainId
* @param affinityGroupName
*/
boolean deleteAffinityGroup(Long affinityGroupId, String account, Long domainId, String affinityGroupName);
/** Lists Affinity Groups in your account
* @param account
* @param domainId
* @param affinityGroupId
* @param affinityGroupName
* @param affinityGroupType
* @param vmId
* @param startIndex
* @param pageSize
* @return
*/
Pair<List<? extends AffinityGroup>, Integer> listAffinityGroups(Long affinityGroupId, String affinityGroupName, String affinityGroupType, Long vmId, Long startIndex,
Long pageSize);
boolean deleteAffinityGroup(Long affinityGroupId, String accountName, Long projectId, Long domainId, String affinityGroupName);
/**
* List group types available in deployment
@ -77,6 +66,5 @@ public interface AffinityGroupService {
boolean isAffinityGroupAvailableInDomain(long affinityGroupId, long domainId);
AffinityGroup createAffinityGroupInternal(String account, Long domainId, String affinityGroupName, String affinityGroupType, String description);
}

View File

@ -17,7 +17,6 @@
package org.apache.cloudstack.api.command.user.affinitygroup;
import org.apache.log4j.Logger;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
import org.apache.cloudstack.api.APICommand;
@ -28,6 +27,7 @@ import org.apache.cloudstack.api.BaseAsyncCreateCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.context.CallContext;
import com.cloud.event.EventTypes;
@ -54,6 +54,12 @@ public class CreateAffinityGroupCmd extends BaseAsyncCreateCmd {
entityType = DomainResponse.class)
private Long domainId;
@Parameter(name = ApiConstants.PROJECT_ID,
type = CommandType.UUID,
entityType = ProjectResponse.class,
description = "create affinity group for project")
private Long projectId;
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "optional description of the affinity group")
private String description;
@ -90,6 +96,10 @@ public class CreateAffinityGroupCmd extends BaseAsyncCreateCmd {
return affinityGroupType;
}
public Long getProjectId() {
return projectId;
}
// ///////////////////////////////////////////////////
// ///////////// API Implementation///////////////////
// ///////////////////////////////////////////////////
@ -101,23 +111,17 @@ public class CreateAffinityGroupCmd extends BaseAsyncCreateCmd {
@Override
public long getEntityOwnerId() {
Account account = CallContext.current().getCallingAccount();
if ((account == null) || _accountService.isAdmin(account.getId())) {
if ((domainId != null) && (accountName != null)) {
Account userAccount = _responseGenerator.findAccountByNameDomain(accountName, domainId);
if (userAccount != null) {
return userAccount.getId();
}
}
}
Account caller = CallContext.current().getCallingAccount();
if (account != null) {
return account.getId();
//For domain wide affinity groups (if the affinity group processor type allows it)
if(projectId == null && domainId != null && accountName == null && _accountService.isRootAdmin(caller.getId())){
return Account.ACCOUNT_ID_SYSTEM;
}
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this
// command to SYSTEM so ERROR events
// are tracked
Account owner = _accountService.finalizeOwner(caller, accountName, domainId, projectId);
if(owner == null){
return caller.getAccountId();
}
return owner.getAccountId();
}
@Override
@ -134,7 +138,7 @@ public class CreateAffinityGroupCmd extends BaseAsyncCreateCmd {
@Override
public void create() throws ResourceAllocationException {
AffinityGroup result = _affinityGroupService.createAffinityGroup(accountName, domainId, affinityGroupName, affinityGroupType, description);
AffinityGroup result = _affinityGroupService.createAffinityGroup(this);
if (result != null) {
setEntityId(result.getId());
setEntityUuid(result.getUuid());

View File

@ -17,8 +17,8 @@
package org.apache.cloudstack.api.command.user.affinitygroup;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.log4j.Logger;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
@ -35,7 +35,6 @@ import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.context.CallContext;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
@APICommand(name = "deleteAffinityGroup", description = "Deletes affinity group", responseObject = SuccessResponse.class, entityType = {AffinityGroup.class},
@ -67,6 +66,9 @@ public class DeleteAffinityGroupCmd extends BaseAsyncCmd {
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "The name of the affinity group. Mutually exclusive with ID parameter")
private String name;
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, description = "the project of the affinity group", entityType = ProjectResponse.class)
private Long projectId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -79,22 +81,11 @@ public class DeleteAffinityGroupCmd extends BaseAsyncCmd {
return domainId;
}
public Long getProjectId() {
return projectId;
}
public Long getId() {
if (id != null && name != null) {
throw new InvalidParameterValueException("name and id parameters are mutually exclusive");
}
if (name != null) {
id = _responseGenerator.getAffinityGroupId(name, getEntityOwnerId());
if (id == null) {
throw new InvalidParameterValueException("Unable to find affinity group by name " + name + " for the account ID=" + getEntityOwnerId());
}
}
if (id == null) {
throw new InvalidParameterValueException("Either ID or name parameter is required by deleteAffinityGroup command");
}
return id;
}
@ -109,29 +100,22 @@ public class DeleteAffinityGroupCmd extends BaseAsyncCmd {
@Override
public long getEntityOwnerId() {
Account account = CallContext.current().getCallingAccount();
if ((account == null) || _accountService.isAdmin(account.getId())) {
if ((domainId != null) && (accountName != null)) {
Account userAccount = _responseGenerator.findAccountByNameDomain(accountName, domainId);
if (userAccount != null) {
return userAccount.getId();
}
}
}
Account caller = CallContext.current().getCallingAccount();
if (account != null) {
return account.getId();
//For domain wide affinity groups (if the affinity group processor type allows it)
if(projectId == null && domainId != null && accountName == null && _accountService.isRootAdmin(caller.getId())){
return Account.ACCOUNT_ID_SYSTEM;
}
return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this
// command to SYSTEM so ERROR events
// are tracked
Account owner = _accountService.finalizeOwner(caller, accountName, domainId, projectId);
if(owner == null){
return caller.getAccountId();
}
return owner.getAccountId();
}
@Override
public void execute() {
boolean result = _affinityGroupService.deleteAffinityGroup(id, accountName, domainId, name);
boolean result = _affinityGroupService.deleteAffinityGroup(id, accountName, projectId, domainId, name);
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
setResponseObject(response);

View File

@ -23,14 +23,14 @@ import org.apache.cloudstack.affinity.AffinityGroupResponse;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandJobType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListAccountResourcesCmd;
import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
@APICommand(name = "listAffinityGroups", description = "Lists affinity groups", responseObject = AffinityGroupResponse.class, entityType = {AffinityGroup.class},
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class ListAffinityGroupsCmd extends BaseListAccountResourcesCmd {
public class ListAffinityGroupsCmd extends BaseListProjectAndAccountResourcesCmd {
public static final Logger s_logger = Logger.getLogger(ListAffinityGroupsCmd.class.getName());
private static final String s_name = "listaffinitygroupsresponse";
@ -69,6 +69,10 @@ public class ListAffinityGroupsCmd extends BaseListAccountResourcesCmd {
return id;
}
public String getAffinityGroupType() {
return affinityGroupType;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@ -80,13 +84,9 @@ public class ListAffinityGroupsCmd extends BaseListAccountResourcesCmd {
@Override
public void execute() {
ListResponse<AffinityGroupResponse> response = _queryService.listAffinityGroups(id, affinityGroupName,
affinityGroupType, virtualMachineId, getAccountName(), getDomainId(), isRecursive(),
listAll(), getStartIndex(), getPageSizeVal(), getKeyword());
ListResponse<AffinityGroupResponse> response = _queryService.searchForAffinityGroups(this);
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override

View File

@ -31,6 +31,7 @@ import org.apache.cloudstack.api.command.admin.storage.ListStorageTagsCmd;
import org.apache.cloudstack.api.command.admin.user.ListUsersCmd;
import org.apache.cloudstack.api.command.user.account.ListAccountsCmd;
import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd;
import org.apache.cloudstack.api.command.user.affinitygroup.ListAffinityGroupsCmd;
import org.apache.cloudstack.api.command.user.event.ListEventsCmd;
import org.apache.cloudstack.api.command.user.iso.ListIsosCmd;
import org.apache.cloudstack.api.command.user.job.ListAsyncJobsCmd;
@ -131,9 +132,7 @@ public interface QueryService {
ListResponse<TemplateResponse> listIsos(ListIsosCmd cmd);
ListResponse<AffinityGroupResponse> listAffinityGroups(Long affinityGroupId, String affinityGroupName,
String affinityGroupType, Long vmId, String accountName, Long domainId, boolean isRecursive,
boolean listAll, Long startIndex, Long pageSize, String keyword);
ListResponse<AffinityGroupResponse> searchForAffinityGroups(ListAffinityGroupsCmd cmd);
List<ResourceDetailResponse> listResourceDetails(ListResourceDetailsCmd cmd);
@ -142,5 +141,4 @@ public interface QueryService {
ListResponse<StorageTagResponse> searchForStorageTags(ListStorageTagsCmd cmd);
ListResponse<HostTagResponse> searchForHostTags(ListHostTagsCmd cmd);
}

View File

@ -192,7 +192,7 @@ public class VMEntityManagerImpl implements VMEntityManager {
try {
dest = _dpMgr.planDeployment(vmProfile, plan, exclude, plannerToUse);
} catch (AffinityConflictException e) {
throw new CloudRuntimeException("Unable to create deployment, affinity rules associted to the VM conflict");
throw new CloudRuntimeException("Unable to create deployment, affinity rules associated to the VM conflict");
}
if (dest != null) {

View File

@ -18,7 +18,6 @@ package org.apache.cloudstack.affinity.dao;
import java.util.List;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupVO;
import com.cloud.utils.db.GenericDao;
@ -34,9 +33,9 @@ public interface AffinityGroupDao extends GenericDao<AffinityGroupVO, Long> {
int removeByAccountId(long accountId);
AffinityGroup findDomainLevelGroupByName(Long domainId, String affinityGroupName);
AffinityGroupVO findDomainLevelGroupByName(Long domainId, String affinityGroupName);
AffinityGroup findByAccountAndType(Long accountId, String string);
AffinityGroupVO findByAccountAndType(Long accountId, String string);
AffinityGroup findDomainLevelGroupByType(Long domainId, String string);
AffinityGroupVO findDomainLevelGroupByType(Long domainId, String string);
}

View File

@ -23,7 +23,6 @@ import javax.ejb.Local;
import javax.inject.Inject;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO;
import org.apache.cloudstack.affinity.AffinityGroupVO;
@ -136,7 +135,7 @@ public class AffinityGroupDaoImpl extends GenericDaoBase<AffinityGroupVO, Long>
}
@Override
public AffinityGroup findDomainLevelGroupByName(Long domainId, String affinityGroupName) {
public AffinityGroupVO findDomainLevelGroupByName(Long domainId, String affinityGroupName) {
SearchCriteria<AffinityGroupVO> sc = DomainLevelNameSearch.create();
sc.setParameters("aclType", ControlledEntity.ACLType.Domain);
sc.setParameters("name", affinityGroupName);
@ -145,7 +144,7 @@ public class AffinityGroupDaoImpl extends GenericDaoBase<AffinityGroupVO, Long>
}
@Override
public AffinityGroup findByAccountAndType(Long accountId, String type) {
public AffinityGroupVO findByAccountAndType(Long accountId, String type) {
SearchCriteria<AffinityGroupVO> sc = AccountIdTypeSearch.create();
sc.setParameters("accountId", accountId);
sc.setParameters("type", type);
@ -154,7 +153,7 @@ public class AffinityGroupDaoImpl extends GenericDaoBase<AffinityGroupVO, Long>
}
@Override
public AffinityGroup findDomainLevelGroupByType(Long domainId, String type) {
public AffinityGroupVO findDomainLevelGroupByType(Long domainId, String type) {
SearchCriteria<AffinityGroupVO> sc = DomainLevelTypeSearch.create();
sc.setParameters("aclType", ControlledEntity.ACLType.Domain);
sc.setParameters("type", type);

View File

@ -639,7 +639,7 @@ public class DedicatedResourceManagerImpl implements DedicatedService {
affinityGroupName = "DedicatedGrp-domain-" + domainName;
}
group = _affinityGroupService.createAffinityGroupInternal(accountName, domainId, affinityGroupName, "ExplicitDedication", "dedicated resources group");
group = _affinityGroupService.createAffinityGroup(accountName, null, domainId, affinityGroupName, "ExplicitDedication", "dedicated resources group");
return group;
@ -948,7 +948,7 @@ public class DedicatedResourceManagerImpl implements DedicatedService {
List<DedicatedResourceVO> resourcesInGroup = _dedicatedDao.listByAffinityGroupId(resource.getAffinityGroupId());
if (resourcesInGroup.isEmpty()) {
// delete the group
_affinityGroupService.deleteAffinityGroup(resource.getAffinityGroupId(), null, null, null);
_affinityGroupService.deleteAffinityGroup(resource.getAffinityGroupId(), null, null, null, null);
}
}

View File

@ -389,7 +389,7 @@ public class IntegrationTestConfiguration {
}
});
Mockito.when(
mock.createAffinityGroupInternal(Matchers.any(String.class), Matchers.any(Long.class), Matchers.any(String.class), Matchers.any(String.class),
mock.createAffinityGroup(Matchers.any(String.class), Matchers.any(Long.class), Matchers.any(Long.class), Matchers.any(String.class), Matchers.any(String.class),
Matchers.any(String.class))).thenReturn(gmock);
} catch (Exception e) {
e.printStackTrace();

View File

@ -19,17 +19,19 @@ package com.cloud.acl;
import javax.ejb.Local;
import javax.inject.Inject;
import org.springframework.stereotype.Component;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupService;
import org.apache.cloudstack.affinity.dao.AffinityGroupDomainMapDao;
import org.springframework.stereotype.Component;
import com.cloud.domain.DomainVO;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.projects.ProjectVO;
import com.cloud.projects.dao.ProjectAccountDao;
import com.cloud.projects.dao.ProjectDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.utils.exception.CloudRuntimeException;
@ -44,6 +46,10 @@ public class AffinityGroupAccessChecker extends DomainChecker {
AccountManager _accountMgr;
@Inject
AffinityGroupDomainMapDao _affinityGroupDomainMapDao;
@Inject
ProjectDao _projectDao;
@Inject
ProjectAccountDao _projectAccountDao;
@Override
public boolean checkAccess(Account caller, ControlledEntity entity, AccessType accessType) throws PermissionDeniedException {
@ -51,8 +57,7 @@ public class AffinityGroupAccessChecker extends DomainChecker {
AffinityGroup group = (AffinityGroup)entity;
if (_affinityGroupService.isAdminControlledGroup(group)) {
if (accessType != null && accessType == AccessType.OperateEntry
&& !_accountMgr.isRootAdmin(caller.getId())) {
if (accessType == AccessType.OperateEntry && !_accountMgr.isRootAdmin(caller.getId())) {
throw new PermissionDeniedException(caller + " does not have permission to operate with resource "
+ entity);
}
@ -72,6 +77,15 @@ public class AffinityGroupAccessChecker extends DomainChecker {
} else {
//acl_type account
if (caller.getId() != group.getAccountId()) {
//check if the group belongs to a project
ProjectVO project = _projectDao.findByProjectAccountId(group.getAccountId());
if (project != null) {
if (AccessType.ModifyProject.equals(accessType) && _projectAccountDao.canModifyProjectAccount(caller.getId(), group.getAccountId())) {
return true;
} else if (!AccessType.ModifyProject.equals(accessType) && _projectAccountDao.canAccessProjectAccount(caller.getId(), group.getAccountId())) {
return true;
}
}
throw new PermissionDeniedException(caller + " does not have permission to operate with resource " + entity);
} else {
return true;

View File

@ -26,9 +26,6 @@ import java.util.Set;
import javax.ejb.Local;
import javax.inject.Inject;
import com.cloud.utils.StringUtils;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.dao.VMInstanceDao;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
@ -57,6 +54,7 @@ import org.apache.cloudstack.api.command.admin.volume.ListVolumesCmdByAdmin;
import org.apache.cloudstack.api.command.admin.zone.ListZonesCmdByAdmin;
import org.apache.cloudstack.api.command.user.account.ListAccountsCmd;
import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd;
import org.apache.cloudstack.api.command.user.affinitygroup.ListAffinityGroupsCmd;
import org.apache.cloudstack.api.command.user.event.ListEventsCmd;
import org.apache.cloudstack.api.command.user.iso.ListIsosCmd;
import org.apache.cloudstack.api.command.user.job.ListAsyncJobsCmd;
@ -196,7 +194,6 @@ import com.cloud.storage.Storage.TemplateType;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VolumeDetailsDao;
import com.cloud.tags.ResourceTagVO;
import com.cloud.tags.dao.ResourceTagDao;
import com.cloud.template.VirtualMachineTemplate.State;
@ -207,6 +204,7 @@ import com.cloud.user.DomainManager;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.DateUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils;
import com.cloud.utils.Ternary;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.Filter;
@ -217,11 +215,12 @@ import com.cloud.utils.db.SearchCriteria.Func;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.vm.DomainRouterVO;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.NicDetailsDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.UserVmDetailsDao;
import com.cloud.vm.dao.VMInstanceDao;
@Component
@Local(value = {QueryService.class})
@ -229,6 +228,8 @@ public class QueryManagerImpl extends ManagerBase implements QueryService, Confi
public static final Logger s_logger = Logger.getLogger(QueryManagerImpl.class);
private static final String ID_FIELD = "id";
@Inject
private AccountManager _accountMgr;
@ -331,12 +332,6 @@ public class QueryManagerImpl extends ManagerBase implements QueryService, Confi
@Inject
private DomainRouterDao _routerDao;
@Inject
private VolumeDetailsDao _volumeDetailDao;
@Inject
private NicDetailsDao _nicDetailDao;
@Inject
UserVmDetailsDao _userVmDetailDao;
@ -375,11 +370,11 @@ public class QueryManagerImpl extends ManagerBase implements QueryService, Confi
@Inject
AffinityGroupDomainMapDao _affinityGroupDomainMapDao;
@Inject NetworkDetailsDao _networkDetailsDao;
@Inject
ResourceTagDao _resourceTagDao;
@Inject
DataStoreManager dataStoreManager;
@ -3395,55 +3390,60 @@ public class QueryManagerImpl extends ManagerBase implements QueryService, Confi
cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedISO);
}
@Override
public ListResponse<AffinityGroupResponse> listAffinityGroups(Long affinityGroupId, String affinityGroupName,
String affinityGroupType, Long vmId, String accountName, Long domainId, boolean isRecursive,
boolean listAll, Long startIndex, Long pageSize, String keyword) {
Pair<List<AffinityGroupJoinVO>, Integer> result = listAffinityGroupsInternal(affinityGroupId,
affinityGroupName, affinityGroupType, vmId, accountName, domainId, isRecursive, listAll, startIndex,
pageSize, keyword);
public ListResponse<AffinityGroupResponse> searchForAffinityGroups(ListAffinityGroupsCmd cmd) {
Pair<List<AffinityGroupJoinVO>, Integer> result = searchForAffinityGroupsInternal(cmd);
ListResponse<AffinityGroupResponse> response = new ListResponse<AffinityGroupResponse>();
List<AffinityGroupResponse> agResponses = ViewResponseHelper.createAffinityGroupResponses(result.first());
response.setResponses(agResponses, result.second());
return response;
}
public Pair<List<AffinityGroupJoinVO>, Integer> listAffinityGroupsInternal(Long affinityGroupId,
String affinityGroupName, String affinityGroupType, Long vmId, String accountName, Long domainId,
boolean isRecursive, boolean listAll, Long startIndex, Long pageSize, String keyword) {
public Pair<List<AffinityGroupJoinVO>, Integer> searchForAffinityGroupsInternal(ListAffinityGroupsCmd cmd) {
final Long affinityGroupId = cmd.getId();
final String affinityGroupName = cmd.getAffinityGroupName();
final String affinityGroupType = cmd.getAffinityGroupType();
final Long vmId = cmd.getVirtualMachineId();
final String accountName = cmd.getAccountName();
Long domainId = cmd.getDomainId();
final Long projectId = cmd.getProjectId();
Boolean isRecursive = cmd.isRecursive();
final Boolean listAll = cmd.listAll();
final Long startIndex = cmd.getStartIndex();
final Long pageSize = cmd.getPageSizeVal();
final String keyword = cmd.getKeyword();
Account caller = CallContext.current().getCallingAccount();
caller.getAccountId();
if (vmId != null) {
UserVmVO userVM = _userVmDao.findById(vmId);
if (userVM == null) {
throw new InvalidParameterValueException("Unable to list affinity groups for virtual machine instance "
+ vmId + "; instance not found.");
throw new InvalidParameterValueException("Unable to list affinity groups for virtual machine instance " + vmId + "; instance not found.");
}
_accountMgr.checkAccess(caller, null, true, userVM);
return listAffinityGroupsByVM(vmId.longValue(), startIndex, pageSize);
}
List<Long> permittedAccounts = new ArrayList<Long>();
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(
domainId, isRecursive, null);
_accountMgr.buildACLSearchParameters(caller, affinityGroupId, accountName, null, permittedAccounts,
domainIdRecursiveListProject, listAll, true);
domainId = domainIdRecursiveListProject.first();
isRecursive = domainIdRecursiveListProject.second();
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
Ternary<Long, Boolean, ListProjectResourcesCriteria> ternary = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(domainId, isRecursive, null);
Filter searchFilter = new Filter(AffinityGroupJoinVO.class, "id", true, startIndex, pageSize);
SearchCriteria<AffinityGroupJoinVO> sc = buildAffinityGroupSearchCriteria(domainId, isRecursive,
permittedAccounts, listProjectResourcesCriteria, affinityGroupId, affinityGroupName, affinityGroupType, keyword);
_accountMgr.buildACLSearchParameters(caller, affinityGroupId, accountName, projectId, permittedAccounts, ternary, listAll, false);
domainId = ternary.first();
isRecursive = ternary.second();
ListProjectResourcesCriteria listProjectResourcesCriteria = ternary.third();
Filter searchFilter = new Filter(AffinityGroupJoinVO.class, ID_FIELD, true, startIndex, pageSize);
SearchCriteria<AffinityGroupJoinVO> sc = buildAffinityGroupSearchCriteria(domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria, affinityGroupId,
affinityGroupName, affinityGroupType, keyword);
Pair<List<AffinityGroupJoinVO>, Integer> uniqueGroupsPair = _affinityGroupJoinDao.searchAndCount(sc, searchFilter);
Pair<List<AffinityGroupJoinVO>, Integer> uniqueGroupsPair = _affinityGroupJoinDao.searchAndCount(sc,
searchFilter);
// search group details by ids
List<AffinityGroupJoinVO> vrs = new ArrayList<AffinityGroupJoinVO>();
List<AffinityGroupJoinVO> affinityGroups = new ArrayList<AffinityGroupJoinVO>();
Integer count = uniqueGroupsPair.second();
if (count.intValue() != 0) {
List<AffinityGroupJoinVO> uniqueGroups = uniqueGroupsPair.first();
@ -3452,36 +3452,33 @@ public class QueryManagerImpl extends ManagerBase implements QueryService, Confi
for (AffinityGroupJoinVO v : uniqueGroups) {
vrIds[i++] = v.getId();
}
vrs = _affinityGroupJoinDao.searchByIds(vrIds);
affinityGroups = _affinityGroupJoinDao.searchByIds(vrIds);
}
if (!permittedAccounts.isEmpty()) {
// add domain level affinity groups
if (domainId != null) {
SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(null, isRecursive,
new ArrayList<Long>(), listProjectResourcesCriteria, affinityGroupId, affinityGroupName,
affinityGroupType, keyword);
vrs.addAll(listDomainLevelAffinityGroups(scDomain, searchFilter, domainId));
SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(null, isRecursive, new ArrayList<Long>(), listProjectResourcesCriteria,
affinityGroupId, affinityGroupName, affinityGroupType, keyword);
affinityGroups.addAll(listDomainLevelAffinityGroups(scDomain, searchFilter, domainId));
} else {
for (Long permAcctId : permittedAccounts) {
Account permittedAcct = _accountDao.findById(permAcctId);
SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(
null, isRecursive, new ArrayList<Long>(),
listProjectResourcesCriteria, affinityGroupId, affinityGroupName, affinityGroupType, keyword);
SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(null, isRecursive, new ArrayList<Long>(), listProjectResourcesCriteria,
affinityGroupId, affinityGroupName, affinityGroupType, keyword);
vrs.addAll(listDomainLevelAffinityGroups(scDomain, searchFilter, permittedAcct.getDomainId()));
affinityGroups.addAll(listDomainLevelAffinityGroups(scDomain, searchFilter, permittedAcct.getDomainId()));
}
}
} else if (((permittedAccounts.isEmpty()) && (domainId != null) && isRecursive)) {
// list all domain level affinity groups for the domain admin case
SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(null, isRecursive,
new ArrayList<Long>(), listProjectResourcesCriteria, affinityGroupId, affinityGroupName,
affinityGroupType, keyword);
vrs.addAll(listDomainLevelAffinityGroups(scDomain, searchFilter, domainId));
SearchCriteria<AffinityGroupJoinVO> scDomain = buildAffinityGroupSearchCriteria(null, isRecursive, new ArrayList<Long>(), listProjectResourcesCriteria,
affinityGroupId, affinityGroupName, affinityGroupType, keyword);
affinityGroups.addAll(listDomainLevelAffinityGroups(scDomain, searchFilter, domainId));
}
return new Pair<List<AffinityGroupJoinVO>, Integer>(vrs, vrs.size());
return new Pair<List<AffinityGroupJoinVO>, Integer>(affinityGroups, affinityGroups.size());
}
@ -3526,9 +3523,8 @@ public class QueryManagerImpl extends ManagerBase implements QueryService, Confi
}
}
private SearchCriteria<AffinityGroupJoinVO> buildAffinityGroupSearchCriteria(Long domainId, boolean isRecursive,
List<Long> permittedAccounts, ListProjectResourcesCriteria listProjectResourcesCriteria,
Long affinityGroupId, String affinityGroupName, String affinityGroupType, String keyword) {
private SearchCriteria<AffinityGroupJoinVO> buildAffinityGroupSearchCriteria(Long domainId, boolean isRecursive, List<Long> permittedAccounts,
ListProjectResourcesCriteria listProjectResourcesCriteria, Long affinityGroupId, String affinityGroupName, String affinityGroupType, String keyword) {
SearchBuilder<AffinityGroupJoinVO> groupSearch = _affinityGroupJoinDao.createSearchBuilder();
buildAffinityGroupViewSearchBuilder(groupSearch, domainId, isRecursive, permittedAccounts,
@ -3538,8 +3534,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService, Confi
// distinct
SearchCriteria<AffinityGroupJoinVO> sc = groupSearch.create();
buildAffinityGroupViewSearchCriteria(sc, domainId, isRecursive, permittedAccounts,
listProjectResourcesCriteria);
buildAffinityGroupViewSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
if (affinityGroupId != null) {
sc.addAnd("id", SearchCriteria.Op.EQ, affinityGroupId);

View File

@ -72,6 +72,15 @@ public class AffinityGroupJoinVO extends BaseViewVO implements ControlledViewEnt
@Column(name = "domain_path")
private String domainPath = null;
@Column(name = "project_id")
private long projectId;
@Column(name = "project_uuid")
private String projectUuid;
@Column(name = "project_name")
private String projectName;
@Column(name = "vm_id")
private long vmId;
@ -153,6 +162,20 @@ public class AffinityGroupJoinVO extends BaseViewVO implements ControlledViewEnt
return domainPath;
}
public long getProjectId() {
return projectId;
}
@Override
public String getProjectUuid() {
return projectUuid;
}
@Override
public String getProjectName() {
return projectName;
}
public String getDescription() {
return description;
}
@ -177,18 +200,6 @@ public class AffinityGroupJoinVO extends BaseViewVO implements ControlledViewEnt
return vmState;
}
@Override
public String getProjectUuid() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getProjectName() {
// TODO Auto-generated method stub
return null;
}
public ControlledEntity.ACLType getAclType() {
return aclType;
}

View File

@ -1484,7 +1484,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
final List<DedicatedResourceVO> resourcesInGroup = _dedicatedDao.listByAffinityGroupId(dr.getAffinityGroupId());
if (resourcesInGroup.isEmpty()) {
// delete the group
_affinityGroupService.deleteAffinityGroup(dr.getAffinityGroupId(), null, null, null);
_affinityGroupService.deleteAffinityGroup(dr.getAffinityGroupId(), null, null, null, null);
}
}
}
@ -1702,7 +1702,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
final List<DedicatedResourceVO> resourcesInGroup = _dedicatedDao.listByAffinityGroupId(resource.getAffinityGroupId());
if (resourcesInGroup.isEmpty()) {
// delete the group
_affinityGroupService.deleteAffinityGroup(resource.getAffinityGroupId(), null, null, null);
_affinityGroupService.deleteAffinityGroup(resource.getAffinityGroupId(), null, null, null, null);
}
}
}
@ -1800,7 +1800,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
}
}
group = _affinityGroupService.createAffinityGroupInternal(accountName, domainId, affinityGroupName, "ExplicitDedication", "dedicated resources group");
group = _affinityGroupService.createAffinityGroup(accountName, null, domainId, affinityGroupName, "ExplicitDedication", "dedicated resources group");
return group;

View File

@ -2406,98 +2406,10 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
}
}
// @Override
// public void buildACLSearchParameters(Account caller, Long id, String accountName, Long projectId, List<Long>
// permittedAccounts, Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject,
// boolean listAll, boolean forProjectInvitation) {
// Long domainId = domainIdRecursiveListProject.first();
// if (domainId != null) {
// Domain domain = _domainDao.findById(domainId);
// if (domain == null) {
// throw new InvalidParameterValueException("Unable to find domain by id " + domainId);
// }
// // check permissions
// checkAccess(caller, domain);
// }
//
// if (accountName != null) {
// if (projectId != null) {
// throw new InvalidParameterValueException("Account and projectId can't be specified together");
// }
//
// Account userAccount = null;
// Domain domain = null;
// if (domainId != null) {
// userAccount = _accountDao.findActiveAccount(accountName, domainId);
// domain = _domainDao.findById(domainId);
// } else {
// userAccount = _accountDao.findActiveAccount(accountName, caller.getDomainId());
// domain = _domainDao.findById(caller.getDomainId());
// }
//
// if (userAccount != null) {
// checkAccess(caller, null, false, userAccount);
// //check permissions
// permittedAccounts.add(userAccount.getId());
// } else {
// throw new InvalidParameterValueException("could not find account " + accountName + " in domain " + domain.getUuid());
// }
// }
//
// // set project information
// if (projectId != null) {
// if (!forProjectInvitation) {
// if (projectId.longValue() == -1) {
// if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL) {
// permittedAccounts.addAll(_projectMgr.listPermittedProjectAccounts(caller.getId()));
// } else {
// domainIdRecursiveListProject.third(Project.ListProjectResourcesCriteria.ListProjectResourcesOnly);
// }
// } else {
// Project project = _projectMgr.getProject(projectId);
// if (project == null) {
// throw new InvalidParameterValueException("Unable to find project by id " + projectId);
// }
// if (!_projectMgr.canAccessProjectAccount(caller, project.getProjectAccountId())) {
// throw new PermissionDeniedException("Account " + caller + " can't access project id=" + projectId);
// }
// permittedAccounts.add(project.getProjectAccountId());
// }
// }
// } else {
// if (id == null) {
// domainIdRecursiveListProject.third(Project.ListProjectResourcesCriteria.SkipProjectResources);
// }
// if (permittedAccounts.isEmpty() && domainId == null) {
// if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL) {
// permittedAccounts.add(caller.getId());
// } else if (!listAll) {
// if (id == null) {
// permittedAccounts.add(caller.getId());
// } else if (!isRootAdmin(caller.getId())) {
// domainIdRecursiveListProject.first(caller.getDomainId());
// domainIdRecursiveListProject.second(true);
// }
// } else if (domainId == null) {
// if (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) {
// domainIdRecursiveListProject.first(caller.getDomainId());
// domainIdRecursiveListProject.second(true);
// }
// }
// } else if (domainId != null) {
// if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL) {
// permittedAccounts.add(caller.getId());
// }
// }
//
// }
// }
//TODO: deprecate this to use the new buildACLSearchParameters with permittedDomains, permittedAccounts, and permittedResources as return
@Override
public void buildACLSearchParameters(Account caller, Long id, String accountName, Long projectId, List<Long>
permittedAccounts, Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject,
boolean listAll, boolean forProjectInvitation) {
public void buildACLSearchParameters(Account caller, Long id, String accountName, Long projectId, List<Long> permittedAccounts,
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject, boolean listAll, boolean forProjectInvitation) {
Long domainId = domainIdRecursiveListProject.first();
if (domainId != null) {
Domain domain = _domainDao.findById(domainId);

View File

@ -27,8 +27,8 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.utils.fsm.StateMachine2;
import org.apache.log4j.Logger;
import org.apache.log4j.Logger;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
@ -36,6 +36,7 @@ import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.affinity.dao.AffinityGroupDomainMapDao;
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.command.user.affinitygroup.CreateAffinityGroupCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.messagebus.MessageBus;
import org.apache.cloudstack.framework.messagebus.PublishScope;
@ -55,8 +56,6 @@ import com.cloud.utils.component.Manager;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.EntityManager;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
@ -113,48 +112,29 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
@DB
@Override
@ActionEvent(eventType = EventTypes.EVENT_AFFINITY_GROUP_CREATE, eventDescription = "Creating Affinity Group", create = true)
public AffinityGroup createAffinityGroup(String account, Long domainId, String affinityGroupName, String affinityGroupType, String description) {
Account caller = CallContext.current().getCallingAccount();
//validate the affinityGroupType
Map<String, AffinityGroupProcessor> typeProcessorMap = getAffinityTypeToProcessorMap();
if (typeProcessorMap != null && !typeProcessorMap.isEmpty()) {
if (!typeProcessorMap.containsKey(affinityGroupType)) {
throw new InvalidParameterValueException("Unable to create affinity group, invalid affinity group type" + affinityGroupType);
public AffinityGroup createAffinityGroup(CreateAffinityGroupCmd createAffinityGroupCmd) {
return createAffinityGroup(createAffinityGroupCmd.getAccountName(), createAffinityGroupCmd.getProjectId(), createAffinityGroupCmd.getDomainId(), createAffinityGroupCmd.getAffinityGroupName(), createAffinityGroupCmd.getAffinityGroupType(), createAffinityGroupCmd.getDescription());
}
} else {
@DB
@Override
public AffinityGroup createAffinityGroup(final String accountName, final Long projectId, final Long domainId, final String affinityGroupName, final String affinityGroupType,
final String description) {
// validate the affinityGroupType
Map<String, AffinityGroupProcessor> typeProcessorMap = getAffinityTypeToProcessorMap();
if (typeProcessorMap == null || typeProcessorMap.isEmpty()) {
throw new InvalidParameterValueException("Unable to create affinity group, no Affinity Group Types configured");
}
AffinityGroupProcessor processor = typeProcessorMap.get(affinityGroupType);
if (processor.isAdminControlledGroup()) {
throw new PermissionDeniedException("Cannot create the affinity group");
}
return createAffinityGroupInternal(account, domainId, affinityGroupName, affinityGroupType, description);
}
@DB
@Override
public AffinityGroup createAffinityGroupInternal(String account, final Long domainId, final String affinityGroupName, final String affinityGroupType,
final String description) {
Account caller = CallContext.current().getCallingAccount();
// validate the affinityGroupType
Map<String, AffinityGroupProcessor> typeProcessorMap = getAffinityTypeToProcessorMap();
if (typeProcessorMap != null && !typeProcessorMap.isEmpty()) {
if (!typeProcessorMap.containsKey(affinityGroupType)) {
if(processor == null){
throw new InvalidParameterValueException("Unable to create affinity group, invalid affinity group type" + affinityGroupType);
}
} else {
throw new InvalidParameterValueException("Unable to create affinity group, no Affinity Group Types configured");
}
final AffinityGroupProcessor processor = typeProcessorMap.get(affinityGroupType);
Account caller = CallContext.current().getCallingAccount();
if (processor.isAdminControlledGroup() && !_accountMgr.isRootAdmin(caller.getId())) {
throw new PermissionDeniedException("Cannot create the affinity group");
}
@ -163,72 +143,24 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
Account owner = null;
boolean domainLevel = false;
if (account != null && domainId != null) {
owner = _accountMgr.finalizeOwner(caller, account, domainId, null);
aclType = ControlledEntity.ACLType.Account;
} else if (domainId != null && account == null) {
if (!_accountMgr.isRootAdmin(caller.getId())) {
// non root admin need to pass both account and domain
throw new InvalidParameterValueException("Unable to create affinity group, account name must be passed with the domainId");
} else if (!processor.canBeSharedDomainWide()) {
// cannot be domain level
throw new InvalidParameterValueException("Unable to create affinity group, account name is needed");
}
DomainVO domain = _domainDao.findById(domainId);
if (domain == null) {
throw new InvalidParameterValueException("Unable to find domain by specified id");
}
if (projectId == null && domainId != null && accountName == null) {
verifyAccessToDomainWideProcessor(caller, processor);
DomainVO domain = getDomain(domainId);
_accountMgr.checkAccess(caller, domain);
// domain level group, owner is SYSTEM.
owner = _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM);
aclType = ControlledEntity.ACLType.Domain;
domainLevel = true;
} else {
owner = caller;
owner = _accountMgr.finalizeOwner(caller, accountName, domainId, projectId);
aclType = ControlledEntity.ACLType.Account;
}
if (_affinityGroupDao.isNameInUse(owner.getAccountId(), owner.getDomainId(), affinityGroupName)) {
throw new InvalidParameterValueException("Unable to create affinity group, a group with name " + affinityGroupName + " already exists.");
}
if (domainLevel && _affinityGroupDao.findDomainLevelGroupByName(domainId, affinityGroupName) != null) {
throw new InvalidParameterValueException("Unable to create affinity group, a group with name " + affinityGroupName + " already exists under the domain.");
}
verifyAffinityGroupNameInUse(owner.getAccountId(), owner.getDomainId(), affinityGroupName);
verifyDomainLevelAffinityGroupName(domainLevel, owner.getDomainId(), affinityGroupName);
final Account ownerFinal = owner;
final ControlledEntity.ACLType aclTypeFinal = aclType;
AffinityGroupVO group = Transaction.execute(new TransactionCallback<AffinityGroupVO>() {
@Override
public AffinityGroupVO doInTransaction(TransactionStatus status) {
AffinityGroupVO group =
new AffinityGroupVO(affinityGroupName, affinityGroupType, description, ownerFinal.getDomainId(), ownerFinal.getId(), aclTypeFinal);
_affinityGroupDao.persist(group);
if (domainId != null && aclTypeFinal == ACLType.Domain) {
boolean subDomainAccess = false;
subDomainAccess = processor.subDomainAccess();
AffinityGroupDomainMapVO domainMap = new AffinityGroupDomainMapVO(group.getId(), domainId,
subDomainAccess);
_affinityGroupDomainMapDao.persist(domainMap);
//send event for storing the domain wide resource access
Map<String, Object> params = new HashMap<String, Object>();
params.put(ApiConstants.ENTITY_TYPE, AffinityGroup.class);
params.put(ApiConstants.ENTITY_ID, group.getId());
params.put(ApiConstants.DOMAIN_ID, domainId);
params.put(ApiConstants.SUBDOMAIN_ACCESS, subDomainAccess);
_messageBus.publish(_name, EntityManager.MESSAGE_ADD_DOMAIN_WIDE_ENTITY_EVENT, PublishScope.LOCAL,
params);
}
return group;
}
});
AffinityGroupVO group = createAffinityGroup(processor, owner, aclType, affinityGroupName, affinityGroupType, description);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Created affinity group =" + affinityGroupName);
@ -237,51 +169,135 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
return group;
}
@DB
private void verifyAccessToDomainWideProcessor(Account caller, AffinityGroupProcessor processor) {
if (!_accountMgr.isRootAdmin(caller.getId())) {
throw new InvalidParameterValueException("Unable to create affinity group, account name must be passed with the domainId");
}
if (!processor.canBeSharedDomainWide()) {
throw new InvalidParameterValueException("Unable to create affinity group, account name is needed. Affinity group type "+ processor.getType() +" cannot be shared domain wide");
}
}
private AffinityGroupVO createAffinityGroup(final AffinityGroupProcessor processor, final Account owner, final ACLType aclType, final String affinityGroupName, final String affinityGroupType, final String description) {
return Transaction.execute(new TransactionCallback<AffinityGroupVO>() {
@Override
public AffinityGroupVO doInTransaction(TransactionStatus status) {
AffinityGroupVO group =
new AffinityGroupVO(affinityGroupName, affinityGroupType, description, owner.getDomainId(), owner.getId(), aclType);
_affinityGroupDao.persist(group);
if (aclType == ACLType.Domain) {
boolean subDomainAccess = false;
subDomainAccess = processor.subDomainAccess();
AffinityGroupDomainMapVO domainMap = new AffinityGroupDomainMapVO(group.getId(), owner.getDomainId(),
subDomainAccess);
_affinityGroupDomainMapDao.persist(domainMap);
//send event for storing the domain wide resource access
Map<String, Object> params = new HashMap<String, Object>();
params.put(ApiConstants.ENTITY_TYPE, AffinityGroup.class);
params.put(ApiConstants.ENTITY_ID, group.getId());
params.put(ApiConstants.DOMAIN_ID, owner.getDomainId());
params.put(ApiConstants.SUBDOMAIN_ACCESS, subDomainAccess);
_messageBus.publish(_name, EntityManager.MESSAGE_ADD_DOMAIN_WIDE_ENTITY_EVENT, PublishScope.LOCAL,
params);
}
return group;
}
});
}
private DomainVO getDomain(Long domainId) {
DomainVO domain = _domainDao.findById(domainId);
if (domain == null) {
throw new InvalidParameterValueException("Unable to find domain by specified id");
}
return domain;
}
private void verifyAffinityGroupNameInUse(long accountId, long domainId, String affinityGroupName) {
if (_affinityGroupDao.isNameInUse(accountId, domainId, affinityGroupName)) {
throw new InvalidParameterValueException("Unable to create affinity group, a group with name " + affinityGroupName + " already exists.");
}
}
private void verifyDomainLevelAffinityGroupName(boolean domainLevel, long domainId, String affinityGroupName) {
if (domainLevel && _affinityGroupDao.findDomainLevelGroupByName(domainId, affinityGroupName) != null) {
throw new InvalidParameterValueException("Unable to create affinity group, a group with name " + affinityGroupName + " already exists under the domain.");
}
}
@DB
@ActionEvent(eventType = EventTypes.EVENT_AFFINITY_GROUP_DELETE, eventDescription = "Deleting affinity group")
public boolean deleteAffinityGroup(Long affinityGroupId, String account, Long domainId, String affinityGroupName) {
public boolean deleteAffinityGroup(Long affinityGroupId, String account, Long projectId, Long domainId, String affinityGroupName) {
AffinityGroupVO group = getAffinityGroup(affinityGroupId, account, projectId, domainId, affinityGroupName);
// check permissions
Account caller = CallContext.current().getCallingAccount();
Account owner = _accountMgr.finalizeOwner(caller, account, domainId, null);
_accountMgr.checkAccess(caller, AccessType.OperateEntry, true, group);
final Long affinityGroupIdFinal = group.getId();
deleteAffinityGroup(affinityGroupIdFinal);
// remove its related ACL permission
Pair<Class<?>, Long> params = new Pair<Class<?>, Long>(AffinityGroup.class, affinityGroupIdFinal);
_messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, params);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Deleted affinity group id=" + affinityGroupIdFinal);
}
return true;
}
private AffinityGroupVO getAffinityGroup(Long affinityGroupId, String account, Long projectId, Long domainId, String affinityGroupName) {
AffinityGroupVO group = null;
if (affinityGroupId != null) {
group = _affinityGroupDao.findById(affinityGroupId);
if (group == null) {
throw new InvalidParameterValueException("Unable to find affinity group: " + affinityGroupId + "; failed to delete group.");
}
} else if (affinityGroupName != null) {
group = _affinityGroupDao.findByAccountAndName(owner.getAccountId(), affinityGroupName);
if (group == null) {
throw new InvalidParameterValueException("Unable to find affinity group: " + affinityGroupName + "; failed to delete group.");
}
group = getAffinityGroupByName(account, projectId, domainId, affinityGroupName);
} else {
throw new InvalidParameterValueException("Either the affinity group Id or group name must be specified to delete the group");
}
if (affinityGroupId == null) {
affinityGroupId = group.getId();
if (group == null) {
throw new InvalidParameterValueException("Unable to find affinity group " + (affinityGroupId == null ? affinityGroupName : affinityGroupId));
}
return group;
}
// check permissions
_accountMgr.checkAccess(caller, AccessType.OperateEntry, true, group);
final Long affinityGroupIdFinal = affinityGroupId;
private AffinityGroupVO getAffinityGroupByName(String account, Long projectId, Long domainId, String affinityGroupName) {
AffinityGroupVO group = null;
if(account == null && domainId != null){
group = _affinityGroupDao.findDomainLevelGroupByName(domainId, affinityGroupName);
}else{
Long accountId = _accountMgr.finalyzeAccountId(account, domainId, projectId, true);
if(accountId == null){
Account caller = CallContext.current().getCallingAccount();
group = _affinityGroupDao.findByAccountAndName(caller.getAccountId(), affinityGroupName);
}else{
group = _affinityGroupDao.findByAccountAndName(accountId, affinityGroupName);
}
}
return group;
}
private void deleteAffinityGroup(final Long affinityGroupId) {
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
AffinityGroupVO group = _affinityGroupDao.lockRow(affinityGroupIdFinal, true);
AffinityGroupVO group = _affinityGroupDao.lockRow(affinityGroupId, true);
if (group == null) {
throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupIdFinal);
throw new InvalidParameterValueException("Unable to find affinity group by id " + affinityGroupId);
}
List<AffinityGroupVMMapVO> affinityGroupVmMap = _affinityGroupVMMapDao.listByAffinityGroup(affinityGroupIdFinal);
List<AffinityGroupVMMapVO> affinityGroupVmMap = _affinityGroupVMMapDao.listByAffinityGroup(affinityGroupId);
if (!affinityGroupVmMap.isEmpty()) {
SearchBuilder<AffinityGroupVMMapVO> listByAffinityGroup = _affinityGroupVMMapDao.createSearchBuilder();
listByAffinityGroup.and("affinityGroupId", listByAffinityGroup.entity().getAffinityGroupId(), SearchCriteria.Op.EQ);
listByAffinityGroup.done();
SearchCriteria<AffinityGroupVMMapVO> sc = listByAffinityGroup.create();
sc.setParameters("affinityGroupId", affinityGroupIdFinal);
sc.setParameters("affinityGroupId", affinityGroupId);
_affinityGroupVMMapDao.lockRows(sc, null, true);
_affinityGroupVMMapDao.remove(sc);
@ -293,77 +309,15 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
processor.handleDeleteGroup(group);
}
if(_affinityGroupDao.expunge(affinityGroupIdFinal)){
if(_affinityGroupDao.expunge(affinityGroupId)){
AffinityGroupDomainMapVO groupDomain = _affinityGroupDomainMapDao
.findByAffinityGroup(affinityGroupIdFinal);
.findByAffinityGroup(affinityGroupId);
if (groupDomain != null) {
_affinityGroupDomainMapDao.remove(groupDomain.getId());
}
}
}
});
// remove its related ACL permission
Pair<Class<?>, Long> params = new Pair<Class<?>, Long>(AffinityGroup.class, affinityGroupIdFinal);
_messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, params);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Deleted affinity group id=" + affinityGroupId);
}
return true;
}
@Override
public Pair<List<? extends AffinityGroup>, Integer> listAffinityGroups(Long affinityGroupId, String affinityGroupName, String affinityGroupType, Long vmId,
Long startIndex, Long pageSize) {
Filter searchFilter = new Filter(AffinityGroupVO.class, "id", Boolean.TRUE, startIndex, pageSize);
Account caller = CallContext.current().getCallingAccount();
Long accountId = caller.getAccountId();
Long domainId = caller.getDomainId();
SearchBuilder<AffinityGroupVMMapVO> vmInstanceSearch = _affinityGroupVMMapDao.createSearchBuilder();
vmInstanceSearch.and("instanceId", vmInstanceSearch.entity().getInstanceId(), SearchCriteria.Op.EQ);
SearchBuilder<AffinityGroupVO> groupSearch = _affinityGroupDao.createSearchBuilder();
SearchCriteria<AffinityGroupVO> sc = groupSearch.create();
if (accountId != null) {
sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
}
if (domainId != null) {
sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
}
if (affinityGroupId != null) {
sc.addAnd("id", SearchCriteria.Op.EQ, affinityGroupId);
}
if (affinityGroupName != null) {
sc.addAnd("name", SearchCriteria.Op.EQ, affinityGroupName);
}
if (affinityGroupType != null) {
sc.addAnd("type", SearchCriteria.Op.EQ, affinityGroupType);
}
if (vmId != null) {
UserVmVO userVM = _userVmDao.findById(vmId);
if (userVM == null) {
throw new InvalidParameterValueException("Unable to list affinity groups for virtual machine instance " + vmId + "; instance not found.");
}
_accountMgr.checkAccess(caller, null, true, userVM);
// add join to affinity_groups_vm_map
groupSearch.join("vmInstanceSearch", vmInstanceSearch, groupSearch.entity().getId(), vmInstanceSearch.entity().getAffinityGroupId(),
JoinBuilder.JoinType.INNER);
sc.setJoinParameters("vmInstanceSearch", "instanceId", vmId);
}
Pair<List<AffinityGroupVO>, Integer> result = _affinityGroupDao.searchAndCount(sc, searchFilter);
return new Pair<List<? extends AffinityGroup>, Integer>(result.first(), result.second());
}
@Override
@ -460,7 +414,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
// Verify input parameters
UserVmVO vmInstance = _userVmDao.findById(vmId);
if (vmInstance == null) {
throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId);
throw new InvalidParameterValueException("Unable to find a virtual machine with id " + vmId);
}
// Check that the VM is stopped

View File

@ -167,38 +167,39 @@ public class AffinityApiUnitTest {
@Test
public void createAffinityGroupTest() {
when(_groupDao.isNameInUse(anyLong(), anyLong(), eq("group1"))).thenReturn(false);
AffinityGroup group = _affinityService.createAffinityGroup("user", domainId, "group1", "mock", "affinity group one");
AffinityGroup group = _affinityService.createAffinityGroup("user", null, domainId, "group1", "mock", "affinity group one");
assertNotNull("Affinity group 'group1' of type 'mock' failed to create ", group);
}
@Test(expected = InvalidParameterValueException.class)
public void invalidAffinityTypeTest() {
AffinityGroup group = _affinityService.createAffinityGroup("user", domainId, "group1", "invalid", "affinity group one");
AffinityGroup group = _affinityService.createAffinityGroup("user", null, domainId, "group1", "invalid", "affinity group one");
}
@Test(expected = InvalidParameterValueException.class)
public void uniqueAffinityNameTest() {
when(_groupDao.isNameInUse(anyLong(), anyLong(), eq("group1"))).thenReturn(true);
AffinityGroup group2 = _affinityService.createAffinityGroup("user", domainId, "group1", "mock", "affinity group two");
AffinityGroup group2 = _affinityService.createAffinityGroup("user", null, domainId, "group1", "mock", "affinity group two");
}
@Test(expected = InvalidParameterValueException.class)
public void deleteAffinityGroupInvalidIdTest() throws ResourceInUseException {
when(_groupDao.findById(20L)).thenReturn(null);
_affinityService.deleteAffinityGroup(20L, "user", domainId, "group1");
_affinityService.deleteAffinityGroup(20L, "user", null, domainId, "group1");
}
@Test(expected = InvalidParameterValueException.class)
public void deleteAffinityGroupInvalidIdName() throws ResourceInUseException {
when(_acctMgr.finalyzeAccountId("user", domainId, null, true)).thenReturn(200L);
when(_groupDao.findByAccountAndName(200L, "group1")).thenReturn(null);
_affinityService.deleteAffinityGroup(null, "user", domainId, "group1");
_affinityService.deleteAffinityGroup(null, "user", null, domainId, "group1");
}
@Test(expected = InvalidParameterValueException.class)
public void deleteAffinityGroupNullIdName() throws ResourceInUseException {
_affinityService.deleteAffinityGroup(null, "user", domainId, null);
_affinityService.deleteAffinityGroup(null, "user", null, domainId, null);
}
@Test(expected = InvalidParameterValueException.class)

View File

@ -0,0 +1,358 @@
// 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.affinity;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.utils.db.EntityManager;
import com.cloud.event.ActionEventUtils;
import com.cloud.user.User;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
import org.apache.cloudstack.test.utils.SpringUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.affinity.dao.AffinityGroupDomainMapDao;
import org.apache.cloudstack.api.command.user.affinitygroup.CreateAffinityGroupCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.framework.messagebus.MessageBus;
import com.cloud.dc.dao.DedicatedResourceDao;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.EventVO;
import com.cloud.event.dao.EventDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceInUseException;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountService;
import com.cloud.user.AccountVO;
import com.cloud.user.DomainManager;
import com.cloud.user.UserVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.component.ComponentContext;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.projects.dao.ProjectDao;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class AffinityGroupServiceImplTest {
@Inject
AffinityGroupServiceImpl _affinityService;
@Inject
AccountManager _acctMgr;
@Inject
AffinityGroupProcessor _processor;
@Inject
AffinityGroupDao _groupDao;
@Inject
UserVmDao _vmDao;
@Inject
AffinityGroupVMMapDao _affinityGroupVMMapDao;
@Inject
AffinityGroupDao _affinityGroupDao;
@Inject
ActionEventUtils _eventUtils;
@Inject
AccountDao _accountDao;
@Inject
ProjectDao _projectDao;
@Inject
EventDao _eventDao;
@Inject
DedicatedResourceDao _dedicatedDao;
private static final long DOMAIN_ID = 5L;
private static final long PROJECT_ID = 10L;
private static final String ACCOUNT_NAME = "user";
private static final String AFFINITY_GROUP_NAME = "group1";
private AccountVO acct;
@BeforeClass
public static void setUpClass() throws ConfigurationException {
}
@Before
public void setUp() {
ComponentContext.initComponentsLifeCycle();
acct = new AccountVO(200L);
acct.setType(Account.ACCOUNT_TYPE_NORMAL);
acct.setAccountName(ACCOUNT_NAME);
acct.setDomainId(DOMAIN_ID);
UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
CallContext.register(user, acct);
when(_processor.getType()).thenReturn("mock");
when(_accountDao.findByIdIncludingRemoved(0L)).thenReturn(acct);
List<AffinityGroupProcessor> affinityProcessors = new ArrayList<AffinityGroupProcessor>();
affinityProcessors.add(_processor);
_affinityService.setAffinityGroupProcessors(affinityProcessors);
AffinityGroupVO group = new AffinityGroupVO(AFFINITY_GROUP_NAME, "mock", "mock group", DOMAIN_ID, 200L, ControlledEntity.ACLType.Account);
Mockito.when(_affinityGroupDao.persist(Matchers.any(AffinityGroupVO.class))).thenReturn(group);
Mockito.when(_affinityGroupDao.findById(Matchers.anyLong())).thenReturn(group);
Mockito.when(_affinityGroupDao.findByAccountAndName(Matchers.anyLong(), Matchers.anyString())).thenReturn(group);
Mockito.when(_affinityGroupDao.lockRow(Matchers.anyLong(), anyBoolean())).thenReturn(group);
Mockito.when(_affinityGroupDao.expunge(Matchers.anyLong())).thenReturn(true);
Mockito.when(_eventDao.persist(Matchers.any(EventVO.class))).thenReturn(new EventVO());
}
@After
public void tearDown() {
CallContext.unregister();
}
@Test
public void createAffinityGroupFromCmdTest() {
when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
when(_groupDao.isNameInUse(anyLong(), anyLong(), eq(AFFINITY_GROUP_NAME))).thenReturn(false);
CreateAffinityGroupCmd mockCreateAffinityGroupCmd = Mockito.mock(CreateAffinityGroupCmd.class);
when(mockCreateAffinityGroupCmd.getProjectId()).thenReturn(PROJECT_ID);
when(mockCreateAffinityGroupCmd.getAffinityGroupName()).thenReturn(AFFINITY_GROUP_NAME);
when(mockCreateAffinityGroupCmd.getAffinityGroupType()).thenReturn("mock");
when(mockCreateAffinityGroupCmd.getDescription()).thenReturn("affinity group one");
AffinityGroup group = _affinityService.createAffinityGroup(mockCreateAffinityGroupCmd);
assertNotNull("Affinity group 'group1' of type 'mock' failed to create ", group);
}
@Test
public void createAffinityGroupTest() {
when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
when(_groupDao.isNameInUse(anyLong(), anyLong(), eq(AFFINITY_GROUP_NAME))).thenReturn(false);
AffinityGroup group = _affinityService.createAffinityGroup(ACCOUNT_NAME, null, DOMAIN_ID, AFFINITY_GROUP_NAME, "mock", "affinity group one");
assertNotNull("Affinity group 'group1' of type 'mock' failed to create ", group);
}
@Test
public void shouldDeleteDomainLevelAffinityGroup() {
AffinityGroupVO mockGroup = Mockito.mock(AffinityGroupVO.class);
when(mockGroup.getId()).thenReturn(2L);
when(_affinityGroupDao.findById(Matchers.anyLong())).thenReturn(mockGroup);
_affinityService.deleteAffinityGroup(2L, null, null, DOMAIN_ID, null);
Mockito.verify(_affinityGroupDao).expunge(2L);
}
@Test
public void shouldDeleteAffintyGroupById() {
AffinityGroupVO mockGroup = Mockito.mock(AffinityGroupVO.class);
when(mockGroup.getId()).thenReturn(1L);
when(_affinityGroupDao.findById(Matchers.anyLong())).thenReturn(mockGroup);
_affinityService.deleteAffinityGroup(1L, ACCOUNT_NAME, null, DOMAIN_ID, null);
Mockito.verify(_affinityGroupDao).expunge(1L);
}
@Test(expected = InvalidParameterValueException.class)
public void invalidAffinityTypeTest() {
when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
_affinityService.createAffinityGroup(ACCOUNT_NAME, null, DOMAIN_ID, AFFINITY_GROUP_NAME, "invalid", "affinity group one");
}
@Test(expected = InvalidParameterValueException.class)
public void uniqueAffinityNameTest() {
when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
when(_groupDao.isNameInUse(anyLong(), anyLong(), eq(AFFINITY_GROUP_NAME))).thenReturn(true);
_affinityService.createAffinityGroup(ACCOUNT_NAME, null, DOMAIN_ID, AFFINITY_GROUP_NAME, "mock", "affinity group two");
}
@Test(expected = InvalidParameterValueException.class)
public void deleteAffinityGroupInvalidIdTest() throws ResourceInUseException {
when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
when(_groupDao.findById(20L)).thenReturn(null);
_affinityService.deleteAffinityGroup(20L, ACCOUNT_NAME, null, DOMAIN_ID, AFFINITY_GROUP_NAME);
}
@Test(expected = InvalidParameterValueException.class)
public void deleteAffinityGroupInvalidIdName() throws ResourceInUseException {
when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
when(_acctMgr.finalyzeAccountId(ACCOUNT_NAME, DOMAIN_ID, null, true)).thenReturn(200L);
when(_groupDao.findByAccountAndName(200L, AFFINITY_GROUP_NAME)).thenReturn(null);
_affinityService.deleteAffinityGroup(null, ACCOUNT_NAME, null, DOMAIN_ID, AFFINITY_GROUP_NAME);
}
@Test(expected = InvalidParameterValueException.class)
public void deleteAffinityGroupNullIdName() throws ResourceInUseException {
when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
_affinityService.deleteAffinityGroup(null, ACCOUNT_NAME, null, DOMAIN_ID, null);
}
@Test(expected = InvalidParameterValueException.class)
public void updateAffinityGroupVMRunning() throws ResourceInUseException {
when(_acctMgr.finalizeOwner((Account)anyObject(), anyString(), anyLong(), anyLong())).thenReturn(acct);
UserVmVO vm = new UserVmVO(10L, "test", "test", 101L, HypervisorType.Any, 21L, false, false, DOMAIN_ID, 200L, 1, 5L, "", "test", 1L);
vm.setState(VirtualMachine.State.Running);
when(_vmDao.findById(10L)).thenReturn(vm);
List<Long> affinityGroupIds = new ArrayList<Long>();
affinityGroupIds.add(20L);
_affinityService.updateVMAffinityGroups(10L, affinityGroupIds);
}
@Configuration
@ComponentScan(basePackageClasses = {AffinityGroupServiceImpl.class, ActionEventUtils.class}, includeFilters = {@Filter(value = TestConfiguration.Library.class, type = FilterType.CUSTOM)}, useDefaultFilters = false)
public static class TestConfiguration extends SpringUtils.CloudStackTestConfiguration {
@Bean
public AccountDao accountDao() {
return Mockito.mock(AccountDao.class);
}
@Bean
public ProjectDao projectDao() {
return Mockito.mock(ProjectDao.class);
}
@Bean
public AccountService accountService() {
return Mockito.mock(AccountService.class);
}
@Bean
public AffinityGroupProcessor affinityGroupProcessor() {
return Mockito.mock(AffinityGroupProcessor.class);
}
@Bean
public AffinityGroupDao affinityGroupDao() {
return Mockito.mock(AffinityGroupDao.class);
}
@Bean
public AffinityGroupVMMapDao affinityGroupVMMapDao() {
return Mockito.mock(AffinityGroupVMMapDao.class);
}
@Bean
public DedicatedResourceDao dedicatedResourceDao() {
return Mockito.mock(DedicatedResourceDao.class);
}
@Bean
public AccountManager accountManager() {
return Mockito.mock(AccountManager.class);
}
@Bean
public DomainManager domainManager() {
return Mockito.mock(DomainManager.class);
}
@Bean
public EventDao eventDao() {
return Mockito.mock(EventDao.class);
}
@Bean
public UserVmDao userVMDao() {
return Mockito.mock(UserVmDao.class);
}
@Bean
public UserDao userDao() {
return Mockito.mock(UserDao.class);
}
@Bean
public AffinityGroupDomainMapDao affinityGroupDomainMapDao() {
return Mockito.mock(AffinityGroupDomainMapDao.class);
}
@Bean
public EntityManager entityManager() {
return Mockito.mock(EntityManager.class);
}
@Bean
public DomainDao domainDao() {
return Mockito.mock(DomainDao.class);
}
@Bean
public MessageBus messageBus() {
return Mockito.mock(MessageBus.class);
}
@Bean
public ConfigurationDao configDao() {
return Mockito.mock(ConfigurationDao.class);
}
public static class Library implements TypeFilter {
@Override
public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException {
ComponentScan cs = TestConfiguration.class.getAnnotation(ComponentScan.class);
return SpringUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs);
}
}
}
}

View File

@ -18,3 +18,35 @@
--;
-- Schema upgrade from 4.6.0 to 4.6.1;
--;
DROP VIEW IF EXISTS `cloud`.`affinity_group_view`;
CREATE VIEW `affinity_group_view`
AS SELECT
`affinity_group`.`id` AS `id`,
`affinity_group`.`name` AS `name`,
`affinity_group`.`type` AS `type`,
`affinity_group`.`description` AS `description`,
`affinity_group`.`uuid` AS `uuid`,
`affinity_group`.`acl_type` AS `acl_type`,
`account`.`id` AS `account_id`,
`account`.`uuid` AS `account_uuid`,
`account`.`account_name` AS `account_name`,
`account`.`type` AS `account_type`,
`domain`.`id` AS `domain_id`,
`domain`.`uuid` AS `domain_uuid`,
`domain`.`name` AS `domain_name`,
`domain`.`path` AS `domain_path`,
`projects`.`id` AS `project_id`,
`projects`.`uuid` AS `project_uuid`,
`projects`.`name` AS `project_name`,
`vm_instance`.`id` AS `vm_id`,
`vm_instance`.`uuid` AS `vm_uuid`,
`vm_instance`.`name` AS `vm_name`,
`vm_instance`.`state` AS `vm_state`,
`user_vm`.`display_name` AS `vm_display_name`
FROM `affinity_group`
JOIN `account` ON`affinity_group`.`account_id` = `account`.`id`
JOIN `domain` ON`affinity_group`.`domain_id` = `domain`.`id`
LEFT JOIN `projects` ON`projects`.`project_account_id` = `account`.`id`
LEFT JOIN `affinity_group_vm_map` ON`affinity_group`.`id` = `affinity_group_vm_map`.`affinity_group_id`
LEFT JOIN `vm_instance` ON`vm_instance`.`id` = `affinity_group_vm_map`.`instance_id`
LEFT JOIN `user_vm` ON`user_vm`.`id` = `vm_instance`.`id`;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,188 @@
#!/usr/bin/env python
# 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.
from marvin.codes import FAILED
from marvin.cloudstackTestCase import *
from marvin.cloudstackAPI import *
from marvin.lib.utils import *
from marvin.lib.base import *
from marvin.lib.common import *
from marvin.sshClient import SshClient
from nose.plugins.attrib import attr
class TestDeployVmWithAffinityGroup(cloudstackTestCase):
"""
This test deploys a virtual machine for a project
using the small service offering and builtin template
"""
@classmethod
def setUpClass(cls):
cls.testClient = super(TestDeployVmWithAffinityGroup, cls).getClsTestClient()
zone_name = cls.testClient.getZoneForTests()
cls.apiclient = cls.testClient.getApiClient()
cls.domain = get_domain(cls.apiclient)
cls.services = cls.testClient.getParsedTestDataConfig()
# Get Zone, Domain and templates
cls.zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
cls.template = get_template(
cls.apiclient,
cls.zone.id,
cls.services["ostype"]
)
if cls.template == FAILED:
assert False, "get_template() failed to return template with description %s" % cls.services["ostype"]
cls.services["virtual_machine"]["zoneid"] = cls.zone.id
cls.services["template"] = cls.template.id
cls.services["zoneid"] = cls.zone.id
cls.account = Account.create(
cls.apiclient,
cls.services["account"],
domainid=cls.domain.id
)
projectData = {
"name": "Project",
"displaytext": "Test project",
}
cls.project = Project.create(
cls.apiclient,
projectData,
account=cls.account.name,
domainid=cls.account.domainid
)
# Add user to the project
cls.project.addAccount(
cls.apiclient,
cls.account.name
)
cls.service_offering = ServiceOffering.create(
cls.apiclient,
cls.services["service_offerings"]["tiny"]
)
cls.ag = AffinityGroup.create(cls.apiclient, cls.services["virtual_machine"]["affinity"],projectid=cls.project.id)
cls._cleanup = [
cls.service_offering,
cls.ag,
cls.project,
cls.account,
]
return
@attr(tags=["basic", "advanced", "multihost"], required_hardware="false")
def test_DeployVmAntiAffinityGroup_in_project(self):
"""
test DeployVM in anti-affinity groups for project
deploy VM1 and VM2 in the same host-anti-affinity groups
Verify that the vms are deployed on separate hosts
"""
#deploy VM1 in affinity group created in setUp
vm1 = VirtualMachine.create(
self.apiclient,
self.services["virtual_machine"],
templateid=self.template.id,
projectid=self.project.id,
serviceofferingid=self.service_offering.id,
affinitygroupnames=[self.ag.name]
)
list_vm1 = list_virtual_machines(
self.apiclient,
id=vm1.id
)
self.assertEqual(
isinstance(list_vm1, list),
True,
"Check list response returns a valid list"
)
self.assertNotEqual(
len(list_vm1),
0,
"Check VM available in List Virtual Machines"
)
vm1_response = list_vm1[0]
self.assertEqual(
vm1_response.state,
'Running',
msg="VM is not in Running state"
)
self.assertEqual(
vm1_response.projectid,
self.project.id,
msg="VM1 is not deployed in project"
)
host_of_vm1 = vm1_response.hostid
#deploy VM2 in affinity group created in setUp
vm2 = VirtualMachine.create(
self.apiclient,
self.services["virtual_machine"],
templateid=self.template.id,
projectid=self.project.id,
serviceofferingid=self.service_offering.id,
affinitygroupnames=[self.ag.name]
)
list_vm2 = list_virtual_machines(
self.apiclient,
id=vm2.id
)
self.assertEqual(
isinstance(list_vm2, list),
True,
"Check list response returns a valid list"
)
self.assertNotEqual(
len(list_vm2),
0,
"Check VM available in List Virtual Machines"
)
vm2_response = list_vm2[0]
self.assertEqual(
vm2_response.state,
'Running',
msg="VM is not in Running state"
)
self.assertEqual(
vm2_response.projectid,
self.project.id,
msg="VM2 is not deployed in project"
)
host_of_vm2 = vm2_response.hostid
self.assertNotEqual(host_of_vm1, host_of_vm2,
msg="Both VMs of affinity group %s are on the same host" % self.ag.name)
@classmethod
def tearDownClass(cls):
try:
#Clean up, terminate the created templates
cleanup_resources(cls.apiclient, cls._cleanup)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)

View File

@ -4220,7 +4220,7 @@ class AffinityGroup:
self.__dict__.update(items)
@classmethod
def create(cls, apiclient, aff_grp, account=None, domainid=None):
def create(cls, apiclient, aff_grp, account=None, domainid=None, projectid=None):
cmd = createAffinityGroup.createAffinityGroupCmd()
cmd.name = aff_grp['name']
cmd.displayText = aff_grp['name']
@ -4229,6 +4229,8 @@ class AffinityGroup:
cmd.account = account
if domainid:
cmd.domainid = domainid
if projectid:
cmd.projectid = projectid
return AffinityGroup(apiclient.createAffinityGroup(cmd).__dict__)
def update(self, apiclient):