bug 11036: resource count update is refactored

status 11036: resolved fixed

1) Use row locks instead of global lock when update resource_count table. When update resource_count for account, make sure that we lock account+all related domains
2) Insert resource_count records for account/domain at the moment when account/domain is created.
3) As a part of DB upgrade, insert missing resource_count records for all non-removed accounts/domains

Conflicts:

	core/src/com/cloud/alert/AlertManager.java
	server/test/com/cloud/agent/MockAgentManagerImpl.java
This commit is contained in:
alena 2011-09-13 10:46:04 -07:00
parent e981546067
commit f6a79c603f
28 changed files with 562 additions and 454 deletions

View File

@ -81,7 +81,7 @@ public class CreateDomainCmd extends BaseCmd {
@Override
public void execute(){
UserContext.current().setEventDetails("Domain Name: "+getDomainName()+((getParentDomainId()!=null)?", Parent DomainId :"+getParentDomainId():""));
Domain domain = _mgr.createDomain(this);
Domain domain = _accountService.createDomain(this);
if (domain != null) {
DomainResponse response = _responseGenerator.createDomainResponse(domain);
response.setResponseName(getCommandName());

View File

@ -19,6 +19,8 @@
package com.cloud.configuration;
public interface ResourceLimit {
public static enum OwnerType {Account, Domain}
public Long getId();

View File

@ -251,15 +251,6 @@ public interface ManagementService {
List<? extends Domain> searchForDomainChildren(ListDomainChildrenCmd cmd);
/**
* create a new domain
*
* @param command
* - the create command defining the name to use and the id of the parent domain under which to create the new
* domain.
*/
Domain createDomain(CreateDomainCmd command);
/**
* delete a domain with the given domainId
*

View File

@ -21,6 +21,7 @@ import java.util.List;
import java.util.Set;
import com.cloud.api.commands.CreateAccountCmd;
import com.cloud.api.commands.CreateDomainCmd;
import com.cloud.api.commands.CreateUserCmd;
import com.cloud.api.commands.DeleteAccountCmd;
import com.cloud.api.commands.DeleteUserCmd;
@ -31,11 +32,11 @@ 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.UpdateResourceCountCmd;
import com.cloud.api.commands.UpdateResourceLimitCmd;
import com.cloud.api.commands.UpdateUserCmd;
import com.cloud.configuration.ResourceLimit;
import com.cloud.configuration.ResourceCount;
import com.cloud.configuration.ResourceLimit;
import com.cloud.domain.Domain;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.ResourceUnavailableException;
@ -197,4 +198,6 @@ public interface AccountService {
Set<Long> getDomainChildrenIds(String parentDomainPath);
Domain createDomain(CreateDomainCmd cmd);
}

View File

@ -122,5 +122,8 @@
<dao name="NetworkDao" class="com.cloud.network.dao.NetworkDaoImpl" singleton="false"/>
<dao name="IpAddressDao" class="com.cloud.network.dao.IPAddressDaoImpl" singleton="false"/>
<dao name="VlanDao" class="com.cloud.dc.dao.VlanDaoImpl" singleton="false"/>
<dao name="ResouceCountDao" class="com.cloud.configuration.dao.ResourceCountDaoImpl" singleton="false"/>
<dao name="AccountDao" class="com.cloud.user.dao.AccountDaoImpl" singleton="false"/>
<dao name="UserDao" class="com.cloud.user.dao.UserDaoImpl" singleton="false"/>
</configuration-server>
</components.xml>

View File

@ -43,7 +43,8 @@ public interface AlertManager extends Manager {
public static final short ALERT_TYPE_SSVM = 18;
public static final short ALERT_TYPE_USAGE_SERVER_RESULT = 19; // Usage job result
public static final short ALERT_TYPE_STORAGE_DELETE = 20;
public static final short ALERT_TYPE_USAGE_SANITY_RESULT = 21;
public static final short ALERT_TYPE_UPDATE_RESOURCE_COUNT = 21; // Generated when we fail to update the resource count
public static final short ALERT_TYPE_USAGE_SANITY_RESULT = 22;
void clearAlert(short alertType, long dataCenterId, long podId);

View File

@ -97,4 +97,9 @@ public class ResourceCountVO implements ResourceCount {
public void setCount(long count) {
this.count = count;
}
@Override
public String toString() {
return new StringBuilder("REsourceCount[").append("-").append(id).append("-").append(type).append("-").append(accountId).append("-").append(domainId).append("]").toString();
}
}

View File

@ -266,7 +266,7 @@ public class ApiDBUtils {
return -1;
}
return _accountMgr.findCorrectResourceLimit(account, type);
return _accountMgr.findCorrectResourceLimit(account.getAccountId(), type);
}
public static AsyncJobVO findInstancePendingAsyncJob(String instanceType, long instanceId) {

View File

@ -117,7 +117,6 @@ import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.test.IPRangeConfig;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO;
import com.cloud.user.User;
import com.cloud.user.UserContext;
import com.cloud.user.dao.AccountDao;
@ -2050,7 +2049,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura
if (forVirtualNetwork) {
if (account != null) {
// verify resource limits
long ipResourceLimit = _accountMgr.findCorrectResourceLimit((AccountVO) account, ResourceType.public_ip);
long ipResourceLimit = _accountMgr.findCorrectResourceLimit(account.getId(), ResourceType.public_ip);
long accountIpRange = NetUtils.ip2Long(endIP) - NetUtils.ip2Long(startIP) + 1;
if (s_logger.isDebugEnabled()) {
s_logger.debug(" IPResourceLimit " + ipResourceLimit + " accountIpRange " + accountIpRange);

View File

@ -18,8 +18,11 @@
package com.cloud.configuration.dao;
import com.cloud.configuration.ResourceCountVO;
import java.util.Set;
import com.cloud.configuration.ResourceCount.ResourceType;
import com.cloud.configuration.ResourceCountVO;
import com.cloud.configuration.ResourceLimit.OwnerType;
import com.cloud.utils.db.GenericDao;
public interface ResourceCountDao extends GenericDao<ResourceCountVO, Long> {
@ -55,15 +58,6 @@ public interface ResourceCountDao extends GenericDao<ResourceCountVO, Long> {
* @param the count of resources in use for the given type and domain
*/
public void setDomainCount(long domainId, ResourceType type, long count);
/**
* Update the count of resources in use for the given account and given resource type
* @param accountId the id of the account to update resource count
* @param type the type of resource (e.g. user_vm, public_ip, volume)
* @param increment whether the change is adding or subtracting from the current count
* @param delta the number of resources being added/released
*/
public void updateAccountCount(long accountId, ResourceType type, boolean increment, long delta);
/**
* Update the count of resources in use for the given domain and given resource type
@ -73,4 +67,17 @@ public interface ResourceCountDao extends GenericDao<ResourceCountVO, Long> {
* @param delta the number of resources being added/released
*/
public void updateDomainCount(long domainId, ResourceType type, boolean increment, long delta);
boolean updateById(long id, boolean increment, long delta);
ResourceCountVO findByDomainIdAndType(long domainId, ResourceType type);
ResourceCountVO findByAccountIdAndType(long accountId, ResourceType type);
Set<Long> listAllRowsToUpdateForAccount(long accountId, long domainId, ResourceType type);
Set<Long> listRowsToUpdateForDomain(long domainId, ResourceType type);
void createResourceCounts(long ownerId, OwnerType ownerType);
}

View File

@ -18,18 +18,29 @@
package com.cloud.configuration.dao;
import java.util.HashSet;
import java.util.Set;
import javax.ejb.Local;
import com.cloud.configuration.ResourceCount.ResourceType;
import com.cloud.configuration.ResourceCount;
import com.cloud.configuration.ResourceCountVO;
import com.cloud.configuration.ResourceLimit;
import com.cloud.domain.dao.DomainDaoImpl;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
@Local(value={ResourceCountDao.class})
public class ResourceCountDaoImpl extends GenericDaoBase<ResourceCountVO, Long> implements ResourceCountDao {
private SearchBuilder<ResourceCountVO> IdTypeSearch;
private SearchBuilder<ResourceCountVO> DomainIdTypeSearch;
protected final DomainDaoImpl _domainDao = ComponentLocator.inject(DomainDaoImpl.class);
public ResourceCountDaoImpl() {
IdTypeSearch = createSearchBuilder();
@ -43,11 +54,8 @@ public class ResourceCountDaoImpl extends GenericDaoBase<ResourceCountVO, Long>
DomainIdTypeSearch.done();
}
private ResourceCountVO findByAccountIdAndType(long accountId, ResourceType type) {
if (type == null) {
return null;
}
@Override
public ResourceCountVO findByAccountIdAndType(long accountId, ResourceType type) {
SearchCriteria<ResourceCountVO> sc = IdTypeSearch.create();
sc.setParameters("accountId", accountId);
sc.setParameters("type", type);
@ -55,11 +63,8 @@ public class ResourceCountDaoImpl extends GenericDaoBase<ResourceCountVO, Long>
return findOneIncludingRemovedBy(sc);
}
private ResourceCountVO findByDomainIdAndType(long domainId, ResourceType type) {
if (type == null) {
return null;
}
@Override
public ResourceCountVO findByDomainIdAndType(long domainId, ResourceType type) {
SearchCriteria<ResourceCountVO> sc = DomainIdTypeSearch.create();
sc.setParameters("domainId", domainId);
sc.setParameters("type", type);
@ -70,59 +75,29 @@ public class ResourceCountDaoImpl extends GenericDaoBase<ResourceCountVO, Long>
@Override
public long getAccountCount(long accountId, ResourceType type) {
ResourceCountVO resourceCountVO = findByAccountIdAndType(accountId, type);
return (resourceCountVO != null) ? resourceCountVO.getCount() : 0;
return resourceCountVO.getCount();
}
@Override
public long getDomainCount(long domainId, ResourceType type) {
ResourceCountVO resourceCountVO = findByDomainIdAndType(domainId, type);
return (resourceCountVO != null) ? resourceCountVO.getCount() : 0;
return resourceCountVO.getCount();
}
@Override
public void setAccountCount(long accountId, ResourceType type, long count) {
ResourceCountVO resourceCountVO = findByAccountIdAndType(accountId, type);
if (resourceCountVO == null) {
if (count != 0) {
resourceCountVO = new ResourceCountVO(accountId, null, type, count);
persist(resourceCountVO);
}
} else {
if (count != resourceCountVO.getCount()) {
resourceCountVO.setCount(count);
update(resourceCountVO.getId(), resourceCountVO);
}
if (count != resourceCountVO.getCount()) {
resourceCountVO.setCount(count);
update(resourceCountVO.getId(), resourceCountVO);
}
}
@Override
public void setDomainCount(long domainId, ResourceType type, long count) {
ResourceCountVO resourceCountVO = findByDomainIdAndType(domainId, type);
if (resourceCountVO == null) {
if (count != 0) {
resourceCountVO = new ResourceCountVO(null, domainId, type, count);
persist(resourceCountVO);
}
} else {
if (count != resourceCountVO.getCount()) {
resourceCountVO.setCount(count);
update(resourceCountVO.getId(), resourceCountVO);
}
}
}
@Override
public void updateAccountCount(long accountId, ResourceType type, boolean increment, long delta) {
delta = increment ? delta : delta * -1;
ResourceCountVO resourceCountVO = findByAccountIdAndType(accountId, type);
if (resourceCountVO == null) {
resourceCountVO = new ResourceCountVO(accountId, null, type, 0);
resourceCountVO.setCount(resourceCountVO.getCount() + delta);
persist(resourceCountVO);
} else {
resourceCountVO.setCount(resourceCountVO.getCount() + delta);
if (count != resourceCountVO.getCount()) {
resourceCountVO.setCount(count);
update(resourceCountVO.getId(), resourceCountVO);
}
}
@ -132,13 +107,63 @@ public class ResourceCountDaoImpl extends GenericDaoBase<ResourceCountVO, Long>
delta = increment ? delta : delta * -1;
ResourceCountVO resourceCountVO = findByDomainIdAndType(domainId, type);
if (resourceCountVO == null) {
resourceCountVO = new ResourceCountVO(null, domainId, type, 0);
resourceCountVO.setCount(resourceCountVO.getCount() + delta);
persist(resourceCountVO);
} else {
resourceCountVO.setCount(resourceCountVO.getCount() + delta);
update(resourceCountVO.getId(), resourceCountVO);
}
resourceCountVO.setCount(resourceCountVO.getCount() + delta);
update(resourceCountVO.getId(), resourceCountVO);
}
@Override
public boolean updateById(long id, boolean increment, long delta) {
delta = increment ? delta : delta * -1;
ResourceCountVO resourceCountVO = findById(id);
resourceCountVO.setCount(resourceCountVO.getCount() + delta);
return update(resourceCountVO.getId(), resourceCountVO);
}
@Override
public Set<Long> listAllRowsToUpdateForAccount(long accountId, long domainId, ResourceType type) {
Set<Long> rowIds = new HashSet<Long>();
//Create resource count records if not exist
//1) for account
ResourceCountVO accountCountRecord = findByAccountIdAndType(accountId, type);
rowIds.add(accountCountRecord.getId());
//2) for domain(s)
rowIds.addAll(listRowsToUpdateForDomain(domainId, type));
return rowIds;
}
@Override
public Set<Long> listRowsToUpdateForDomain(long domainId, ResourceType type) {
Set<Long> rowIds = new HashSet<Long>();
Set<Long> domainIdsToUpdate = _domainDao.getDomainParentIds(domainId);
for (Long domainIdToUpdate : domainIdsToUpdate) {
ResourceCountVO domainCountRecord = findByDomainIdAndType(domainIdToUpdate, type);
rowIds.add(domainCountRecord.getId());
}
return rowIds;
}
@Override @DB
public void createResourceCounts(long ownerId, ResourceLimit.OwnerType ownerType){
Long accountId = null;
Long domainId = null;
if (ownerType == ResourceLimit.OwnerType.Account) {
accountId = ownerId;
} else if (ownerType == ResourceLimit.OwnerType.Domain) {
domainId = ownerId;
}
Transaction txn = Transaction.currentTxn();
txn.start();
ResourceType[] resourceTypes = ResourceCount.ResourceType.values();
for (ResourceType resourceType : resourceTypes) {
ResourceCountVO resourceCountVO = new ResourceCountVO(accountId, domainId, resourceType, 0);
persist(resourceCountVO);
}
txn.commit();
}
}

View File

@ -21,6 +21,7 @@ package com.cloud.configuration.dao;
import java.util.List;
import com.cloud.configuration.ResourceCount;
import com.cloud.configuration.ResourceLimit.OwnerType;
import com.cloud.configuration.ResourceLimitVO;
import com.cloud.utils.db.GenericDao;
@ -32,4 +33,5 @@ public interface ResourceLimitDao extends GenericDao<ResourceLimitVO, Long> {
public List<ResourceLimitVO> listByDomainId(Long domainId);
public boolean update(Long id, Long max);
public ResourceCount.ResourceType getLimitType(String type);
public ResourceLimitVO findByOwnerIdAndType(long ownerId, OwnerType ownerType, ResourceCount.ResourceType type);
}

View File

@ -23,6 +23,7 @@ import java.util.List;
import javax.ejb.Local;
import com.cloud.configuration.ResourceCount;
import com.cloud.configuration.ResourceLimit.OwnerType;
import com.cloud.configuration.ResourceLimitVO;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
@ -99,7 +100,17 @@ public class ResourceLimitDaoImpl extends GenericDaoBase<ResourceLimitVO, Long>
return validType;
}
}
return null;
}
@Override
public ResourceLimitVO findByOwnerIdAndType(long ownerId, OwnerType ownerType, ResourceCount.ResourceType type) {
if (ownerType == OwnerType.Account) {
return findByAccountIdAndType(ownerId, type);
} else if (ownerType == OwnerType.Domain) {
return findByDomainIdAndType(ownerId, type);
} else {
return null;
}
}
}

View File

@ -67,7 +67,12 @@ public class DomainVO implements Domain {
@Column(name="network_domain")
private String networkDomain;
public DomainVO() {}
public DomainVO() {}
public DomainVO(long id, String name, long owner, Long parentId, String networkDomain) {
this(name, owner, parentId, networkDomain);
this.id = id;
}
public DomainVO(String name, long owner, Long parentId, String networkDomain) {
this.parent = parentId;

View File

@ -19,6 +19,7 @@
package com.cloud.domain.dao;
import java.util.List;
import java.util.Set;
import com.cloud.domain.DomainVO;
import com.cloud.utils.db.GenericDao;
@ -30,5 +31,6 @@ public interface DomainDao extends GenericDao<DomainVO, Long> {
DomainVO findImmediateChildForParent(Long parentId);
List<DomainVO> findImmediateChildrenForParent(Long parentId);
List<DomainVO> findAllChildren(String path, Long parentId);
List<DomainVO> findInactiveDomains();
List<DomainVO> findInactiveDomains();
Set<Long> getDomainParentIds(long domainId);
}

View File

@ -21,7 +21,9 @@ package com.cloud.domain.dao;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.ejb.Local;
@ -255,5 +257,19 @@ public class DomainDaoImpl extends GenericDaoBase<DomainVO, Long> implements Dom
SearchCriteria<DomainVO> sc = AllFieldsSearch.create();
sc.setParameters("state", Domain.State.Inactive);
return listBy(sc);
}
@Override
public Set<Long> getDomainParentIds(long domainId) {
Set<Long> parentDomains = new HashSet<Long>();
Domain domain = findById(domainId);
parentDomains.add(domain.getId());
while (domain.getParent() != null) {
domain = findById(domain.getParent());
parentDomains.add(domain.getId());
}
return parentDomains;
}
}

View File

@ -2234,9 +2234,9 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
disconnectedRouters.add(router);
}
//If rules fail to apply on one domR, no need to proceed with the rest
//If ip fails to apply on one domR, no need to proceed with the rest
if (!result) {
throw new ResourceUnavailableException("Unable to apply firewall rules on router ", VirtualRouter.class, router.getId());
throw new ResourceUnavailableException("Unable to associate ip addresses on router ", VirtualRouter.class, router.getId());
}
} else if (router.getState() == State.Stopped || router.getState() == State.Stopping) {

View File

@ -47,7 +47,9 @@ import org.apache.log4j.Logger;
import com.cloud.configuration.Config;
import com.cloud.configuration.ConfigurationVO;
import com.cloud.configuration.ResourceLimit.OwnerType;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.configuration.dao.ResourceCountDao;
import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
@ -55,6 +57,8 @@ import com.cloud.dc.VlanVO;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.HostPodDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.exception.InternalErrorException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.network.Network.GuestIpType;
@ -78,7 +82,11 @@ import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.test.IPRangeConfig;
import com.cloud.user.Account;
import com.cloud.user.AccountVO;
import com.cloud.user.User;
import com.cloud.user.UserVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.PasswordGenerator;
import com.cloud.utils.PropertiesUtil;
import com.cloud.utils.component.ComponentLocator;
@ -101,6 +109,10 @@ public class ConfigurationServerImpl implements ConfigurationServer {
private final NetworkDao _networkDao;
private final VlanDao _vlanDao;
private String _domainSuffix;
private final ResourceCountDao _resourceCountDao;
private final AccountDao _accountDao;
private final UserDao _userDao;
private final DomainDao _domainDao;
public ConfigurationServerImpl() {
@ -114,14 +126,15 @@ public class ConfigurationServerImpl implements ConfigurationServer {
_dataCenterDao = locator.getDao(DataCenterDao.class);
_networkDao = locator.getDao(NetworkDao.class);
_vlanDao = locator.getDao(VlanDao.class);
_resourceCountDao = locator.getDao(ResourceCountDao.class);
_accountDao = locator.getDao(AccountDao.class);
_userDao = locator.getDao(UserDao.class);
_domainDao = locator.getDao(DomainDao.class);
}
@Override @DB
public void persistDefaultValues() throws InternalErrorException {
// Create system user and admin user
saveUser();
// Get init
String init = _configDao.getValue("init");
@ -131,6 +144,14 @@ public class ConfigurationServerImpl implements ConfigurationServer {
if (init == null || init.equals("false")) {
s_logger.debug("ConfigurationServer is saving default values to the database.");
Transaction txn = Transaction.currentTxn();
txn.start();
// Create ROOT domain
saveRootDomain();
// Create system user and admin user
saveUser();
// Save default Configuration Table values
List<String> categories = Config.getCategories();
for (String category : categories) {
@ -199,11 +220,9 @@ public class ConfigurationServerImpl implements ConfigurationServer {
//Create default networks
createDefaultNetworks();
//Create userIpAddress ranges
//Update existing vlans with networkId
Transaction txn = Transaction.currentTxn();
List<VlanVO> vlans = _vlanDao.listAll();
if (vlans != null && !vlans.isEmpty()) {
@ -218,14 +237,17 @@ public class ConfigurationServerImpl implements ConfigurationServer {
String startIp = range[0];
String endIp = range[1];
txn.start();
IPRangeConfig config = new IPRangeConfig();
long startIPLong = NetUtils.ip2Long(startIp);
long endIPLong = NetUtils.ip2Long(endIp);
config.savePublicIPRange(txn, startIPLong, endIPLong, vlan.getDataCenterId(), vlan.getId(), vlan.getNetworkId());
txn.commit();
}
}
// Set init to true
_configDao.update("init", "true");
txn.commit();
}
// keystore for SSL/TLS connection
@ -240,8 +262,6 @@ public class ConfigurationServerImpl implements ConfigurationServer {
// Update the cloud identifier
updateCloudIdentifier();
// Set init to true
_configDao.update("init", "true");
}
@ -273,27 +293,24 @@ public class ConfigurationServerImpl implements ConfigurationServer {
// insert system account
String insertSql = "INSERT INTO `cloud`.`account` (id, account_name, type, domain_id) VALUES (1, 'system', '1', '1')";
Transaction txn = Transaction.currentTxn();
try {
PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
stmt.executeUpdate();
} catch (SQLException ex) {
}
// insert system user
insertSql = "INSERT INTO `cloud`.`user` (id, username, password, account_id, firstname, lastname, created) VALUES (1, 'system', '', 1, 'system', 'cloud', now())";
txn = Transaction.currentTxn();
try {
PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
stmt.executeUpdate();
} catch (SQLException ex) {
}
// insert admin user
long id = 2;
String username = "admin";
String firstname = "admin";
String lastname = "cloud";
String password = "password";
txn.start();
//Create system/admin accounts
AccountVO systemAccount = new AccountVO(1);
systemAccount.setAccountName("system");
systemAccount.setType(Account.ACCOUNT_TYPE_ADMIN);;
systemAccount.setDomainId(1);
systemAccount.setState(Account.State.enabled);
_accountDao.persist(systemAccount);
AccountVO adminAccount = new AccountVO(1);
adminAccount.setAccountName("admin");
adminAccount.setType(Account.ACCOUNT_TYPE_ADMIN);;
adminAccount.setDomainId(1);
adminAccount.setState(Account.State.enabled);
_accountDao.persist(adminAccount);
//Create system/admin users
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
@ -301,6 +318,7 @@ public class ConfigurationServerImpl implements ConfigurationServer {
return;
}
String password = "password";
md5.reset();
BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes()));
String pwStr = pwInt.toString(16);
@ -310,29 +328,36 @@ public class ConfigurationServerImpl implements ConfigurationServer {
sb.append('0'); // make sure the MD5 password is 32 digits long
}
sb.append(pwStr);
// create an account for the admin user first
insertSql = "INSERT INTO `cloud`.`account` (id, account_name, type, domain_id) VALUES (" + id + ", '" + username + "', '1', '1')";
txn = Transaction.currentTxn();
try {
PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
stmt.executeUpdate();
} catch (SQLException ex) {
}
// now insert the user
insertSql = "INSERT INTO `cloud`.`user` (id, username, password, account_id, firstname, lastname, created) " +
"VALUES (" + id + ",'" + username + "','" + sb.toString() + "', 2, '" + firstname + "','" + lastname + "',now())";
password = sb.toString();
txn = Transaction.currentTxn();
try {
PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
stmt.executeUpdate();
} catch (SQLException ex) {
}
UserVO systemUser = new UserVO(1);
systemUser.setUsername("system");
systemUser.setPassword("");
systemUser.setAccountId(1);
systemUser.setFirstname("system");
systemUser.setLastname("system");
systemUser.setState(Account.State.enabled);
_userDao.persist(systemUser);
UserVO adminUser = new UserVO(2);
adminUser.setUsername("admin");
adminUser.setPassword(password);
adminUser.setAccountId(2);
adminUser.setFirstname("admin");
adminUser.setLastname("cloud");
adminUser.setState(Account.State.enabled);
_userDao.persist(adminUser);
//create resource counts
try {
_resourceCountDao.createResourceCounts(1, OwnerType.Account);
_resourceCountDao.createResourceCounts(2, OwnerType.Account);
} catch (Exception ex) {
// if exception happens, it might mean that resource counts are already created by another management server being started in the cluster
s_logger.warn("Failed to create initial resource counts for system/admin accounts");
}
try {
String tableName = "security_group";
@ -358,7 +383,6 @@ public class ConfigurationServerImpl implements ConfigurationServer {
"VALUES ('default', 'Default Security Group', 2, 1, 'admin')";
}
txn = Transaction.currentTxn();
try {
stmt = txn.prepareAutoCloseStatement(insertSql);
stmt.executeUpdate();
@ -369,6 +393,8 @@ public class ConfigurationServerImpl implements ConfigurationServer {
rs.close();
} catch (Exception ex) {
s_logger.warn("Failed to create default security group for default admin account due to ", ex);
} finally {
txn.commit();
}
}
@ -902,7 +928,7 @@ public class ConfigurationServerImpl implements ConfigurationServer {
}
}
private void updateVlanWithNetworkId(VlanVO vlan) {
long zoneId = vlan.getDataCenterId();
long networkId = 0L;
@ -939,5 +965,19 @@ public class ConfigurationServerImpl implements ConfigurationServer {
}
return networks.get(0).getId();
}
@DB
public void saveRootDomain() {
Transaction txn = Transaction.currentTxn();
txn.start();
DomainVO domain = new DomainVO(1, "ROOT", 2, null, null);
domain.setPath("/");
domain.setLevel(0);
_domainDao.persist(domain);
_resourceCountDao.createResourceCounts(1, OwnerType.Domain);
txn.commit();
}
}

View File

@ -65,7 +65,6 @@ import com.cloud.alert.AlertVO;
import com.cloud.alert.dao.AlertDao;
import com.cloud.api.ApiConstants;
import com.cloud.api.ApiDBUtils;
import com.cloud.api.commands.CreateDomainCmd;
import com.cloud.api.commands.CreateSSHKeyPairCmd;
import com.cloud.api.commands.DeleteDomainCmd;
import com.cloud.api.commands.DeleteSSHKeyPairCmd;
@ -2968,59 +2967,6 @@ public class ManagementServerImpl implements ManagementServer {
return _domainDao.search(sc, searchFilter);
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_DOMAIN_CREATE, eventDescription = "creating Domain")
public DomainVO createDomain(CreateDomainCmd cmd) {
String name = cmd.getDomainName();
Long parentId = cmd.getParentDomainId();
Long ownerId = UserContext.current().getCaller().getId();
Account caller = UserContext.current().getCaller();
String networkDomain = cmd.getNetworkDomain();
if (ownerId == null) {
ownerId = Long.valueOf(1);
}
if (parentId == null) {
parentId = Long.valueOf(DomainVO.ROOT_DOMAIN);
}
DomainVO parentDomain = _domainDao.findById(parentId);
if (parentDomain == null) {
throw new InvalidParameterValueException("Unable to create domain " + name + ", parent domain " + parentId + " not found.");
}
if (parentDomain.getState().equals(Domain.State.Inactive)) {
throw new CloudRuntimeException("The domain cannot be created as the parent domain " + parentDomain.getName() + " is being deleted");
}
_accountMgr.checkAccess(caller, parentDomain);
if (networkDomain != null) {
if (!NetUtils.verifyDomainName(networkDomain)) {
throw new InvalidParameterValueException(
"Invalid network domain. Total length shouldn't exceed 190 chars. Each domain label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', "
+ "and the hyphen ('-'); can't start or end with \"-\"");
}
}
SearchCriteria<DomainVO> sc = _domainDao.createSearchCriteria();
sc.addAnd("name", SearchCriteria.Op.EQ, name);
sc.addAnd("parent", SearchCriteria.Op.EQ, parentId);
List<DomainVO> domains = _domainDao.search(sc, null);
if ((domains == null) || domains.isEmpty()) {
DomainVO domain = new DomainVO(name, ownerId, parentId, networkDomain);
try {
return _domainDao.create(domain);
} catch (IllegalArgumentException ex) {
s_logger.warn("Failed to create domain ", ex);
throw ex;
}
} else {
throw new InvalidParameterValueException("Domain with name " + name + " already exists for the parent id=" + parentId);
}
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_DOMAIN_DELETE, eventDescription = "deleting Domain", async = true)
public boolean deleteDomain(DeleteDomainCmd cmd) {

View File

@ -1068,7 +1068,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
}
// Verify that max doesn't exceed domain and account snapshot limits
long accountLimit = _accountMgr.findCorrectResourceLimit(owner, ResourceType.snapshot);
long accountLimit = _accountMgr.findCorrectResourceLimit(owner.getId(), ResourceType.snapshot);
long domainLimit = _accountMgr.findCorrectResourceLimit(domain, ResourceType.snapshot);
int max = cmd.getMaxSnaps().intValue();
if (owner.getType() != Account.ACCOUNT_TYPE_ADMIN && ((accountLimit != -1 && max > accountLimit) || (domainLimit != -1 && max > domainLimit))) {

View File

@ -20,10 +20,7 @@ package com.cloud.test;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URISyntaxException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -410,7 +407,6 @@ public class DatabaseConfig {
// Save default values for configuration fields
saveVMTemplate();
saveRootDomain();
saveDefaultConfiguations();
txn.commit();
@ -439,8 +435,6 @@ public class DatabaseConfig {
saveServiceOffering();
} else if ("diskOffering".equals(_currentObjectName)) {
saveDiskOffering();
} else if ("user".equals(_currentObjectName)) {
saveUser();
} else if ("configuration".equals(_currentObjectName)) {
saveConfiguration();
} else if ("storagePool".equals(_currentObjectName)) {
@ -965,80 +959,6 @@ public class DatabaseConfig {
*/
}
@DB
protected void saveUser() {
// insert system account
String insertSql = "INSERT INTO `cloud`.`account` (id, account_name, type, domain_id) VALUES (1, 'system', '1', '1')";
Transaction txn = Transaction.currentTxn();
try {
PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
stmt.executeUpdate();
} catch (SQLException ex) {
s_logger.error("error creating system account", ex);
}
// insert system user
insertSql = "INSERT INTO `cloud`.`user` (id, username, password, account_id, firstname, lastname, created) VALUES (1, 'system', '', 1, 'system', 'cloud', now())";
txn = Transaction.currentTxn();
try {
PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
stmt.executeUpdate();
} catch (SQLException ex) {
s_logger.error("error creating system user", ex);
}
// insert admin user
long id = Long.parseLong(_currentObjectParams.get("id"));
String username = _currentObjectParams.get("username");
String firstname = _currentObjectParams.get("firstname");
String lastname = _currentObjectParams.get("lastname");
String password = _currentObjectParams.get("password");
String email = _currentObjectParams.get("email");
if (email == null || email.equals("")) {
printError("An email address for each user is required.");
}
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
s_logger.error("error saving user", e);
return;
}
md5.reset();
BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes()));
String pwStr = pwInt.toString(16);
int padding = 32 - pwStr.length();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < padding; i++) {
sb.append('0'); // make sure the MD5 password is 32 digits long
}
sb.append(pwStr);
// create an account for the admin user first
insertSql = "INSERT INTO `cloud`.`account` (id, account_name, type, domain_id) VALUES (" + id + ", '" + username + "', '1', '1')";
txn = Transaction.currentTxn();
try {
PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
stmt.executeUpdate();
} catch (SQLException ex) {
s_logger.error("error creating account", ex);
}
// now insert the user
insertSql = "INSERT INTO `cloud`.`user` (id, username, password, account_id, firstname, lastname, email, created) " +
"VALUES (" + id + ",'" + username + "','" + sb.toString() + "', 2, '" + firstname + "','" + lastname + "','" + email + "',now())";
txn = Transaction.currentTxn();
try {
PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
stmt.executeUpdate();
} catch (SQLException ex) {
s_logger.error("error creating user", ex);
}
}
private void saveDefaultConfiguations() {
for (String name : s_defaultConfigurationValues.keySet()) {
String value = s_defaultConfigurationValues.get(name);
@ -1126,42 +1046,6 @@ public class DatabaseConfig {
return true;
}
@DB
protected void saveRootDomain() {
String insertSql = "insert into `cloud`.`domain` (id, name, parent, owner, path, level) values (1, 'ROOT', NULL, 2, '/', 0)";
Transaction txn = Transaction.currentTxn();
try {
PreparedStatement stmt = txn.prepareAutoCloseStatement(insertSql);
stmt.executeUpdate();
} catch (SQLException ex) {
s_logger.error("error creating ROOT domain", ex);
}
/*
String updateSql = "update account set domain_id = 1 where id = 2";
Transaction txn = Transaction.currentTxn();
try {
PreparedStatement stmt = txn.prepareStatement(updateSql);
stmt.executeUpdate();
} catch (SQLException ex) {
s_logger.error("error updating admin user", ex);
} finally {
txn.close();
}
updateSql = "update account set domain_id = 1 where id = 1";
Transaction txn = Transaction.currentTxn();
try {
PreparedStatement stmt = txn.prepareStatement(updateSql);
stmt.executeUpdate();
} catch (SQLException ex) {
s_logger.error("error updating system user", ex);
} finally {
txn.close();
}
*/
}
class DbConfigXMLHandler extends DefaultHandler {
private DatabaseConfig _parent = null;

View File

@ -19,9 +19,16 @@ package com.cloud.upgrade.dao;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import com.cloud.configuration.ResourceCount;
import com.cloud.configuration.ResourceCount.ResourceType;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;
@ -55,11 +62,78 @@ public class Upgrade2211to2212 implements DbUpgrade {
@Override
public void performDataMigration(Connection conn) {
createResourceCount(conn);
}
@Override
public File[] getCleanupScripts() {
return null;
}
private void createResourceCount(Connection conn) {
s_logger.debug("Creating missing resource_count records as a part of 2.2.11-2.2.12 upgrade");
try {
//Get all non removed accounts
List<Long> accounts = new ArrayList<Long>();
PreparedStatement pstmt = conn.prepareStatement("SELECT id FROM account");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
accounts.add(rs.getLong(1));
}
rs.close();
//get all non removed domains
List<Long> domains = new ArrayList<Long>();
pstmt = conn.prepareStatement("SELECT id FROM domain");
rs = pstmt.executeQuery();
while (rs.next()) {
domains.add(rs.getLong(1));
}
rs.close();
for (Long accountId : accounts) {
ResourceType[] resourceTypes = ResourceCount.ResourceType.values();
for (ResourceType resourceType : resourceTypes) {
pstmt = conn.prepareStatement("SELECT * FROM resource_count WHERE type=? and account_id=?");
pstmt.setString(1, resourceType.toString());
pstmt.setLong(2, accountId);
rs = pstmt.executeQuery();
if (!rs.next()) {
s_logger.debug("Inserting resource_count record of type " + resourceType + " for account id=" + accountId);
pstmt = conn.prepareStatement("INSERT INTO resource_count (account_id, domain_id, type, count) VALUES (?, null, ?, 0)");
pstmt.setLong(1, accountId);
pstmt.setString(2, resourceType.toString());
pstmt.executeUpdate();
}
rs.close();
}
pstmt.close();
}
for (Long domainId : domains) {
ResourceType[] resourceTypes = ResourceCount.ResourceType.values();
for (ResourceType resourceType : resourceTypes) {
pstmt = conn.prepareStatement("SELECT * FROM resource_count WHERE type=? and domain_id=?");
pstmt.setString(1, resourceType.toString());
pstmt.setLong(2, domainId);
rs = pstmt.executeQuery();
if (!rs.next()) {
s_logger.debug("Inserting resource_count record of type " + resourceType + " for domain id=" + domainId);
pstmt = conn.prepareStatement("INSERT INTO resource_count (account_id, domain_id, type, count) VALUES (null, ?, ?, 0)");
pstmt.setLong(1, domainId);
pstmt.setString(2, resourceType.toString());
pstmt.executeUpdate();
}
rs.close();
}
pstmt.close();
}
} catch (SQLException e) {
throw new CloudRuntimeException("Unable to create default security groups for existing accounts due to", e);
}
}
}

View File

@ -49,11 +49,11 @@ public interface AccountManager extends AccountService {
/**
* Finds the resource limit for a specified account and type. If the account has an infinite limit, will check
* the account's parent domain, and if that limit is also infinite, will return the ROOT domain's limit.
* @param account
* @param accountId
* @param type
* @return resource limit
*/
public long findCorrectResourceLimit(AccountVO account, ResourceType type);
public long findCorrectResourceLimit(long accountId, ResourceType type);
/**
* Finds the resource limit for a specified domain and type. If the domain has an infinite limit, will check

View File

@ -38,8 +38,10 @@ import org.apache.log4j.Logger;
import com.cloud.acl.ControlledEntity;
import com.cloud.acl.SecurityChecker;
import com.cloud.acl.SecurityChecker.AccessType;
import com.cloud.alert.AlertManager;
import com.cloud.api.ApiDBUtils;
import com.cloud.api.commands.CreateAccountCmd;
import com.cloud.api.commands.CreateDomainCmd;
import com.cloud.api.commands.CreateUserCmd;
import com.cloud.api.commands.DeleteAccountCmd;
import com.cloud.api.commands.DeleteUserCmd;
@ -57,6 +59,7 @@ import com.cloud.configuration.Config;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.configuration.ResourceCount.ResourceType;
import com.cloud.configuration.ResourceCountVO;
import com.cloud.configuration.ResourceLimit;
import com.cloud.configuration.ResourceLimitVO;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.configuration.dao.ResourceCountDao;
@ -68,7 +71,6 @@ import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
import com.cloud.event.dao.UsageEventDao;
import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InvalidParameterValueException;
@ -183,8 +185,6 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
@Inject
private VirtualMachineManager _itMgr;
@Inject
private UsageEventDao _usageEventDao;
@Inject
private RemoteAccessVpnDao _remoteAccessVpnDao;
@Inject
private RemoteAccessVpnService _remoteAccessVpnMgr;
@ -192,10 +192,12 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
private VpnUserDao _vpnUser;
@Inject
private DataCenterDao _dcDao;
@Inject
private AlertManager _alertMgr;
private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AccountChecker"));
private final GlobalLock m_resourceCountLock = GlobalLock.getInternLock("resource.count");
protected SearchBuilder<ResourceCountVO> ResourceCountSearch;
UserVO _systemUser;
AccountVO _systemAccount;
@ -223,6 +225,12 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
String value = configs.get(Config.AccountCleanupInterval.key());
_cleanupInterval = NumbersUtil.parseInt(value, 60 * 60 * 24); // 1 hour.
ResourceCountSearch = _resourceCountDao.createSearchBuilder();
ResourceCountSearch.and("id", ResourceCountSearch.entity().getId(), SearchCriteria.Op.IN);
ResourceCountSearch.and("accountId", ResourceCountSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
ResourceCountSearch.and("domainId", ResourceCountSearch.entity().getDomainId(), SearchCriteria.Op.EQ);
ResourceCountSearch.done();
return true;
}
@ -252,57 +260,27 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
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();
}
if (!updateResourceCount(accountId, type, true, numToIncrement)) {
//we should fail the operation (resource creation) when failed to update the resource count
throw new CloudRuntimeException("Failed to increment resource count of type " + type + " for account id=" + accountId);
}
}
@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 {
assert ((_resourceCountDao.getAccountCount(accountId, type) - numToDecrement) >= 0) : "Resource counts can not be negative. Check where we skipped increment.";
_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) {
assert ((_resourceCountDao.getDomainCount(domainId, type) - numToDecrement) >= 0) : "Resource counts can not be negative. Check where we skipped increment.";
_resourceCountDao.updateDomainCount(domainId, type, false, numToDecrement);
DomainVO domain = _domainDao.findByIdIncludingRemoved(domainId);
domainId = domain.getParent();
}
} finally {
m_resourceCountLock.unlock();
}
if (!updateResourceCount(accountId, type, false, numToDecrement)) {
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_UPDATE_RESOURCE_COUNT, 0L, 0L, "Failed to decrement resource count of type " + type + " for account id=" + accountId,
"Failed to decrement resource count of type " + type + " for account id=" + accountId + "; use updateResourceCount API to recalculate/fix the problem");
}
}
@Override
public long findCorrectResourceLimit(AccountVO account, ResourceType type) {
public long findCorrectResourceLimit(long accountId, ResourceType type) {
long max = -1;
ResourceLimitVO limit = _resourceLimitDao.findByAccountIdAndType(account.getId(), type);
ResourceLimitVO limit = _resourceLimitDao.findByAccountIdAndType(accountId, type);
// Check if limit is configured for account
if (limit != null) {
@ -361,46 +339,49 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
return max;
}
@Override
@Override @DB
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) {
if (isAdmin(account.getType())) {
return false;
}
Transaction txn = Transaction.currentTxn();
txn.start();
try {
//Lock all rows first so nobody else can read it
Set<Long> rowIdsToLock = _resourceCountDao.listAllRowsToUpdateForAccount(account.getId(), account.getDomainId(), type);
SearchCriteria<ResourceCountVO> sc = ResourceCountSearch.create();
sc.setParameters("id", rowIdsToLock.toArray());
_resourceCountDao.lockRows(sc, null, true);
if (m_resourceCountLock.lock(120)) { // 2 minutes
try {
// Check account limits
AccountVO accountVo = _accountDao.findById(account.getAccountId());
long accountLimit = findCorrectResourceLimit(accountVo, type);
long potentialCount = _resourceCountDao.getAccountCount(account.getId(), type) + numResources;
if (accountLimit != -1 && potentialCount > accountLimit) {
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();
}
return false;
} finally {
m_resourceCountLock.unlock();
// Check account limits
long accountLimit = findCorrectResourceLimit(account.getId(), type);
long potentialCount = _resourceCountDao.getAccountCount(account.getId(), type) + numResources;
if (potentialCount > accountLimit) {
return true;
}
}
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();
}
return false;
} finally {
txn.commit();
}
}
@Override
@ -487,7 +468,7 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
}
} else {
AccountVO account = _accountDao.findById(accountId);
limits.add(new ResourceLimitVO(null, accountId, type, findCorrectResourceLimit(account, type)));
limits.add(new ResourceLimitVO(null, accountId, type, findCorrectResourceLimit(account.getId(), type)));
}
} else if (domainId != null) {
if (type == null) {
@ -745,69 +726,80 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
}
}
@Override
@Override @DB
public long updateAccountResourceCount(long accountId, ResourceType type) {
Long count=null;
// this lock guards against the updates to user_vm, volume, snapshot, public _ip and template table
// as any resource creation precedes with the resourceLimitExceeded check which needs this lock too
if (m_resourceCountLock.lock(120)) { // 2 minutes
try {
switch (type) {
case user_vm:
count = _userVmDao.countAllocatedVMsForAccount(accountId);
break;
case volume:
count = _volumeDao.countAllocatedVolumesForAccount(accountId);
long virtualRouterCount = _vmDao.countAllocatedVirtualRoutersForAccount(accountId);
count = count - virtualRouterCount; // don't count the volumes of virtual router
break;
case snapshot:
count = _snapshotDao.countSnapshotsForAccount(accountId);
break;
case public_ip:
count = _ipAddressDao.countAllocatedIPsForAccount(accountId);
break;
case template:
count = _vmTemplateDao.countTemplatesForAccount(accountId);
break;
}
_resourceCountDao.setAccountCount(accountId, type, (count == null) ? 0 : count.longValue());
} catch (Exception e) {
throw new CloudRuntimeException("Failed to update resource count for account with Id" + accountId);
} finally {
m_resourceCountLock.unlock();
Transaction txn = Transaction.currentTxn();
txn.start();
try {
// this lock guards against the updates to user_vm, volume, snapshot, public _ip and template table
// as any resource creation precedes with the resourceLimitExceeded check which needs this lock too
SearchCriteria<ResourceCountVO> sc = ResourceCountSearch.create();
sc.setParameters("accountId", accountId);
_resourceCountDao.lockRows(sc, null, true);
switch (type) {
case user_vm:
count = _userVmDao.countAllocatedVMsForAccount(accountId);
break;
case volume:
count = _volumeDao.countAllocatedVolumesForAccount(accountId);
long virtualRouterCount = _vmDao.countAllocatedVirtualRoutersForAccount(accountId);
count = count - virtualRouterCount; // don't count the volumes of virtual router
break;
case snapshot:
count = _snapshotDao.countSnapshotsForAccount(accountId);
break;
case public_ip:
count = _ipAddressDao.countAllocatedIPsForAccount(accountId);
break;
case template:
count = _vmTemplateDao.countTemplatesForAccount(accountId);
break;
}
_resourceCountDao.setAccountCount(accountId, type, (count == null) ? 0 : count.longValue());
} catch (Exception e) {
throw new CloudRuntimeException("Failed to update resource count for account with Id" + accountId);
} finally {
txn.commit();
}
return (count==null)?0:count.longValue();
}
@Override
@Override @DB
public long updateDomainResourceCount(long domainId, ResourceType type) {
long count=0;
if (m_resourceCountLock.lock(120)) { // 2 minutes
try {
List<DomainVO> domainChildren = _domainDao.findImmediateChildrenForParent(domainId);
// for each child domain update the resource count
for (DomainVO domainChild : domainChildren) {
long domainCount = updateDomainResourceCount(domainChild.getId(), type);
count = count + domainCount; // add the child domain count to parent domain count
}
Transaction txn = Transaction.currentTxn();
txn.start();
try {
//Lock all rows first so nobody else can read it
Set<Long> rowIdsToLock = _resourceCountDao.listRowsToUpdateForDomain(domainId, type);
SearchCriteria<ResourceCountVO> sc = ResourceCountSearch.create();
sc.setParameters("id", rowIdsToLock.toArray());
_resourceCountDao.lockRows(sc, null, true);
List<DomainVO> domainChildren = _domainDao.findImmediateChildrenForParent(domainId);
// for each child domain update the resource count
for (DomainVO domainChild : domainChildren) {
long domainCount = updateDomainResourceCount(domainChild.getId(), type);
count = count + domainCount; // add the child domain count to parent domain count
}
List<AccountVO> accounts = _accountDao.findActiveAccountsForDomain(domainId);
for (AccountVO account : accounts) {
long accountCount = updateAccountResourceCount(account.getId(), type);
count = count + accountCount; // add account's resource count to parent domain count
}
List<AccountVO> accounts = _accountDao.findActiveAccountsForDomain(domainId);
for (AccountVO account : accounts) {
long accountCount = updateAccountResourceCount(account.getId(), type);
count = count + accountCount; // add account's resource count to parent domain count
}
_resourceCountDao.setDomainCount(domainId, type, count);
} catch (Exception e) {
throw new CloudRuntimeException("Failed to update resource count for domain with Id " + domainId);
} finally {
m_resourceCountLock.unlock();
}
_resourceCountDao.setDomainCount(domainId, type, count);
} catch (Exception e) {
throw new CloudRuntimeException("Failed to update resource count for domain with Id " + domainId);
} finally {
txn.commit();
}
return count;
@ -1274,7 +1266,11 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
+ "and the hyphen ('-'); can't start or end with \"-\"");
}
}
Transaction txn = Transaction.currentTxn();
txn.start();
//Create account itself
if (accountId == null) {
if ((userType < Account.ACCOUNT_TYPE_NORMAL) || (userType > Account.ACCOUNT_TYPE_READ_ONLY_ADMIN)) {
throw new InvalidParameterValueException("Invalid account type " + userType + " given; unable to create user");
@ -1330,10 +1326,15 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
s_logger.debug("Creating user: " + username + ", account: " + accountName + " (id:" + accountId + "), domain: " + domainId + " timezone:" + timezone);
}
Transaction txn = Transaction.currentTxn();
txn.start();
//Create resource count records for the account
_resourceCountDao.createResourceCounts(accountId, ResourceLimit.OwnerType.Account);
//Create a user
UserVO dbUser = _userDao.persist(user);
//Create default security group
_networkGroupMgr.createDefaultSecurityGroup(accountId);
txn.commit();
if (!user.getPassword().equals(dbUser.getPassword())) {
@ -2034,16 +2035,7 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
@Override
public Set<Long> getDomainParentIds(long domainId) {
Set<Long> parentDomains = new HashSet<Long>();
Domain domain = _domainDao.findById(domainId);
parentDomains.add(domain.getId());
while (domain.getParent() != null) {
domain = _domainDao.findById(domain.getParent());
parentDomains.add(domain.getId());
}
return parentDomains;
return _domainDao.getDomainParentIds(domainId);
}
@Override
@ -2060,4 +2052,94 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
return childDomains;
}
@DB
public boolean updateResourceCount(long accountId, ResourceType type, boolean increment, long delta) {
boolean result = true;
try {
Transaction txn = Transaction.currentTxn();
txn.start();
Set<Long> rowsToLock = _resourceCountDao.listAllRowsToUpdateForAccount(accountId, getAccount(accountId).getDomainId(), type);
//Lock rows first
SearchCriteria<ResourceCountVO> sc = ResourceCountSearch.create();
sc.setParameters("id", rowsToLock.toArray());
List<ResourceCountVO> rowsToUpdate = _resourceCountDao.lockRows(sc, null, true);
for (ResourceCountVO rowToUpdate : rowsToUpdate) {
if (!_resourceCountDao.updateById(rowToUpdate.getId(), increment, delta)) {
s_logger.trace("Unable to update resource count for the row " + rowToUpdate);
result = false;
}
}
txn.commit();
} catch (Exception ex) {
s_logger.error("Failed to update resource count for account id=" + accountId);
result = false;
}
return result;
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_DOMAIN_CREATE, eventDescription = "creating Domain")
@DB
public Domain createDomain(CreateDomainCmd cmd) {
String name = cmd.getDomainName();
Long parentId = cmd.getParentDomainId();
Long ownerId = UserContext.current().getCaller().getId();
Account caller = UserContext.current().getCaller();
String networkDomain = cmd.getNetworkDomain();
if (ownerId == null) {
ownerId = Long.valueOf(1);
}
if (parentId == null) {
parentId = Long.valueOf(DomainVO.ROOT_DOMAIN);
}
DomainVO parentDomain = _domainDao.findById(parentId);
if (parentDomain == null) {
throw new InvalidParameterValueException("Unable to create domain " + name + ", parent domain " + parentId + " not found.");
}
if (parentDomain.getState().equals(Domain.State.Inactive)) {
throw new CloudRuntimeException("The domain cannot be created as the parent domain " + parentDomain.getName() + " is being deleted");
}
checkAccess(caller, parentDomain);
if (networkDomain != null) {
if (!NetUtils.verifyDomainName(networkDomain)) {
throw new InvalidParameterValueException(
"Invalid network domain. Total length shouldn't exceed 190 chars. Each domain label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', "
+ "and the hyphen ('-'); can't start or end with \"-\"");
}
}
SearchCriteria<DomainVO> sc = _domainDao.createSearchCriteria();
sc.addAnd("name", SearchCriteria.Op.EQ, name);
sc.addAnd("parent", SearchCriteria.Op.EQ, parentId);
List<DomainVO> domains = _domainDao.search(sc, null);
if ((domains == null) || domains.isEmpty()) {
DomainVO domain = new DomainVO(name, ownerId, parentId, networkDomain);
try {
Transaction txn = Transaction.currentTxn();
txn.start();
domain = _domainDao.create(domain);
_resourceCountDao.createResourceCounts(domain.getId(), ResourceLimit.OwnerType.Domain);
txn.commit();
return domain;
} catch (IllegalArgumentException ex) {
s_logger.warn("Failed to create domain ", ex);
throw ex;
}
} else {
throw new InvalidParameterValueException("Domain with name " + name + " already exists for the parent id=" + parentId);
}
}
}

View File

@ -61,7 +61,6 @@ public class MockAgentManagerImpl implements AgentManager {
return null;
}
@Override
public Answer send(Long hostId, Command cmd) throws AgentUnavailableException, OperationTimedoutException {
// TODO Auto-generated method stub
@ -200,7 +199,6 @@ public class MockAgentManagerImpl implements AgentManager {
return false;
}
@Override
public boolean isHostNativeHAEnabled(long hostId) {
// TODO Auto-generated method stub

View File

@ -10,6 +10,7 @@ import javax.naming.ConfigurationException;
import com.cloud.acl.ControlledEntity;
import com.cloud.acl.SecurityChecker.AccessType;
import com.cloud.api.commands.CreateAccountCmd;
import com.cloud.api.commands.CreateDomainCmd;
import com.cloud.api.commands.CreateUserCmd;
import com.cloud.api.commands.DeleteAccountCmd;
import com.cloud.api.commands.DeleteUserCmd;
@ -221,7 +222,7 @@ public class MockAccountManagerImpl implements Manager, AccountManager {
}
@Override
public long findCorrectResourceLimit(AccountVO account, ResourceType type) {
public long findCorrectResourceLimit(long accountId, ResourceType type) {
// TODO Auto-generated method stub
return 0;
}
@ -338,5 +339,10 @@ public class MockAccountManagerImpl implements Manager, AccountManager {
// TODO Auto-generated method stub
}
@Override
public Domain createDomain(CreateDomainCmd cmd) {
return null;
}
}

View File

@ -1076,7 +1076,9 @@ CREATE TABLE `cloud`.`resource_count` (
PRIMARY KEY (`id`),
CONSTRAINT `fk_resource_count__account_id` FOREIGN KEY `fk_resource_count__account_id`(`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_resource_count__domain_id` FOREIGN KEY `fk_resource_count__domain_id`(`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE,
INDEX `i_resource_count__type`(`type`)
INDEX `i_resource_count__type`(`type`),
UNIQUE `i_resource_count__type_accountId`(`type`, `account_id`),
UNIQUE `i_resource_count__type_domaintId`(`type`, `domain_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cloud`.`op_host_capacity` (

View File

@ -54,3 +54,7 @@ ALTER TABLE `cloud_usage`.`usage_port_forwarding` ADD INDEX `i_usage_port_forwar
ALTER TABLE `cloud_usage`.`usage_network_offering` ADD INDEX `i_usage_network_offering__account_id`(`account_id`);
ALTER TABLE `cloud_usage`.`usage_network_offering` ADD INDEX `i_usage_network_offering__created`(`created`);
ALTER TABLE `cloud_usage`.`usage_network_offering` ADD INDEX `i_usage_network_offering__deleted`(`deleted`);
ALTER TABLE `cloud`.`resource_count` ADD UNIQUE `i_resource_count__type_accountId`(`type`, `account_id`);
ALTER TABLE `cloud`.`resource_count` ADD UNIQUE `i_resource_count__type_domaintId`(`type`, `domain_id`);