package org.ovirt.engine.core.bll;
import java.util.List;
import org.ovirt.engine.core.common.VdcObjectType;
import org.ovirt.engine.core.common.action.CreateAllSnapshotsFromVmParameters;
import org.ovirt.engine.core.common.action.PermissionsOperationsParametes;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VdcReturnValueBase;
import org.ovirt.engine.core.common.action.VmPoolUserParameters;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.permissions;
import org.ovirt.engine.core.common.errors.VdcBLLException;
import org.ovirt.engine.core.common.errors.VdcBllErrors;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.LogCompat;
import org.ovirt.engine.core.compat.LogFactoryCompat;
import org.ovirt.engine.core.compat.NGuid;
import org.ovirt.engine.core.dal.VdcBllMessages;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
/**
* Command to attach a VM from a pool to a user, so that the user can use the attached VM.<br>
* The command-level lock is per user, so that a single user won't be able to attach more than one VM from a given pool
* since this is the policy.
*/
@LockIdNameAttribute(fieldName = "AdUserId")
@InternalCommandAttribute
public class AttachUserToVmFromPoolCommand<T extends VmPoolUserParameters> extends VmPoolUserCommandBase<T> {
protected AttachUserToVmFromPoolCommand(Guid commandId) {
super(commandId);
}
public AttachUserToVmFromPoolCommand(T parameters) {
super(parameters);
}
/**
* This lock is used to synchronize multiple users trying to attach a VM from pool, so that they won't be able to
* attach the same VM to more than one user.
*/
private static final Object _lockObject = new Object();
@Override
protected boolean canDoAction() {
boolean returnValue = true;
// VmId = GetVmToAttach(PoolUserParameters.VmPoolId);
// Parameters.EntityId = VmId;
synchronized (_lockObject) {
if (GetVmToAttach(getParameters().getVmPoolId()).equals(Guid.Empty)) // no
// available
// VMs:
{
addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_NO_AVAILABLE_POOL_VMS);
returnValue = false;
}
}
// check user isn't already attached to vm from this pool
if (returnValue) {
List<VM> vmsForUser = DbFacade.getInstance().getVmDAO().getAllForUser(getAdUserId());
for (VM vm : vmsForUser) {
if (vm.getVmPoolId() != null && getVmPoolId().equals(vm.getVmPoolId())) {
addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_USER_ATTACHED_TO_POOL);
returnValue = false;
}
}
}
if (!returnValue) {
addCanDoActionMessage(VdcBllMessages.VAR__ACTION__ALLOCATE_AND_RUN);
addCanDoActionMessage(VdcBllMessages.VAR__TYPE__VM_FROM_VM_POOL);
}
return returnValue;
}
@Override
public Guid getVmId() {
return getParameters().getVmId();
}
@Override
public void setVmId(Guid value) {
getParameters().setVmId(value);
}
@Override
protected NGuid getVmPoolId() {
return getParameters().getVmPoolId();
}
@Override
protected void setVmPoolId(NGuid value) {
getParameters().setVmPoolId(value);
}
@Override
public Guid getAdUserId() {
return getParameters().getUserId();
}
@Override
protected void executeCommand() {
/**
* TODO: check users throw their groups as well
*/
initUser();
synchronized (_lockObject) {
// check vm is not attached to user and attach
List<permissions> vmUserPermissions = DbFacade
.getInstance()
.getPermissionDAO()
.getAllForRoleAndObject(PredefinedRoles.ENGINE_USER.getId(),
getVmId());
if (vmUserPermissions == null || vmUserPermissions.isEmpty()) {
setVmId(GetVmToAttach(getParameters().getVmPoolId()));
if (!getVmId().equals(Guid.Empty)) {
getParameters().setEntityId(getVmId());
permissions perm = new permissions(getAdUserId(), PredefinedRoles.ENGINE_USER.getId(), getVmId(),
VdcObjectType.VM);
PermissionsOperationsParametes permParams = new PermissionsOperationsParametes(perm);
permParams.setShouldBeLogged(false);
Backend.getInstance().runInternalAction(VdcActionType.AddPermission,
permParams,
getCompensationContext());
log.infoFormat("Vm {0} was attached to user {1} ", getVmId(), getAdUserId());
}
}
}
if (getVmId().equals(Guid.Empty)) {
log.infoFormat("No free Vms in pool. Cannot allocate for user {1} ", getAdUserId());
throw new VdcBLLException(VdcBllErrors.NO_FREE_VM_IN_POOL);
}
CreateAllSnapshotsFromVmParameters tempVar = new CreateAllSnapshotsFromVmParameters(getVmId(),
"SnapshotForVmFromPool");
tempVar.setShouldBeLogged(false);
tempVar.setParentCommand(getParameters().getParentCommand() != VdcActionType.Unknown ? getParameters()
.getParentCommand() : VdcActionType.AttachUserToVmFromPool);
tempVar.setSessionId(getParameters().getSessionId());
tempVar.setEntityId(getParameters().getEntityId());
CreateAllSnapshotsFromVmParameters p = tempVar;
VdcReturnValueBase vdcReturnValue = Backend.getInstance().runInternalAction(
VdcActionType.CreateAllSnapshotsFromVm, p, getCompensationContext());
getParameters().getImagesParameters().add(p);
getTaskIdList().addAll(vdcReturnValue.getInternalTaskIdList());
setSucceeded(vdcReturnValue.getSucceeded());
setActionReturnValue(getVmId());
}
@Override
protected void EndSuccessfully() {
Backend.getInstance().endAction(VdcActionType.CreateAllSnapshotsFromVm,
getParameters().getImagesParameters().get(0), getCompensationContext());
setSucceeded(true);
}
@Override
protected void EndWithFailure() {
Backend.getInstance().endAction(VdcActionType.CreateAllSnapshotsFromVm,
getParameters().getImagesParameters().get(0), getCompensationContext());
DetachUserFromVmFromPool();
setSucceeded(true);
}
protected void DetachUserFromVmFromPool() {
// Detach user from vm from pool:
if (!getAdUserId().equals(Guid.Empty)) {
permissions perm = DbFacade
.getInstance()
.getPermissionDAO()
.getForRoleAndAdElementAndObject(
PredefinedRoles.ENGINE_USER.getId(), getAdUserId(),
getVmId());
if (perm != null) {
DbFacade.getInstance().getPermissionDAO().remove(perm.getId());
}
}
}
private static LogCompat log = LogFactoryCompat.getLog(AttachUserToVmFromPoolCommand.class);
}