Merge pull request #2124 from GabrielBrascher/CLOUDSTACK-9432

CLOUDSTACK-9432: cluster/host dedicated to a domain is owned by the root domain
This commit is contained in:
Gabriel Beims Bräscher 2017-11-28 10:31:23 -02:00 committed by GitHub
commit bd5604428b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 77 additions and 39 deletions

View File

@ -117,7 +117,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
@DB @DB
@Override @Override
public AffinityGroup createAffinityGroup(final String accountName, final Long projectId, final Long domainId, final String affinityGroupName, final String affinityGroupType, public AffinityGroup createAffinityGroup(final String accountName, final Long projectId, final Long domainId, final String affinityGroupName, final String affinityGroupType,
final String description) { final String description) {
// validate the affinityGroupType // validate the affinityGroupType
Map<String, AffinityGroupProcessor> typeProcessorMap = getAffinityTypeToProcessorMap(); Map<String, AffinityGroupProcessor> typeProcessorMap = getAffinityTypeToProcessorMap();
@ -158,7 +158,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
verifyAffinityGroupNameInUse(owner.getAccountId(), owner.getDomainId(), affinityGroupName); verifyAffinityGroupNameInUse(owner.getAccountId(), owner.getDomainId(), affinityGroupName);
verifyDomainLevelAffinityGroupName(domainLevel, owner.getDomainId(), affinityGroupName); verifyDomainLevelAffinityGroupName(domainLevel, owner.getDomainId(), affinityGroupName);
AffinityGroupVO group = createAffinityGroup(processor, owner, aclType, affinityGroupName, affinityGroupType, description); AffinityGroupVO group = createAffinityGroup(processor, owner, aclType, affinityGroupName, affinityGroupType, description, domainLevel, domainId);
if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) {
s_logger.debug("Created affinity group =" + affinityGroupName); s_logger.debug("Created affinity group =" + affinityGroupName);
@ -176,25 +176,27 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
} }
} }
private AffinityGroupVO createAffinityGroup(final AffinityGroupProcessor processor, final Account owner, final ACLType aclType, final String affinityGroupName, final String affinityGroupType, final String description) { private AffinityGroupVO createAffinityGroup(final AffinityGroupProcessor processor, final Account owner, final ACLType aclType, final String affinityGroupName, final String affinityGroupType, final String description, boolean domainLevel, Long domainId) {
final Long affinityGroupDomainId = getDomainIdBasedOnDomainLevel(owner, domainLevel, domainId);
return Transaction.execute(new TransactionCallback<AffinityGroupVO>() { return Transaction.execute(new TransactionCallback<AffinityGroupVO>() {
@Override @Override
public AffinityGroupVO doInTransaction(TransactionStatus status) { public AffinityGroupVO doInTransaction(TransactionStatus status) {
AffinityGroupVO group = AffinityGroupVO group = new AffinityGroupVO(affinityGroupName, affinityGroupType, description, affinityGroupDomainId, owner.getId(), aclType);
new AffinityGroupVO(affinityGroupName, affinityGroupType, description, owner.getDomainId(), owner.getId(), aclType);
_affinityGroupDao.persist(group); _affinityGroupDao.persist(group);
if (aclType == ACLType.Domain) { if (aclType == ACLType.Domain) {
boolean subDomainAccess = false; boolean subDomainAccess = false;
subDomainAccess = processor.subDomainAccess(); subDomainAccess = processor.subDomainAccess();
AffinityGroupDomainMapVO domainMap = new AffinityGroupDomainMapVO(group.getId(), owner.getDomainId(), AffinityGroupDomainMapVO domainMap = new AffinityGroupDomainMapVO(group.getId(), affinityGroupDomainId,
subDomainAccess); subDomainAccess);
_affinityGroupDomainMapDao.persist(domainMap); _affinityGroupDomainMapDao.persist(domainMap);
//send event for storing the domain wide resource access //send event for storing the domain wide resource access
Map<String, Object> params = new HashMap<String, Object>(); Map<String, Object> params = new HashMap<String, Object>();
params.put(ApiConstants.ENTITY_TYPE, AffinityGroup.class); params.put(ApiConstants.ENTITY_TYPE, AffinityGroup.class);
params.put(ApiConstants.ENTITY_ID, group.getId()); params.put(ApiConstants.ENTITY_ID, group.getId());
params.put(ApiConstants.DOMAIN_ID, owner.getDomainId()); params.put(ApiConstants.DOMAIN_ID, affinityGroupDomainId);
params.put(ApiConstants.SUBDOMAIN_ACCESS, subDomainAccess); params.put(ApiConstants.SUBDOMAIN_ACCESS, subDomainAccess);
_messageBus.publish(_name, EntityManager.MESSAGE_ADD_DOMAIN_WIDE_ENTITY_EVENT, PublishScope.LOCAL, _messageBus.publish(_name, EntityManager.MESSAGE_ADD_DOMAIN_WIDE_ENTITY_EVENT, PublishScope.LOCAL,
params); params);
@ -205,6 +207,20 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
}); });
} }
/**
* If the account is null (domainLevel is true), then returns the domain id passed as a
* parameter; otherwise (domainLevel is false) it returns the domain id from the owner account.
*
* @note: this method fixes a critical bug. More details in JIRA ticket CLOUDSTACK-9432.
*/
protected Long getDomainIdBasedOnDomainLevel(final Account owner, boolean domainLevel, Long domainId) {
Long domainIdBasedOnDomainLevel = owner.getDomainId();
if (domainLevel) {
domainIdBasedOnDomainLevel = domainId;
}
return domainIdBasedOnDomainLevel;
}
private DomainVO getDomain(Long domainId) { private DomainVO getDomain(Long domainId) {
DomainVO domain = _domainDao.findById(domainId); DomainVO domain = _domainDao.findById(domainId);
if (domain == null) { if (domain == null) {
@ -225,6 +241,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
} }
} }
@Override
@DB @DB
@ActionEvent(eventType = EventTypes.EVENT_AFFINITY_GROUP_DELETE, eventDescription = "Deleting affinity group") @ActionEvent(eventType = EventTypes.EVENT_AFFINITY_GROUP_DELETE, eventDescription = "Deleting affinity group")
public boolean deleteAffinityGroup(Long affinityGroupId, String account, Long projectId, Long domainId, String affinityGroupName) { public boolean deleteAffinityGroup(Long affinityGroupId, String account, Long projectId, Long domainId, String affinityGroupName) {
@ -258,7 +275,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
throw new InvalidParameterValueException("Either the affinity group Id or group name must be specified to delete the group"); throw new InvalidParameterValueException("Either the affinity group Id or group name must be specified to delete the group");
} }
if (group == null) { if (group == null) {
throw new InvalidParameterValueException("Unable to find affinity group " + (affinityGroupId == null ? affinityGroupName : affinityGroupId)); throw new InvalidParameterValueException("Unable to find affinity group " + (affinityGroupId == null ? affinityGroupName : affinityGroupId));
} }
return group; return group;
} }
@ -292,10 +309,10 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
List<AffinityGroupVMMapVO> affinityGroupVmMap = _affinityGroupVMMapDao.listByAffinityGroup(affinityGroupId); List<AffinityGroupVMMapVO> affinityGroupVmMap = _affinityGroupVMMapDao.listByAffinityGroup(affinityGroupId);
if (!affinityGroupVmMap.isEmpty()) { if (!affinityGroupVmMap.isEmpty()) {
SearchBuilder<AffinityGroupVMMapVO> listByAffinityGroup = _affinityGroupVMMapDao.createSearchBuilder(); SearchBuilder<AffinityGroupVMMapVO> listByAffinityGroup = _affinityGroupVMMapDao.createSearchBuilder();
listByAffinityGroup.and("affinityGroupId", listByAffinityGroup.entity().getAffinityGroupId(), SearchCriteria.Op.EQ); listByAffinityGroup.and("affinityGroupId", listByAffinityGroup.entity().getAffinityGroupId(), SearchCriteria.Op.EQ);
listByAffinityGroup.done(); listByAffinityGroup.done();
SearchCriteria<AffinityGroupVMMapVO> sc = listByAffinityGroup.create(); SearchCriteria<AffinityGroupVMMapVO> sc = listByAffinityGroup.create();
sc.setParameters("affinityGroupId", affinityGroupId); sc.setParameters("affinityGroupId", affinityGroupId);
_affinityGroupVMMapDao.lockRows(sc, null, true); _affinityGroupVMMapDao.lockRows(sc, null, true);
_affinityGroupVMMapDao.remove(sc); _affinityGroupVMMapDao.remove(sc);
@ -323,12 +340,12 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
List<String> types = new ArrayList<String>(); List<String> types = new ArrayList<String>();
for (AffinityGroupProcessor processor : _affinityProcessors) { for (AffinityGroupProcessor processor : _affinityProcessors) {
if (processor.isAdminControlledGroup()) { if (processor.isAdminControlledGroup()) {
continue; // we dont list the type if this group can be continue; // we dont list the type if this group can be
// created only as an admin/system operation. // created only as an admin/system operation.
}
types.add(processor.getType());
} }
types.add(processor.getType());
}
return types; return types;
} }
@ -394,20 +411,20 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
@Override @Override
public boolean postStateTransitionEvent(StateMachine2.Transition<State, Event> transition, VirtualMachine vo, boolean status, Object opaque) { public boolean postStateTransitionEvent(StateMachine2.Transition<State, Event> transition, VirtualMachine vo, boolean status, Object opaque) {
if (!status) { if (!status) {
return false; return false;
} }
State newState = transition.getToState(); State newState = transition.getToState();
if ((newState == State.Expunging) || (newState == State.Error)) { if ((newState == State.Expunging) || (newState == State.Error)) {
// cleanup all affinity groups associations of the Expunged VM // cleanup all affinity groups associations of the Expunged VM
SearchCriteria<AffinityGroupVMMapVO> sc = _affinityGroupVMMapDao.createSearchCriteria(); SearchCriteria<AffinityGroupVMMapVO> sc = _affinityGroupVMMapDao.createSearchCriteria();
sc.addAnd("instanceId", SearchCriteria.Op.EQ, vo.getId()); sc.addAnd("instanceId", SearchCriteria.Op.EQ, vo.getId());
_affinityGroupVMMapDao.expunge(sc); _affinityGroupVMMapDao.expunge(sc);
} }
return true; return true;
} }
@Override @Override
public UserVm updateVMAffinityGroups(Long vmId, List<Long> affinityGroupIds) { public UserVm updateVMAffinityGroups(Long vmId, List<Long> affinityGroupIds) {
// Verify input parameters // Verify input parameters
UserVmVO vmInstance = _userVmDao.findById(vmId); UserVmVO vmInstance = _userVmDao.findById(vmId);
@ -419,7 +436,7 @@ public class AffinityGroupServiceImpl extends ManagerBase implements AffinityGro
if (!vmInstance.getState().equals(State.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()); 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 " + 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."); vmInstance.getState() + "; make sure the virtual machine is stopped and not in an error state before updating.");
} }
Account caller = CallContext.current().getCallingAccount(); Account caller = CallContext.current().getCallingAccount();

View File

@ -32,12 +32,14 @@ import java.util.UUID;
import javax.inject.Inject; import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import com.cloud.utils.db.EntityManager; import org.apache.cloudstack.acl.ControlledEntity;
import com.cloud.event.ActionEventUtils;
import com.cloud.user.User;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao; 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.affinity.dao.AffinityGroupVMMapDao;
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 org.apache.cloudstack.test.utils.SpringUtils; import org.apache.cloudstack.test.utils.SpringUtils;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -57,33 +59,32 @@ import org.springframework.core.type.filter.TypeFilter;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader; 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.dc.dao.DedicatedResourceDao;
import com.cloud.domain.dao.DomainDao; import com.cloud.domain.dao.DomainDao;
import com.cloud.event.ActionEventUtils;
import com.cloud.event.EventVO; import com.cloud.event.EventVO;
import com.cloud.event.dao.EventDao; import com.cloud.event.dao.EventDao;
import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceInUseException; import com.cloud.exception.ResourceInUseException;
import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.projects.dao.ProjectDao;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.user.AccountManager; import com.cloud.user.AccountManager;
import com.cloud.user.AccountService; import com.cloud.user.AccountService;
import com.cloud.user.AccountVO; import com.cloud.user.AccountVO;
import com.cloud.user.DomainManager; import com.cloud.user.DomainManager;
import com.cloud.user.User;
import com.cloud.user.UserVO; import com.cloud.user.UserVO;
import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao; import com.cloud.user.dao.UserDao;
import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.db.EntityManager;
import com.cloud.vm.UserVmVO; import com.cloud.vm.UserVmVO;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDao;
import com.cloud.projects.dao.ProjectDao;
import org.junit.Assert;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class)
@ -191,6 +192,26 @@ public class AffinityGroupServiceImplTest {
} }
private AccountVO mockOwnerForTestGetDomainIdBasedOnDomainLevel() {
AccountVO mockOwner = Mockito.mock(AccountVO.class);
when(mockOwner.getDomainId()).thenReturn(0l);
return mockOwner;
}
@Test
public void getDomainIdBasedOnDomainLevelTestDomainLevelTrue() {
AccountVO owner = mockOwnerForTestGetDomainIdBasedOnDomainLevel();
Long domainIdBasedOnDomainLevel = _affinityService.getDomainIdBasedOnDomainLevel(owner, true, 1l);
Assert.assertEquals(new Long(1), domainIdBasedOnDomainLevel);
}
@Test
public void getDomainIdBasedOnDomainLevelTestDomainLevelFalse() {
AccountVO owner = mockOwnerForTestGetDomainIdBasedOnDomainLevel();
Long domainIdBasedOnDomainLevel = _affinityService.getDomainIdBasedOnDomainLevel(owner, false, 1l);
Assert.assertEquals(new Long(0), domainIdBasedOnDomainLevel);
}
@Test @Test
public void shouldDeleteDomainLevelAffinityGroup() { public void shouldDeleteDomainLevelAffinityGroup() {
AffinityGroupVO mockGroup = Mockito.mock(AffinityGroupVO.class); AffinityGroupVO mockGroup = Mockito.mock(AffinityGroupVO.class);