cloudstack/server/src/com/cloud/user/AccountManagerImpl.java

1648 lines
70 KiB
Java
Executable File

/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.user;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import com.cloud.acl.ControlledEntity;
import com.cloud.acl.SecurityChecker;
import com.cloud.api.BaseCmd;
import com.cloud.api.ServerApiException;
import com.cloud.api.commands.CreateAccountCmd;
import com.cloud.api.commands.CreateUserCmd;
import com.cloud.api.commands.DeleteAccountCmd;
import com.cloud.api.commands.DeleteUserCmd;
import com.cloud.api.commands.DisableAccountCmd;
import com.cloud.api.commands.DisableUserCmd;
import com.cloud.api.commands.EnableAccountCmd;
import com.cloud.api.commands.EnableUserCmd;
import com.cloud.api.commands.ListResourceLimitsCmd;
import com.cloud.api.commands.LockUserCmd;
import com.cloud.api.commands.UpdateAccountCmd;
import com.cloud.api.commands.UpdateResourceLimitCmd;
import com.cloud.api.commands.UpdateUserCmd;
import com.cloud.configuration.Config;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.configuration.ResourceCount.ResourceType;
import com.cloud.configuration.ResourceLimitVO;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.configuration.dao.ResourceCountDao;
import com.cloud.configuration.dao.ResourceLimitDao;
import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventVO;
import com.cloud.event.dao.UsageEventDao;
import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.OperationTimedoutException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.NetworkManager;
import com.cloud.network.NetworkVO;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.security.SecurityGroupManager;
import com.cloud.network.security.dao.SecurityGroupDao;
import com.cloud.server.Criteria;
import com.cloud.storage.StorageManager;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.template.TemplateManager;
import com.cloud.user.Account.State;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserAccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.component.Adapters;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.component.Inject;
import com.cloud.utils.component.Manager;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GlobalLock;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.InstanceGroupVO;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.ReservationContextImpl;
import com.cloud.vm.UserVmManager;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.dao.InstanceGroupDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
@Local(value={AccountManager.class, AccountService.class})
public class AccountManagerImpl implements AccountManager, AccountService, Manager {
public static final Logger s_logger = Logger.getLogger(AccountManagerImpl.class);
private String _name;
@Inject private AccountDao _accountDao;
@Inject private DomainDao _domainDao;
@Inject private ResourceLimitDao _resourceLimitDao;
@Inject private ResourceCountDao _resourceCountDao;
@Inject private UserDao _userDao;
@Inject private InstanceGroupDao _vmGroupDao;
@Inject private UserAccountDao _userAccountDao;
@Inject private VolumeDao _volumeDao;
@Inject private UserVmDao _userVmDao;
@Inject private VMTemplateDao _templateDao;
@Inject private NetworkDao _networkDao;
@Inject private SecurityGroupDao _securityGroupDao;
@Inject private VMInstanceDao _vmDao;
@Inject private SecurityGroupManager _networkGroupMgr;
@Inject private NetworkManager _networkMgr;
@Inject private SnapshotManager _snapMgr;
@Inject private UserVmManager _vmMgr;
@Inject private StorageManager _storageMgr;
@Inject private TemplateManager _tmpltMgr;
@Inject private ConfigurationManager _configMgr;
@Inject private VirtualMachineManager _itMgr;
@Inject private UsageEventDao _usageEventDao;
private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AccountChecker"));
private final GlobalLock m_resourceCountLock = GlobalLock.getInternLock("resource.count");
UserVO _systemUser;
AccountVO _systemAccount;
@Inject(adapter=SecurityChecker.class)
Adapters<SecurityChecker> _securityCheckers;
int _cleanupInterval;
@Override
public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException {
_name = name;
_systemAccount = _accountDao.findById(AccountVO.ACCOUNT_ID_SYSTEM);
if (_systemAccount == null) {
throw new ConfigurationException("Unable to find the system account using " + Account.ACCOUNT_ID_SYSTEM);
}
_systemUser = _userDao.findById(UserVO.UID_SYSTEM);
if (_systemUser == null) {
throw new ConfigurationException("Unable to find the system user using " + User.UID_SYSTEM);
}
ComponentLocator locator = ComponentLocator.getCurrentLocator();
ConfigurationDao configDao = locator.getDao(ConfigurationDao.class);
Map<String, String> configs = configDao.getConfiguration(params);
String value = configs.get(Config.AccountCleanupInterval.key());
_cleanupInterval = NumbersUtil.parseInt(value, 60 * 60 * 24); // 1 hour.
return true;
}
@Override
public UserVO getSystemUser() {
return _systemUser;
}
@Override
public String getName() {
return _name;
}
@Override
public boolean start() {
_executor.scheduleAtFixedRate(new AccountCleanupTask(), _cleanupInterval, _cleanupInterval, TimeUnit.SECONDS);
return true;
}
@Override
public boolean stop() {
return true;
}
@Override
public void incrementResourceCount(long accountId, ResourceType type, Long...delta) {
long numToIncrement = (delta.length == 0) ? 1 : delta[0].longValue();
if (m_resourceCountLock.lock(120)) { // 2 minutes
try {
_resourceCountDao.updateAccountCount(accountId, type, true, numToIncrement);
// on a per-domain basis, increment the count
// FIXME: can this increment be done on the database side in a custom update statement?
Account account = _accountDao.findByIdIncludingRemoved(accountId);
Long domainId = account.getDomainId();
while (domainId != null) {
_resourceCountDao.updateDomainCount(domainId, type, true, numToIncrement);
DomainVO domain = _domainDao.findById(domainId);
domainId = domain.getParent();
}
} finally {
m_resourceCountLock.unlock();
}
}
}
@Override
public void decrementResourceCount(long accountId, ResourceType type, Long...delta) {
long numToDecrement = (delta.length == 0) ? 1 : delta[0].longValue();
if (m_resourceCountLock.lock(120)) { // 2 minutes
try {
_resourceCountDao.updateAccountCount(accountId, type, false, numToDecrement);
// on a per-domain basis, decrement the count
// FIXME: can this decrement be done on the database side in a custom update statement?
Account account = _accountDao.findByIdIncludingRemoved(accountId); // find all accounts, even removed accounts if this happens to be for an account that's being deleted
Long domainId = account.getDomainId();
while (domainId != null) {
_resourceCountDao.updateDomainCount(domainId, type, false, numToDecrement);
DomainVO domain = _domainDao.findById(domainId);
domainId = domain.getParent();
}
} finally {
m_resourceCountLock.unlock();
}
}
}
@Override
public long findCorrectResourceLimit(AccountVO account, ResourceType type) {
long max = -1;
// Check account
ResourceLimitVO limit = _resourceLimitDao.findByAccountIdAndType(account.getId(), type);
if (limit != null) {
max = limit.getMax().longValue();
} else {
// If the account has an infinite limit, check the ROOT domain
Long domainId = account.getDomainId();
while ((domainId != null) && (limit == null)) {
limit = _resourceLimitDao.findByDomainIdAndType(domainId, type);
DomainVO domain = _domainDao.findById(domainId);
domainId = domain.getParent();
}
if (limit != null) {
max = limit.getMax().longValue();
}
}
return max;
}
@Override
public long findCorrectResourceLimit(DomainVO domain, ResourceType type) {
long max = -1;
// Check account
ResourceLimitVO limit = _resourceLimitDao.findByDomainIdAndType(domain.getId(), type);
if (limit != null) {
max = limit.getMax().longValue();
} else {
// check domain hierarchy
Long domainId = domain.getParent();
while ((domainId != null) && (limit == null)) {
limit = _resourceLimitDao.findByDomainIdAndType(domainId, type);
DomainVO tmpDomain = _domainDao.findById(domainId);
domainId = tmpDomain.getParent();
}
if (limit != null) {
max = limit.getMax().longValue();
}
}
return max;
}
@Override
public boolean resourceLimitExceeded(Account account, ResourceType type, long...count) {
long numResources = ((count.length == 0) ? 1 : count[0]);
// Don't place any limits on system or admin accounts
long accountType = account.getType();
if (accountType == Account.ACCOUNT_TYPE_ADMIN || accountType == Account.ACCOUNT_ID_SYSTEM) {
return false;
}
if (m_resourceCountLock.lock(120)) { // 2 minutes
try {
// Check account
ResourceLimitVO limit = _resourceLimitDao.findByAccountIdAndType(account.getId(), type);
if (limit != null) {
long potentialCount = _resourceCountDao.getAccountCount(account.getId(), type) + numResources;
if (potentialCount > limit.getMax().longValue()) {
return true;
}
}
// check all domains in the account's domain hierarchy
Long domainId = account.getDomainId();
while (domainId != null) {
ResourceLimitVO domainLimit = _resourceLimitDao.findByDomainIdAndType(domainId, type);
if (domainLimit != null) {
long domainCount = _resourceCountDao.getDomainCount(domainId, type);
if ((domainCount + numResources) > domainLimit.getMax().longValue()) {
return true;
}
}
DomainVO domain = _domainDao.findById(domainId);
domainId = domain.getParent();
}
} finally {
m_resourceCountLock.unlock();
}
}
return false;
}
@Override
public long getResourceCount(AccountVO account, ResourceType type) {
return _resourceCountDao.getAccountCount(account.getId(), type);
}
@Override
public List<ResourceLimitVO> searchForLimits(Criteria c) {
Long id = (Long) c.getCriteria(Criteria.ID);
Long domainId = (Long) c.getCriteria(Criteria.DOMAINID);
Long accountId = (Long) c.getCriteria(Criteria.ACCOUNTID);
ResourceType type = (ResourceType) c.getCriteria(Criteria.TYPE);
// For 2.0, we are just limiting the scope to having an user retrieve
// limits for himself and if limits don't exist, use the ROOT domain's limits.
// - Will
List<ResourceLimitVO> limits = new ArrayList<ResourceLimitVO>();
if ((accountId != null) && (domainId != null)) {
//if domainId==ROOT_DOMAIN and account belongs to admin
//return all records for resource limits (bug 3778)
if (domainId == DomainVO.ROOT_DOMAIN) {
AccountVO account = _accountDao.findById(accountId);
if ((account != null) && (account.getType() == 1)) {
// account belongs to admin return all limits
limits = _resourceLimitDao.listAll();
return limits;
}
}
}
if (accountId != null) {
SearchBuilder<ResourceLimitVO> sb = _resourceLimitDao.createSearchBuilder();
sb.and("accountId", sb.entity().getAccountId(), SearchCriteria.Op.EQ);
sb.and("type", sb.entity().getType(), SearchCriteria.Op.EQ);
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
SearchCriteria<ResourceLimitVO> sc = sb.create();
if (accountId != null) {
sc.setParameters("accountId", accountId);
}
if (type != null) {
sc.setParameters("type", type);
}
if (id != null) {
sc.setParameters("id", id);
}
// Listing all limits for an account
if (type == null) {
//List<ResourceLimitVO> userLimits = _resourceLimitDao.search(sc, searchFilter);
List<ResourceLimitVO> userLimits = _resourceLimitDao.listByAccountId(accountId);
List<ResourceLimitVO> rootLimits = _resourceLimitDao.listByDomainId(DomainVO.ROOT_DOMAIN);
ResourceType resourceTypes[] = ResourceType.values();
for (ResourceType resourceType: resourceTypes) {
boolean found = false;
for (ResourceLimitVO userLimit : userLimits) {
if (userLimit.getType() == resourceType) {
limits.add(userLimit);
found = true;
break;
}
}
if (!found) {
// Check the ROOT domain
for (ResourceLimitVO rootLimit : rootLimits) {
if (rootLimit.getType() == resourceType) {
limits.add(rootLimit);
found = true;
break;
}
}
}
if (!found) {
limits.add(new ResourceLimitVO(domainId, accountId, resourceType, -1L));
}
}
} else {
AccountVO account = _accountDao.findById(accountId);
limits.add(new ResourceLimitVO(null, accountId, type, findCorrectResourceLimit(account, type)));
}
} else if (domainId != null) {
if (type == null) {
ResourceType resourceTypes[] = ResourceType.values();
List<ResourceLimitVO> domainLimits = _resourceLimitDao.listByDomainId(domainId);
for (ResourceType resourceType: resourceTypes) {
boolean found = false;
for (ResourceLimitVO domainLimit : domainLimits) {
if (domainLimit.getType() == resourceType) {
limits.add(domainLimit);
found = true;
break;
}
}
if (!found) {
limits.add(new ResourceLimitVO(domainId, null, resourceType, -1L));
}
}
} else {
limits.add(_resourceLimitDao.findByDomainIdAndType(domainId, type));
}
}
return limits;
}
@Override
public List<ResourceLimitVO> searchForLimits(ListResourceLimitsCmd cmd) throws InvalidParameterValueException, PermissionDeniedException {
String accountName = cmd.getAccountName();
Long domainId = cmd.getDomainId();
Long accountId = null;
Account account = UserContext.current().getCaller();
if ((account == null) ||
(account.getType() == Account.ACCOUNT_TYPE_ADMIN) ||
(account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) ||
(account.getType() == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN)) {
if (accountName != null) {
// Look up limits for the specified account
if (domainId == null) {
throw new InvalidParameterValueException("Failed to list limits for account " + accountName + " no domain id specified.");
}
Account userAccount = _accountDao.findActiveAccount(accountName, domainId);
if (userAccount == null) {
throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId);
} else if (account != null && (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || account.getType() == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN)) {
// If this is a non-root admin, make sure that the admin and the user account belong in the same domain or
// that the user account's domain is a child domain of the parent
if (account.getDomainId() != userAccount.getDomainId() && !_domainDao.isChildDomain(account.getDomainId(), userAccount.getDomainId())) {
throw new PermissionDeniedException("You do not have permission to access limits for this account: " + accountName);
}
}
accountId = userAccount.getId();
domainId = null;
} else if (domainId != null) {
// Look up limits for the specified domain
accountId = null;
} else if (account == null) {
// Look up limits for the ROOT domain
domainId = DomainVO.ROOT_DOMAIN;
} else {
// Look up limits for the admin's account
accountId = account.getId();
domainId = null;
}
} else {
// Look up limits for the user's account
accountId = account.getId();
domainId = null;
}
// Map resource type
ResourceType resourceType = null;
Integer type = cmd.getResourceType();
try {
if (type != null) {
resourceType = ResourceType.values()[type];
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new InvalidParameterValueException("Invalid resource type " + type + " given. Please specify a valid resource type.");
}
Criteria c = new Criteria("id", Boolean.FALSE, cmd.getStartIndex(), cmd.getPageSizeVal());
c.addCriteria(Criteria.ID, cmd.getId());
c.addCriteria(Criteria.DOMAINID, domainId);
c.addCriteria(Criteria.ACCOUNTID, accountId);
c.addCriteria(Criteria.TYPE, resourceType);
return searchForLimits(c);
}
@Override
public ResourceLimitVO updateResourceLimit(UpdateResourceLimitCmd cmd) {
Account account = UserContext.current().getCaller();
String accountName = cmd.getAccountName();
Long domainId = cmd.getDomainId();
Long max = cmd.getMax();
Integer type = cmd.getResourceType();
//Validate input
Long accountId = null;
if (max == null) {
max = new Long(-1);
} else if (max < -1) {
throw new InvalidParameterValueException("Please specify either '-1' for an infinite limit, or a limit that is at least '0'.");
}
// Map resource type
ResourceType resourceType;
try {
resourceType = ResourceType.values()[type];
} catch (ArrayIndexOutOfBoundsException e) {
throw new InvalidParameterValueException("Please specify a valid resource type.");
}
// Either a domainId or an accountId must be passed in, but not both.
if ((domainId == null) && (accountName == null)) {
throw new InvalidParameterValueException("Either a domainId or domainId/account must be passed in.");
}
if (account != null) {
if (domainId != null) {
if (!_domainDao.isChildDomain(account.getDomainId(), domainId)) {
throw new PermissionDeniedException("Unable to update resource limit for " + ((account.getAccountName() == null) ? "" : "account " + account.getAccountName() + " in ") + "domain " + domainId + ", permission denied");
}
} else if (account.getType() == Account.ACCOUNT_TYPE_ADMIN) {
domainId = DomainVO.ROOT_DOMAIN; // for root admin, default to root domain if domain is not specified
}
if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) {
if ((domainId != null) && (accountName == null) && domainId.equals(account.getDomainId())) {
// if the admin is trying to update their own domain, disallow...
throw new PermissionDeniedException("Unable to update resource limit for domain " + domainId + ", permission denied");
}
// If there is an existing ROOT domain limit, make sure its max isn't being exceeded
Criteria c = new Criteria();
c.addCriteria(Criteria.DOMAINID, DomainVO.ROOT_DOMAIN);
c.addCriteria(Criteria.TYPE, resourceType);
List<ResourceLimitVO> currentRootDomainLimits = searchForLimits(c);
ResourceLimitVO currentRootDomainLimit = (currentRootDomainLimits.size() == 0) ? null : currentRootDomainLimits.get(0);
if (currentRootDomainLimit != null) {
long currentRootDomainMax = currentRootDomainLimits.get(0).getMax();
if ((max == -1 && currentRootDomainMax != -1) || max > currentRootDomainMax) {
throw new InvalidParameterValueException("The current ROOT domain limit for resource type " + resourceType + " is " + currentRootDomainMax + " and cannot be exceeded.");
}
}
}
}
if (accountName != null) {
if (domainId == null) {
throw new InvalidParameterValueException("domainId parameter is required if account is specified");
}
Account userAccount = _accountDao.findActiveAccount(accountName, domainId);
if (userAccount == null) {
throw new InvalidParameterValueException("unable to find account by name " + account.getAccountName() + " in domain with id " + domainId);
}
accountId = userAccount.getId();
}
if (accountId != null) {
domainId = null;
}
// Check if the domain or account exists and is valid
if (accountId != null) {
AccountVO accountHandle = _accountDao.findById(accountId);
if (accountHandle == null) {
throw new InvalidParameterValueException("Please specify a valid account ID.");
} else if (accountHandle.getRemoved() != null) {
throw new InvalidParameterValueException("Please specify an active account.");
} else if (accountHandle.getType() == Account.ACCOUNT_TYPE_ADMIN || accountHandle.getType() == Account.ACCOUNT_ID_SYSTEM) {
throw new InvalidParameterValueException("Please specify a non-admin account.");
}
DomainVO domain = _domainDao.findById(accountHandle.getDomainId());
long parentMaximum = findCorrectResourceLimit(domain, resourceType);
if ((parentMaximum >= 0) && ((max.longValue() == -1) || (max.longValue() > parentMaximum))) {
throw new InvalidParameterValueException("Account " + account.getAccountName() + "(id: " + accountId + ") has maximum allowed resource limit " + parentMaximum +
" for " + type + ", please specify a value less that or equal to " + parentMaximum);
}
} else if (domainId != null) {
DomainVO domain = _domainDao.findById(domainId);
if (domain == null) {
throw new InvalidParameterValueException("Please specify a valid domain ID.");
} else if (domain.getRemoved() != null) {
throw new InvalidParameterValueException("Please specify an active domain.");
}
Long parentDomainId = domain.getParent();
if (parentDomainId != null) {
DomainVO parentDomain = _domainDao.findById(parentDomainId);
long parentMaximum = findCorrectResourceLimit(parentDomain, resourceType);
if ((parentMaximum >= 0) && (max.longValue() > parentMaximum)) {
throw new InvalidParameterValueException("Domain " + domain.getName() + "(id: " + domainId + ") has maximum allowed resource limit " + parentMaximum +
" for " + type + ", please specify a value less that or equal to " + parentMaximum);
}
}
}
// A valid limit type must be passed in
if (resourceType == null) {
throw new InvalidParameterValueException("A valid limit type must be passed in.");
}
// Check if a limit with the specified domainId/accountId/type combo already exists
Filter searchFilter = new Filter(ResourceLimitVO.class, null, false, null, null);
SearchCriteria<ResourceLimitVO> sc = _resourceLimitDao.createSearchCriteria();
if (domainId != null) {
sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
}
if (accountId != null) {
sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
}
if (resourceType != null) {
sc.addAnd("type", SearchCriteria.Op.EQ, resourceType);
}
List<ResourceLimitVO> limits = _resourceLimitDao.search(sc, searchFilter);
if (limits.size() == 1) {
ResourceLimitVO limit = limits.get(0);
//if limit is set to -1, remove the record
if (max != null && max.longValue() == -1L) {
//this parameter is needed by API as it expects the object to be returned and updates the UI with the object's new "max" parameter
ResourceLimitVO limitToReturn = limit;
limitToReturn.setMax(-1L);
_resourceLimitDao.remove(limit.getId());
return limitToReturn;
} else {
// Update the existing limit
_resourceLimitDao.update(limit.getId(), max);
return _resourceLimitDao.findById(limit.getId());
}
} else {
// Persist the new Limit
return _resourceLimitDao.persist(new ResourceLimitVO(domainId, accountId, resourceType, max));
}
}
@Override
public AccountVO getSystemAccount() {
if (_systemAccount == null) {
_systemAccount = _accountDao.findById(Account.ACCOUNT_ID_SYSTEM);
}
return _systemAccount;
}
@Override
public boolean isAdmin(short accountType) {
return ((accountType == Account.ACCOUNT_TYPE_ADMIN) ||
(accountType == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) ||
(accountType == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN));
}
@Override
public void checkAccess(Account caller, Domain domain) throws PermissionDeniedException {
for (SecurityChecker checker : _securityCheckers) {
if (checker.checkAccess(caller, domain)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Access granted to " + caller + " to " + domain + " by " + checker.getName());
}
return;
}
}
assert false : "How can all of the security checkers pass on checking this caller?";
throw new PermissionDeniedException("There's no way to confirm " + caller + " has access to " + domain);
}
@Override
public void checkAccess(Account caller, ControlledEntity... entities) {
HashMap<Long, List<ControlledEntity>> domains = new HashMap<Long, List<ControlledEntity>>();
for (ControlledEntity entity : entities) {
if (entity.getAccountId() != -1 && entity.getDomainId() != -1) {
List<ControlledEntity> toBeChecked = domains.get(entity.getDomainId());
if (toBeChecked == null) {
toBeChecked = new ArrayList<ControlledEntity>();
domains.put(entity.getDomainId(), toBeChecked);
}
toBeChecked.add(entity);
}
boolean granted = false;
for (SecurityChecker checker : _securityCheckers) {
if (checker.checkAccess(caller, entity)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Access to " + entity + " granted to " + caller + " by " + checker.getName());
}
granted = true;
break;
}
}
if (!granted) {
assert false : "How can all of the security checkers pass on checking this check: " + entity;
throw new PermissionDeniedException("There's no way to confirm " + caller + " has access to " + entity);
}
}
for (Map.Entry<Long, List<ControlledEntity>> domain : domains.entrySet()) {
for (SecurityChecker checker : _securityCheckers) {
Domain d = _domainDao.findById(domain.getKey());
if (d == null || d.getRemoved() != null) {
throw new PermissionDeniedException("Domain is not found.", caller, domain.getValue());
}
try {
checker.checkAccess(caller, d);
} catch (PermissionDeniedException e) {
e.addDetails(caller, domain.getValue());
throw e;
}
}
}
}
private boolean doSetUserStatus(long userId, State state) {
UserVO userForUpdate = _userDao.createForUpdate();
userForUpdate.setState(state);
return _userDao.update(Long.valueOf(userId), userForUpdate);
}
public boolean enableAccount(long accountId) {
boolean success = false;
AccountVO acctForUpdate = _accountDao.createForUpdate();
acctForUpdate.setState(State.enabled);
success = _accountDao.update(Long.valueOf(accountId), acctForUpdate);
return success;
}
private boolean lockAccountInternal(long accountId) {
boolean success = false;
Account account = _accountDao.findById(accountId);
if (account != null) {
if (account.getState().equals(State.locked)) {
return true; // already locked, no-op
} else if (account.getState().equals(State.enabled)) {
AccountVO acctForUpdate = _accountDao.createForUpdate();
acctForUpdate.setState(State.locked);
success = _accountDao.update(Long.valueOf(accountId), acctForUpdate);
} else {
if (s_logger.isInfoEnabled()) {
s_logger.info("Attempting to lock a non-enabled account, current state is " + account.getState() + " (accountId: " + accountId + "), locking failed.");
}
}
} else {
s_logger.warn("Failed to lock account " + accountId + ", account not found.");
}
return success;
}
@Override
public boolean deleteAccount(AccountVO account, long callerUserId, Account caller) {
long accountId = account.getId();
try {
if (!_accountDao.remove(accountId)) {
s_logger.error("Unable to delete account " + accountId);
return false;
}
List<UserVO> users = _userDao.listByAccount(accountId);
for(UserVO user : users){
_userDao.remove(user.getId());
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Remove account " + accountId);
}
cleanupAccount(account, callerUserId, caller);
return true;
} catch (Exception e) {
s_logger.error("exception deleting account: " + accountId, e);
return false;
}
}
@Override
public boolean cleanupAccount(AccountVO account, long callerUserId, Account caller) throws ConcurrentOperationException, ResourceUnavailableException{
long accountId = account.getId();
boolean accountCleanupNeeded = false;
try {
//delete all vm groups belonging to accont
List<InstanceGroupVO> groups = _vmGroupDao.listByAccountId(accountId);
for (InstanceGroupVO group : groups) {
if (!_vmMgr.deleteVmGroup(group.getId())) {
s_logger.error("Unable to delete group: " + group.getId());
accountCleanupNeeded = true;
}
}
// Delete the snapshots dir for the account. Have to do this before destroying the VMs.
boolean success = _snapMgr.deleteSnapshotDirsForAccount(accountId);
if (success) {
s_logger.debug("Successfully deleted snapshots directories for all volumes under account " + accountId + " across all zones");
}
// clean up templates
List<VMTemplateVO> userTemplates = _templateDao.listByAccountId(accountId);
boolean allTemplatesDeleted = true;
for (VMTemplateVO template : userTemplates) {
try {
allTemplatesDeleted = _tmpltMgr.delete(callerUserId, template.getId(), null);
} catch (Exception e) {
s_logger.warn("Failed to delete template while removing account: " + template.getName() + " due to: " + e.getMessage());
allTemplatesDeleted = false;
}
}
if (!allTemplatesDeleted) {
s_logger.warn("Failed to delete templates while removing account id=" + accountId);
accountCleanupNeeded = true;
}
// Destroy the account's VMs
List<UserVmVO> vms = _userVmDao.listByAccountId(accountId);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Destroying # of vms (accountId=" + accountId + "): " + vms.size());
}
for (UserVmVO vm : vms) {
if (!_vmMgr.expunge(vm, callerUserId, caller)) {
s_logger.error("Unable to destroy vm: " + vm.getId());
accountCleanupNeeded = true;
}
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_DESTROY, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getName(), vm.getServiceOfferingId(), vm.getTemplateId(), null);
_usageEventDao.persist(usageEvent);
}
// Mark the account's volumes as destroyed
List<VolumeVO> volumes = _volumeDao.findDetachedByAccount(accountId);
for (VolumeVO volume : volumes) {
if(!volume.getState().equals(Volume.State.Destroy)) {
_storageMgr.destroyVolume(volume);
if(volume.getPoolId() != null){
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(),
volume.getName(), null, null, null);
_usageEventDao.persist(usageEvent);
}
}
}
//Cleanup security groups
int numRemoved = _securityGroupDao.removeByAccountId(accountId);
s_logger.info("deleteAccount: Deleted " + numRemoved + " network groups for account " + accountId);
//Delete all the networks
boolean networksDeleted = true;
s_logger.debug("Deleting networks for account " + account.getId());
List<NetworkVO> networks = _networkDao.listByOwner(accountId);
if (networks != null) {
for (NetworkVO network : networks) {
ReservationContext context = new ReservationContextImpl(null, null, getActiveUser(callerUserId), account);
if (!_networkMgr.deleteNetworkInternal(network.getId(), context)) {
s_logger.warn("Unable to destroy network " + network + " as a part of account id=" + accountId +" cleanup.");
accountCleanupNeeded = true;
networksDeleted = false;
} else {
s_logger.debug("Network " + network.getId() + " successfully deleted as a part of account id=" + accountId + " cleanup.");
}
}
}
//delete account specific vlans - only when networks are cleaned up successfully
if (networksDeleted) {
if (!_configMgr.deleteAccountSpecificVirtualRanges(accountId)){
accountCleanupNeeded = true;
} else {
s_logger.debug("Account specific Virtual IP ranges " + " are successfully deleted as a part of account id=" + accountId + " cleanup.");
}
}
return true;
} finally {
s_logger.info("Cleanup for account " + account.getId() + (accountCleanupNeeded ? " is needed." : " is not needed."));
if (accountCleanupNeeded) {
_accountDao.markForCleanup(accountId);
}
}
}
@Override
public boolean disableAccount(long accountId) throws ConcurrentOperationException, ResourceUnavailableException{
boolean success = false;
if (accountId <= 2) {
if (s_logger.isInfoEnabled()) {
s_logger.info("disableAccount -- invalid account id: " + accountId);
}
return false;
}
AccountVO account = _accountDao.findById(accountId);
if ((account == null) || account.getState().equals(State.disabled)) {
success = true;
} else {
AccountVO acctForUpdate = _accountDao.createForUpdate();
acctForUpdate.setState(State.disabled);
success = _accountDao.update(Long.valueOf(accountId), acctForUpdate);
success = (success && doDisableAccount(accountId));
}
return success;
}
private boolean doDisableAccount(long accountId) throws ConcurrentOperationException, ResourceUnavailableException{
List<VMInstanceVO> vms = _vmDao.listByAccountId(accountId);
boolean success = true;
for (VMInstanceVO vm : vms) {
try {
try {
success = (success && _itMgr.advanceStop(vm, true, getSystemUser(), getSystemAccount()));
} catch (OperationTimedoutException ote) {
s_logger.warn("Operation for stopping vm timed out, unable to stop vm " + vm.getName(),ote);
success = false;
}
} catch (AgentUnavailableException aue) {
s_logger.warn("Agent running on host " + vm.getHostId() + " is unavailable, unable to stop vm " + vm.getName(),aue);
success = false;
}
}
return success;
}
/////////////////////////////////////////////////////
//////////////// API commands /////////////////////
/////////////////////////////////////////////////////
@Override
public UserAccount createAccount(CreateAccountCmd cmd) {
Long accountId = null;
String username = cmd.getUsername();
String password = cmd.getPassword();
String firstName = cmd.getFirstname();
String lastName = cmd.getLastname();
Long domainId = cmd.getDomainId();
String email = cmd.getEmail();
String timezone = cmd.getTimezone();
String accountName = cmd.getAccountName();
short userType = cmd.getAccountType().shortValue();
try {
if (accountName == null) {
accountName = username;
}
if (domainId == null) {
domainId = DomainVO.ROOT_DOMAIN;
}
Account account = _accountDao.findActiveAccount(accountName, domainId);
if (account != null) {
throw new CloudRuntimeException("The specified account: "+account.getAccountName()+" already exists");
}
DomainVO domain = _domainDao.findById(domainId);
if(domain == null) {
throw new CloudRuntimeException("The domain "+domainId+" does not exist; unable to create account");
} else {
if(domain.getState().equals(Domain.State.Inactive)) {
throw new CloudRuntimeException("The account cannot be created as domain "+domain.getName()+" is being deleted");
}
}
if (!_userAccountDao.validateUsernameInDomain(username, domainId)) {
throw new CloudRuntimeException("The user " + username + " already exists in domain " + domainId);
}
if (accountId == null) {
if ((userType < Account.ACCOUNT_TYPE_NORMAL) || (userType > Account.ACCOUNT_TYPE_READ_ONLY_ADMIN)) {
throw new CloudRuntimeException("Invalid account type " + userType + " given; unable to create user");
}
// create a new account for the user
AccountVO newAccount = new AccountVO();
if (domainId == null) {
// root domain is default
domainId = DomainVO.ROOT_DOMAIN;
}
if ((domainId != DomainVO.ROOT_DOMAIN) && (userType == Account.ACCOUNT_TYPE_ADMIN)) {
throw new CloudRuntimeException("Invalid account type " + userType + " given for an account in domain " + domainId + "; unable to create user.");
}
newAccount.setAccountName(accountName);
newAccount.setDomainId(domainId);
newAccount.setType(userType);
newAccount.setState(State.enabled);
newAccount = _accountDao.persist(newAccount);
accountId = newAccount.getId();
}
if (accountId == null) {
throw new CloudRuntimeException("Failed to create account for user: " + username + "; unable to create user");
}
UserVO user = new UserVO();
user.setUsername(username);
user.setPassword(password);
user.setState(State.enabled);
user.setFirstname(firstName);
user.setLastname(lastName);
user.setAccountId(accountId.longValue());
user.setEmail(email);
user.setTimezone(timezone);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Creating user: " + username + ", account: " + accountName + " (id:" + accountId + "), domain: " + domainId + " timezone:"+ timezone);
}
UserVO dbUser = _userDao.persist(user);
_networkGroupMgr.createDefaultSecurityGroup(accountId);
if (!user.getPassword().equals(dbUser.getPassword())) {
throw new CloudRuntimeException("The user " + username + " being creating is using a password that is different than what's in the db");
}
return _userAccountDao.findById(dbUser.getId());
} catch (Exception e) {
if (e instanceof CloudRuntimeException) {
s_logger.info("unable to create user: " + e);
} else {
s_logger.warn("unknown exception creating user", e);
}
throw new CloudRuntimeException(e.getMessage());
}
}
@Override
public UserVO createUser(CreateUserCmd cmd){
String accountName = cmd.getAccountName();
Long domainId = cmd.getDomainId();
String userName = cmd.getUsername();
String password = cmd.getPassword();
String firstName = cmd.getFirstname();
String lastName = cmd.getLastname();
String email = cmd.getEmail();
String timeZone = cmd.getTimezone();
Long accountId = null;
Account account = _accountDao.findActiveAccount(accountName, domainId);
if( account == null){
throw new ServerApiException(BaseCmd.ACCOUNT_ERROR, "Unable to find account to create user");
}else{
accountId = account.getAccountId();
}
DomainVO domain = _domainDao.findById(domainId);
if(domain == null) {
throw new CloudRuntimeException("The domain "+domainId+" does not exist; unable to create user");
} else {
if(domain.getState().equals(Domain.State.Inactive)) {
throw new CloudRuntimeException("The user cannot be created as domain "+domain.getName()+" is being deleted");
}
}
if (!_userAccountDao.validateUsernameInDomain(userName, domainId)) {
throw new CloudRuntimeException("The user " + userName + " already exists in domain " + domainId);
}
UserVO user = new UserVO();
user.setUsername(userName);
user.setPassword(password);
user.setState(State.enabled);
user.setFirstname(firstName);
user.setLastname(lastName);
user.setAccountId(accountId.longValue());
user.setEmail(email);
user.setTimezone(timeZone);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Creating user: " + userName + ", account: " + accountName + " (id:" + accountId + "), domain: " + domainId + " timezone:"+ timeZone);
}
UserVO dbUser = _userDao.persist(user);
if (!user.getPassword().equals(dbUser.getPassword())) {
throw new CloudRuntimeException("The user " + userName + " being creating is using a password that is different than what's in the db");
}
return dbUser;
}
@Override
public UserAccount updateUser(UpdateUserCmd cmd) throws InvalidParameterValueException {
Long id = cmd.getId();
String apiKey = cmd.getApiKey();
String firstName = cmd.getFirstname();
String email = cmd.getEmail();
String lastName = cmd.getLastname();
String password = cmd.getPassword();
String secretKey = cmd.getSecretKey();
String timeZone = cmd.getTimezone();
String userName = cmd.getUsername();
//Input validation
UserVO user = _userDao.getUser(id);
if (user == null) {
throw new InvalidParameterValueException("unable to find user by id");
}
if((apiKey == null && secretKey != null) || (apiKey != null && secretKey == null)) {
throw new InvalidParameterValueException("Please provide an api key/secret key pair");
}
// If the account is an admin type, return an error. We do not allow this
Account account = _accountDao.findById(user.getAccountId());
if (account != null && (account.getId() == Account.ACCOUNT_ID_SYSTEM)) {
throw new PermissionDeniedException("user id : " + id + " is system account, update is not allowed");
}
if (firstName == null) {
firstName = user.getFirstname();
}
if (lastName == null) {
lastName = user.getLastname();
}
if (userName == null) {
userName = user.getUsername();
}
if (password == null) {
password = user.getPassword();
}
if (email == null) {
email = user.getEmail();
}
if (timeZone == null) {
timeZone = user.getTimezone();
}
if (apiKey == null) {
apiKey = user.getApiKey();
}
if (secretKey == null) {
secretKey = user.getSecretKey();
}
Long accountId = user.getAccountId();
if (s_logger.isDebugEnabled()) {
s_logger.debug("updating user with id: " + id);
}
try {
//check if the apiKey and secretKey are globally unique
if (apiKey != null && secretKey != null) {
Pair<User, Account> apiKeyOwner = _accountDao.findUserAccountByApiKey(apiKey);
if(apiKeyOwner != null) {
User usr = apiKeyOwner.first();
if (usr.getId() != id) {
throw new InvalidParameterValueException("The api key:"+apiKey+" exists in the system for user id:"+id+" ,please provide a unique key");
} else {
//allow the updation to take place
}
}
}
_userDao.update(id, userName, password, firstName, lastName, email, accountId, timeZone, apiKey, secretKey);
} catch (Throwable th) {
s_logger.error("error updating user", th);
throw new CloudRuntimeException("Unable to update user " + id);
}
return _userAccountDao.findById(id);
}
@Override
public UserAccount disableUser(DisableUserCmd cmd) throws InvalidParameterValueException, PermissionDeniedException{
Long userId = cmd.getId();
Account adminAccount = UserContext.current().getCaller();
//Check if user exists in the system
User user = _userDao.findById(userId);
if ((user == null) || (user.getRemoved() != null)) {
throw new InvalidParameterValueException("Unable to find active user by id " + userId);
}
// If the user is a System user, return an error
Account account = _accountDao.findById(user.getAccountId());
if ((account != null) && (account.getId() == Account.ACCOUNT_ID_SYSTEM)) {
throw new InvalidParameterValueException("User id : " + userId + " is a system user, disabling is not allowed");
}
if ((adminAccount != null) && !_domainDao.isChildDomain(adminAccount.getDomainId(), account.getDomainId())) {
throw new PermissionDeniedException("Failed to disable user " + userId + ", permission denied.");
}
boolean success = doSetUserStatus(userId, State.disabled);
if (success) {
//user successfully disabled
return _userAccountDao.findById(userId);
} else {
throw new CloudRuntimeException("Unable to disable user " + userId);
}
}
@Override
public UserAccount enableUser(EnableUserCmd cmd) throws InvalidParameterValueException, PermissionDeniedException{
Long userId = cmd.getId();
Account adminAccount = UserContext.current().getCaller();
boolean success = false;
//Check if user exists in the system
User user = _userDao.findById(userId);
if ((user == null) || (user.getRemoved() != null)) {
throw new InvalidParameterValueException("Unable to find active user by id " + userId);
}
// If the user is a System user, return an error
Account account = _accountDao.findById(user.getAccountId());
if ((account != null) && (account.getId() == Account.ACCOUNT_ID_SYSTEM)) {
throw new InvalidParameterValueException("User id : " + userId + " is a system user, enabling is not allowed");
}
if ((adminAccount != null) && !_domainDao.isChildDomain(adminAccount.getDomainId(), account.getDomainId())) {
throw new PermissionDeniedException("Failed to enable user " + userId + ", permission denied.");
}
success = doSetUserStatus(userId, State.enabled);
// make sure the account is enabled too
success = (success && enableAccount(user.getAccountId()));
if (success) {
return _userAccountDao.findById(userId);
} else {
throw new CloudRuntimeException("Unable to enable user " + userId);
}
}
@Override
public UserAccount lockUser(LockUserCmd cmd) {
boolean success = false;
Account adminAccount = UserContext.current().getCaller();
Long id = cmd.getId();
// Check if user with id exists in the system
User user = _userDao.findById(id);
if (user == null) {
throw new InvalidParameterValueException("Unable to find user by id");
} else if (user.getRemoved() != null) {
throw new InvalidParameterValueException("Unable to find user by id");
}
// If the user is a System user, return an error. We do not allow this
Account account = _accountDao.findById(user.getAccountId());
if ((account != null) && (account.getId() == Account.ACCOUNT_ID_SYSTEM)) {
throw new PermissionDeniedException("user id : " + id + " is a system user, locking is not allowed");
}
if ((adminAccount != null) && !_domainDao.isChildDomain(adminAccount.getDomainId(), account.getDomainId())) {
throw new PermissionDeniedException("Failed to lock user " + id + ", permission denied.");
}
// make sure the account is enabled too
// if the user is either locked already or disabled already, don't change state...only lock currently enabled users
if (user.getState().equals(State.locked)) {
// already locked...no-op
return _userAccountDao.findById(id);
} else if (user.getState().equals(State.enabled)) {
success = doSetUserStatus(user.getId(), State.locked);
boolean lockAccount = true;
List<UserVO> allUsersByAccount = _userDao.listByAccount(user.getAccountId());
for (UserVO oneUser : allUsersByAccount) {
if (oneUser.getState().equals(State.enabled)) {
lockAccount = false;
break;
}
}
if (lockAccount) {
success = (success && lockAccountInternal(user.getAccountId()));
}
} else {
if (s_logger.isInfoEnabled()) {
s_logger.info("Attempting to lock a non-enabled user, current state is " + user.getState() + " (userId: " + user.getId() + "), locking failed.");
}
}
if (success) {
return _userAccountDao.findById(id);
} else {
throw new CloudRuntimeException("Unable to lock user " + id);
}
}
@Override
//This method deletes the account
public boolean deleteUserAccount(DeleteAccountCmd cmd) {
UserContext ctx = UserContext.current();
long callerUserId = ctx.getCallerUserId();
Account caller = ctx.getCaller();
Long accountId = cmd.getId();
// If the user is a System user, return an error. We do not allow this
AccountVO account = _accountDao.findById(accountId);
if ((account != null) && (account.getId() == Account.ACCOUNT_ID_SYSTEM)) {
throw new PermissionDeniedException("Account id : " + accountId + " is a system account, delete is not allowed");
}
if(account == null){
throw new InvalidParameterValueException("The specified account does not exist in the system");
}
if(account.getRemoved() != null){
s_logger.info("The account:"+account.getAccountName()+" is already removed");
return true;
}
return deleteAccount(account, callerUserId, caller);
}
@Override
public AccountVO enableAccount(EnableAccountCmd cmd) throws InvalidParameterValueException, PermissionDeniedException{
String accountName = cmd.getAccountName();
Long domainId = cmd.getDomainId();
boolean success = false;
Account account = _accountDao.findActiveAccount(accountName, domainId);
//Check if account exists
if (account == null) {
s_logger.error("Unable to find account " + accountName + " in domain " + domainId);
throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId);
}
//Don't allow to modify system account
if (account.getId() == Account.ACCOUNT_ID_SYSTEM) {
throw new InvalidParameterValueException ("Can not modify system account");
}
//Check if user performing the action is allowed to modify this account
Account adminAccount = UserContext.current().getCaller();
if ((adminAccount != null) && !_domainDao.isChildDomain(adminAccount.getDomainId(), account.getDomainId())) {
throw new PermissionDeniedException("Invalid account " + accountName + " in domain " + domainId + " given, permission denied");
}
success = enableAccount(account.getId());
if (success) {
return _accountDao.findById(account.getId());
} else {
throw new CloudRuntimeException("Unable to enable account " + accountName + " in domain " + domainId);
}
}
@Override
public AccountVO lockAccount(DisableAccountCmd cmd) {
Account adminAccount = UserContext.current().getCaller();
Long domainId = cmd.getDomainId();
String accountName = cmd.getAccountName();
if ((adminAccount != null) && !_domainDao.isChildDomain(adminAccount.getDomainId(), domainId)) {
throw new PermissionDeniedException("Failed to lock account " + accountName + " in domain " + domainId + ", permission denied.");
}
Account account = _accountDao.findActiveAccount(accountName, domainId);
if (account == null) {
throw new InvalidParameterValueException("Unable to find active account with name " + accountName + " in domain " + domainId);
}
// don't allow modify system account
if (account.getId() == Account.ACCOUNT_ID_SYSTEM) {
throw new InvalidParameterValueException("can not lock system account");
}
if (lockAccountInternal(account.getId())) {
return _accountDao.findById(account.getId());
} else {
throw new CloudRuntimeException("Unable to lock account " + accountName + " in domain " + domainId);
}
}
@Override
public AccountVO disableAccount(DisableAccountCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, ConcurrentOperationException, ResourceUnavailableException {
String accountName = cmd.getAccountName();
Long domainId = cmd.getDomainId();
Account adminAccount = UserContext.current().getCaller();
if ((adminAccount != null) && !_domainDao.isChildDomain(adminAccount.getDomainId(), domainId)) {
throw new PermissionDeniedException("Failed to disable account " + accountName + " in domain " + domainId + ", permission denied.");
}
Account account = _accountDao.findActiveAccount(accountName, domainId);
if (account == null) {
throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId);
}
if (disableAccount(account.getId())) {
return _accountDao.findById(account.getId());
} else {
throw new CloudRuntimeException("Unable to update account " + accountName + " in domain " + domainId);
}
}
@Override
public AccountVO updateAccount(UpdateAccountCmd cmd) throws InvalidParameterValueException, PermissionDeniedException{
Long domainId = cmd.getDomainId();
String accountName = cmd.getAccountName();
String newAccountName = cmd.getNewName();
boolean success = false;
Account account = _accountDao.findAccount(accountName, domainId);
//Check if account exists
if (account == null) {
s_logger.error("Unable to find account " + accountName + " in domain " + domainId);
throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId);
}
//Don't allow to modify system account
if (account.getId() == Account.ACCOUNT_ID_SYSTEM) {
throw new InvalidParameterValueException ("Can not modify system account");
}
//Check if user performing the action is allowed to modify this account
Account adminAccount = UserContext.current().getCaller();
if ((adminAccount != null) && (adminAccount.getType() != Account.ACCOUNT_TYPE_ADMIN) && _domainDao.isChildDomain(adminAccount.getDomainId(), account.getDomainId())) {
throw new PermissionDeniedException("Invalid account " + accountName + " in domain " + domainId + " given, permission denied");
}
//check if the given account name is unique in this domain for updating
Account duplicateAcccount = _accountDao.findAccount(newAccountName, domainId);
if(duplicateAcccount != null && duplicateAcccount.getRemoved() == null && duplicateAcccount.getId() != account.getId()){//allow same account to update itself
throw new PermissionDeniedException("There already exists an account with the name:"+newAccountName+" in the domain:"+domainId+" with existing account id:"+duplicateAcccount.getId());
}
if (account.getAccountName().equals(newAccountName)) {
success = true;
} else {
AccountVO acctForUpdate = _accountDao.createForUpdate();
acctForUpdate.setAccountName(newAccountName);
success = _accountDao.update(Long.valueOf(account.getId()), acctForUpdate);
}
if (success) {
return _accountDao.findById(account.getId());
} else {
throw new CloudRuntimeException("Unable to update account " + accountName + " in domain " + domainId);
}
}
@Override
public boolean deleteUser(DeleteUserCmd deleteUserCmd) {
long id = deleteUserCmd.getId();
UserVO user = _userDao.findById(id);
if(user == null) {
throw new InvalidParameterValueException("The specified user doesn't exist in the system");
}
if ((user != null) && (user.getAccountId() == Account.ACCOUNT_ID_SYSTEM)) {
throw new InvalidParameterValueException("Account id : " + user.getAccountId() + " is a system account, delete for user associated with this account is not allowed");
}
return _userDao.remove(id);
}
protected class AccountCleanupTask implements Runnable {
@Override
public void run() {
try {
GlobalLock lock = GlobalLock.getInternLock("AccountCleanup");
if (lock == null) {
s_logger.debug("Couldn't get the global lock");
return;
}
if (!lock.lock(30)) {
s_logger.debug("Couldn't lock the db");
return;
}
Transaction txn = null;
try {
txn = Transaction.open(Transaction.CLOUD_DB);
List<AccountVO> accounts = _accountDao.findCleanups();
s_logger.info("Found " + accounts.size() + " accounts to cleanup");
for (AccountVO account : accounts) {
s_logger.debug("Cleaning up " + account.getId());
try {
cleanupAccount(account, getSystemUser().getId(), getSystemAccount());
} catch (Exception e) {
s_logger.error("Skipping due to error on account " + account.getId(), e);
}
}
} catch (Exception e) {
s_logger.error("Exception ", e);
} finally {
if(txn != null) {
txn.close();
}
lock.unlock();
}
} catch (Exception e) {
s_logger.error("Exception ", e);
}
}
}
@Override
public Account finalizeOwner(Account caller, String accountName, Long domainId) {
//don't default the owner to the system account
if (caller.getId() == Account.ACCOUNT_ID_SYSTEM && (accountName == null || domainId == null)) {
throw new InvalidParameterValueException("Account and domainId are needed for resource creation");
}
if (isAdmin(caller.getType()) && accountName != null && domainId != null) {
DomainVO domain = _domainDao.findById(domainId);
if (domain == null) {
throw new InvalidParameterValueException("Unable to find the domain by id=" + domainId);
}
Account owner = _accountDao.findActiveAccount(accountName, domainId);
if (owner == null) {
throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId);
}
checkAccess(caller, domain);
return owner;
} else if (!isAdmin(caller.getType()) && accountName != null && domainId != null) {
if (!accountName.equals(caller.getAccountName()) || domainId.longValue() != caller.getDomainId()) {
throw new PermissionDeniedException("Can't create/list resources for account " + accountName + " in domain " + domainId + ", permission denied");
} else {
return caller;
}
} else {
if ((accountName == null && domainId != null) || (accountName != null && domainId == null)) {
throw new InvalidParameterValueException("AccountName and domainId must be specified together");
}
//regular user can't create/list resources for other people
return caller;
}
}
@Override
public Account getActiveAccount(String accountName, Long domainId) {
if (accountName == null || domainId == null) {
throw new InvalidParameterValueException("Both accountName and domainId are required for finding active account in the system");
} else {
return _accountDao.findActiveAccount(accountName, domainId);
}
}
@Override
public Account getActiveAccount(Long accountId) {
if (accountId == null) {
throw new InvalidParameterValueException("AccountId is required by account search");
} else {
return _accountDao.findById(accountId);
}
}
@Override
public Account getAccount(Long accountId) {
if (accountId == null) {
throw new InvalidParameterValueException("AccountId is required by account search");
} else {
return _accountDao.findByIdIncludingRemoved(accountId);
}
}
@Override
public User getActiveUser(long userId) {
return _userDao.findById(userId);
}
@Override
public Domain getDomain(long domainId) {
return _domainDao.findById(domainId);
}
@Override
public Pair<String, Long> finalizeAccountDomainForList(Account caller, String accountName, Long domainId) {
if (isAdmin(caller.getType())) {
if (domainId == null && accountName != null) {
throw new InvalidParameterValueException("accountName and domainId might be specified together");
} else if (domainId != null){
Domain domain = getDomain(domainId);
if (domain == null) {
throw new InvalidParameterValueException("Unable to find the domain by id=" + domainId);
}
checkAccess(caller, domain);
if (accountName != null) {
Account owner = getActiveAccount(accountName, domainId);
if (owner == null) {
throw new InvalidParameterValueException("Unable to find account with name " + accountName + " in domain id=" + domainId);
}
}
}
} else if (accountName != null && domainId != null) {
if (!accountName.equals(caller.getAccountName()) || domainId.longValue() != caller.getDomainId()) {
throw new PermissionDeniedException("Can't list port forwarding rules for account " + accountName + " in domain " + domainId + ", permission denied");
}
} else {
accountName = caller.getAccountName();
domainId = caller.getDomainId();
}
return new Pair<String, Long>(accountName, domainId);
}
}