| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| package com.cloud.resourcelimit; |
| |
| import static com.cloud.utils.NumbersUtil.toHumanReadableSize; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.EnumMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.ScheduledExecutorService; |
| import java.util.concurrent.TimeUnit; |
| |
| import javax.inject.Inject; |
| import javax.naming.ConfigurationException; |
| |
| import com.cloud.cluster.ManagementServerHostVO; |
| import com.cloud.cluster.dao.ManagementServerHostDao; |
| import com.cloud.utils.db.GlobalLock; |
| import org.apache.cloudstack.acl.SecurityChecker.AccessType; |
| import org.apache.cloudstack.context.CallContext; |
| import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; |
| import org.apache.cloudstack.framework.config.ConfigKey; |
| import org.apache.cloudstack.framework.config.Configurable; |
| import org.apache.cloudstack.framework.config.dao.ConfigurationDao; |
| import org.apache.cloudstack.managed.context.ManagedContextRunnable; |
| import org.apache.cloudstack.reservation.dao.ReservationDao; |
| import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; |
| import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; |
| import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; |
| import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; |
| import org.apache.cloudstack.user.ResourceReservation; |
| import org.apache.cloudstack.utils.identity.ManagementServerNode; |
| import org.apache.commons.collections.CollectionUtils; |
| import org.apache.log4j.Logger; |
| import org.springframework.stereotype.Component; |
| |
| import com.cloud.alert.AlertManager; |
| import com.cloud.api.query.dao.UserVmJoinDao; |
| import com.cloud.api.query.vo.UserVmJoinVO; |
| import com.cloud.configuration.Config; |
| import com.cloud.configuration.Resource; |
| import com.cloud.configuration.Resource.ResourceOwnerType; |
| import com.cloud.configuration.Resource.ResourceType; |
| import com.cloud.configuration.ResourceCount; |
| import com.cloud.configuration.ResourceCountVO; |
| import com.cloud.configuration.ResourceLimitVO; |
| import com.cloud.configuration.dao.ResourceCountDao; |
| import com.cloud.configuration.dao.ResourceLimitDao; |
| import com.cloud.dc.VlanVO; |
| import com.cloud.dc.dao.VlanDao; |
| import com.cloud.domain.Domain; |
| import com.cloud.domain.DomainVO; |
| import com.cloud.domain.dao.DomainDao; |
| import com.cloud.exception.InvalidParameterValueException; |
| import com.cloud.exception.PermissionDeniedException; |
| import com.cloud.exception.ResourceAllocationException; |
| import com.cloud.network.dao.IPAddressDao; |
| import com.cloud.network.dao.IPAddressVO; |
| import com.cloud.network.dao.NetworkDao; |
| import com.cloud.network.vpc.dao.VpcDao; |
| import com.cloud.projects.Project; |
| import com.cloud.projects.ProjectAccount.Role; |
| import com.cloud.projects.dao.ProjectAccountDao; |
| import com.cloud.projects.dao.ProjectDao; |
| import com.cloud.storage.DataStoreRole; |
| import com.cloud.storage.SnapshotVO; |
| import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; |
| import com.cloud.storage.VMTemplateVO; |
| import com.cloud.storage.dao.SnapshotDao; |
| import com.cloud.storage.dao.VMTemplateDao; |
| import com.cloud.storage.dao.VolumeDao; |
| import com.cloud.storage.dao.VolumeDaoImpl.SumCount; |
| import com.cloud.user.Account; |
| import com.cloud.user.AccountManager; |
| import com.cloud.user.AccountVO; |
| import com.cloud.user.ResourceLimitService; |
| import com.cloud.user.dao.AccountDao; |
| import com.cloud.utils.component.ManagerBase; |
| import com.cloud.utils.concurrency.NamedThreadFactory; |
| import com.cloud.utils.db.DB; |
| import com.cloud.utils.db.EntityManager; |
| import com.cloud.utils.db.Filter; |
| import com.cloud.utils.db.GenericSearchBuilder; |
| import com.cloud.utils.db.JoinBuilder; |
| import com.cloud.utils.db.SearchBuilder; |
| import com.cloud.utils.db.SearchCriteria; |
| import com.cloud.utils.db.SearchCriteria.Func; |
| import com.cloud.utils.db.SearchCriteria.Op; |
| import com.cloud.utils.db.Transaction; |
| import com.cloud.utils.db.TransactionCallback; |
| import com.cloud.utils.db.TransactionCallbackNoReturn; |
| import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn; |
| import com.cloud.utils.db.TransactionStatus; |
| import com.cloud.utils.exception.CloudRuntimeException; |
| import com.cloud.vm.VirtualMachine.State; |
| import com.cloud.vm.VirtualMachineManager; |
| import com.cloud.vm.dao.UserVmDao; |
| import com.cloud.vm.dao.VMInstanceDao; |
| |
| @Component |
| public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLimitService, Configurable { |
| public static final Logger s_logger = Logger.getLogger(ResourceLimitManagerImpl.class); |
| |
| @Inject |
| private AccountManager _accountMgr; |
| @Inject |
| private AlertManager _alertMgr; |
| @Inject |
| private AccountDao _accountDao; |
| @Inject |
| private ConfigurationDao _configDao; |
| @Inject |
| private DomainDao _domainDao; |
| @Inject |
| private EntityManager _entityMgr; |
| @Inject |
| private IPAddressDao _ipAddressDao; |
| @Inject |
| private NetworkDao _networkDao; |
| @Inject |
| private ProjectDao _projectDao; |
| @Inject |
| private ProjectAccountDao _projectAccountDao; |
| @Inject |
| private ResourceCountDao _resourceCountDao; |
| @Inject |
| private ResourceLimitDao _resourceLimitDao; |
| @Inject |
| private ResourceLimitService resourceLimitService; |
| @Inject |
| private ReservationDao reservationDao; |
| @Inject |
| protected SnapshotDao _snapshotDao; |
| @Inject |
| private SnapshotDataStoreDao _snapshotDataStoreDao; |
| @Inject |
| private TemplateDataStoreDao _vmTemplateStoreDao; |
| @Inject |
| private UserVmDao _userVmDao; |
| @Inject |
| private UserVmJoinDao _userVmJoinDao; |
| @Inject |
| private VMInstanceDao _vmDao; |
| @Inject |
| protected VMTemplateDao _vmTemplateDao; |
| @Inject |
| private VolumeDao _volumeDao; |
| @Inject |
| private VpcDao _vpcDao; |
| @Inject |
| private VlanDao _vlanDao; |
| @Inject |
| private ManagementServerHostDao managementServerHostDao; |
| |
| protected GenericSearchBuilder<TemplateDataStoreVO, SumCount> templateSizeSearch; |
| protected GenericSearchBuilder<SnapshotDataStoreVO, SumCount> snapshotSizeSearch; |
| |
| protected SearchBuilder<ResourceCountVO> ResourceCountSearch; |
| ScheduledExecutorService _rcExecutor; |
| long _resourceCountCheckInterval = 0; |
| Map<ResourceType, Long> accountResourceLimitMap = new EnumMap<ResourceType, Long>(ResourceType.class); |
| Map<ResourceType, Long> domainResourceLimitMap = new EnumMap<ResourceType, Long>(ResourceType.class); |
| Map<ResourceType, Long> projectResourceLimitMap = new EnumMap<ResourceType, Long>(ResourceType.class); |
| |
| protected void removeResourceReservationIfNeededAndIncrementResourceCount(final long accountId, final ResourceType type, final long numToIncrement) { |
| Transaction.execute(new TransactionCallbackWithExceptionNoReturn<CloudRuntimeException>() { |
| @Override |
| public void doInTransactionWithoutResult(TransactionStatus status) throws CloudRuntimeException { |
| |
| Object obj = CallContext.current().getContextParameter(String.format("%s-%s", ResourceReservation.class.getSimpleName(), type.getName())); |
| if (obj instanceof Long) { |
| reservationDao.remove((long)obj); |
| } |
| if (!updateResourceCountForAccount(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 boolean start() { |
| if (_resourceCountCheckInterval > 0) { |
| _rcExecutor.scheduleAtFixedRate(new ResourceCountCheckTask(), _resourceCountCheckInterval, _resourceCountCheckInterval, TimeUnit.SECONDS); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean stop() { |
| return true; |
| } |
| |
| @Override |
| public boolean configure(final String name, final Map<String, Object> params) throws ConfigurationException { |
| |
| 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(); |
| |
| templateSizeSearch = _vmTemplateStoreDao.createSearchBuilder(SumCount.class); |
| templateSizeSearch.select("sum", Func.SUM, templateSizeSearch.entity().getSize()); |
| templateSizeSearch.and("downloadState", templateSizeSearch.entity().getDownloadState(), Op.EQ); |
| templateSizeSearch.and("destroyed", templateSizeSearch.entity().getDestroyed(), Op.EQ); |
| SearchBuilder<VMTemplateVO> join1 = _vmTemplateDao.createSearchBuilder(); |
| join1.and("accountId", join1.entity().getAccountId(), Op.EQ); |
| templateSizeSearch.join("templates", join1, templateSizeSearch.entity().getTemplateId(), join1.entity().getId(), JoinBuilder.JoinType.INNER); |
| templateSizeSearch.done(); |
| |
| snapshotSizeSearch = _snapshotDataStoreDao.createSearchBuilder(SumCount.class); |
| snapshotSizeSearch.select("sum", Func.SUM, snapshotSizeSearch.entity().getPhysicalSize()); |
| snapshotSizeSearch.and("state", snapshotSizeSearch.entity().getState(), Op.EQ); |
| snapshotSizeSearch.and("storeRole", snapshotSizeSearch.entity().getRole(), Op.EQ); |
| SearchBuilder<SnapshotVO> join2 = _snapshotDao.createSearchBuilder(); |
| join2.and("accountId", join2.entity().getAccountId(), Op.EQ); |
| snapshotSizeSearch.join("snapshots", join2, snapshotSizeSearch.entity().getSnapshotId(), join2.entity().getId(), JoinBuilder.JoinType.INNER); |
| snapshotSizeSearch.done(); |
| |
| _resourceCountCheckInterval = ResourceCountCheckInterval.value(); |
| if (_resourceCountCheckInterval > 0) { |
| _rcExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("ResourceCountChecker")); |
| } |
| |
| try { |
| projectResourceLimitMap.put(Resource.ResourceType.public_ip, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectPublicIPs.key()))); |
| projectResourceLimitMap.put(Resource.ResourceType.snapshot, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectSnapshots.key()))); |
| projectResourceLimitMap.put(Resource.ResourceType.template, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectTemplates.key()))); |
| projectResourceLimitMap.put(Resource.ResourceType.user_vm, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectUserVms.key()))); |
| projectResourceLimitMap.put(Resource.ResourceType.volume, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectVolumes.key()))); |
| projectResourceLimitMap.put(Resource.ResourceType.network, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectNetworks.key()))); |
| projectResourceLimitMap.put(Resource.ResourceType.vpc, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectVpcs.key()))); |
| projectResourceLimitMap.put(Resource.ResourceType.cpu, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectCpus.key()))); |
| projectResourceLimitMap.put(Resource.ResourceType.memory, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectMemory.key()))); |
| projectResourceLimitMap.put(Resource.ResourceType.primary_storage, Long.parseLong(_configDao.getValue(Config.DefaultMaxProjectPrimaryStorage.key()))); |
| projectResourceLimitMap.put(Resource.ResourceType.secondary_storage, MaxProjectSecondaryStorage.value()); |
| |
| accountResourceLimitMap.put(Resource.ResourceType.public_ip, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountPublicIPs.key()))); |
| accountResourceLimitMap.put(Resource.ResourceType.snapshot, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountSnapshots.key()))); |
| accountResourceLimitMap.put(Resource.ResourceType.template, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountTemplates.key()))); |
| accountResourceLimitMap.put(Resource.ResourceType.user_vm, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountUserVms.key()))); |
| accountResourceLimitMap.put(Resource.ResourceType.volume, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountVolumes.key()))); |
| accountResourceLimitMap.put(Resource.ResourceType.network, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountNetworks.key()))); |
| accountResourceLimitMap.put(Resource.ResourceType.vpc, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountVpcs.key()))); |
| accountResourceLimitMap.put(Resource.ResourceType.cpu, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountCpus.key()))); |
| accountResourceLimitMap.put(Resource.ResourceType.memory, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountMemory.key()))); |
| accountResourceLimitMap.put(Resource.ResourceType.primary_storage, Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountPrimaryStorage.key()))); |
| accountResourceLimitMap.put(Resource.ResourceType.secondary_storage, MaxAccountSecondaryStorage.value()); |
| |
| domainResourceLimitMap.put(Resource.ResourceType.public_ip, Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainPublicIPs.key()))); |
| domainResourceLimitMap.put(Resource.ResourceType.snapshot, Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainSnapshots.key()))); |
| domainResourceLimitMap.put(Resource.ResourceType.template, Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainTemplates.key()))); |
| domainResourceLimitMap.put(Resource.ResourceType.user_vm, Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainUserVms.key()))); |
| domainResourceLimitMap.put(Resource.ResourceType.volume, Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainVolumes.key()))); |
| domainResourceLimitMap.put(Resource.ResourceType.network, Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainNetworks.key()))); |
| domainResourceLimitMap.put(Resource.ResourceType.vpc, Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainVpcs.key()))); |
| domainResourceLimitMap.put(Resource.ResourceType.cpu, Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainCpus.key()))); |
| domainResourceLimitMap.put(Resource.ResourceType.memory, Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainMemory.key()))); |
| domainResourceLimitMap.put(Resource.ResourceType.primary_storage, Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainPrimaryStorage.key()))); |
| domainResourceLimitMap.put(Resource.ResourceType.secondary_storage, Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainSecondaryStorage.key()))); |
| } catch (NumberFormatException e) { |
| s_logger.error("NumberFormatException during configuration", e); |
| throw new ConfigurationException("Configuration failed due to NumberFormatException, see log for the stacktrace"); |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public void incrementResourceCount(long accountId, ResourceType type, Long... delta) { |
| // don't upgrade resource count for system account |
| if (accountId == Account.ACCOUNT_ID_SYSTEM) { |
| s_logger.trace("Not incrementing resource count for system accounts, returning"); |
| return; |
| } |
| |
| final long numToIncrement = (delta.length == 0) ? 1 : delta[0].longValue(); |
| removeResourceReservationIfNeededAndIncrementResourceCount(accountId, type, numToIncrement); |
| } |
| |
| @Override |
| public void decrementResourceCount(long accountId, ResourceType type, Long... delta) { |
| // don't upgrade resource count for system account |
| if (accountId == Account.ACCOUNT_ID_SYSTEM) { |
| s_logger.trace("Not decrementing resource count for system accounts, returning"); |
| return; |
| } |
| long numToDecrement = (delta.length == 0) ? 1 : delta[0].longValue(); |
| |
| if (!updateResourceCountForAccount(accountId, type, false, numToDecrement)) { |
| _alertMgr.sendAlert(AlertManager.AlertType.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 findCorrectResourceLimitForAccount(Account account, ResourceType type) { |
| |
| long max = Resource.RESOURCE_UNLIMITED; // if resource limit is not found, then we treat it as unlimited |
| |
| // No limits for Root Admin accounts |
| if (_accountMgr.isRootAdmin(account.getId())) { |
| return max; |
| } |
| |
| ResourceLimitVO limit = _resourceLimitDao.findByOwnerIdAndType(account.getId(), ResourceOwnerType.Account, type); |
| |
| // Check if limit is configured for account |
| if (limit != null) { |
| max = limit.getMax().longValue(); |
| } else { |
| // If the account has an no limit set, then return global default account limits |
| Long value = null; |
| if (account.getType() == Account.Type.PROJECT) { |
| value = projectResourceLimitMap.get(type); |
| } else { |
| value = accountResourceLimitMap.get(type); |
| } |
| if (value != null) { |
| if (value < 0) { // return unlimit if value is set to negative |
| return max; |
| } |
| // convert the value from GiB to bytes in case of primary or secondary storage. |
| if (type == ResourceType.primary_storage || type == ResourceType.secondary_storage) { |
| value = value * ResourceType.bytesToGiB; |
| } |
| return value; |
| } |
| } |
| |
| return max; |
| } |
| |
| @Override |
| public long findCorrectResourceLimitForAccount(long accountId, Long limit, ResourceType type) { |
| |
| long max = Resource.RESOURCE_UNLIMITED; // if resource limit is not found, then we treat it as unlimited |
| |
| // No limits for Root Admin accounts |
| if (_accountMgr.isRootAdmin(accountId)) { |
| return max; |
| } |
| |
| Account account = _accountDao.findById(accountId); |
| if (account == null) { |
| return max; |
| } |
| |
| // Check if limit is configured for account |
| if (limit != null) { |
| max = limit.longValue(); |
| } else { |
| // If the account has an no limit set, then return global default account limits |
| Long value = null; |
| if (account.getType() == Account.Type.PROJECT) { |
| value = projectResourceLimitMap.get(type); |
| } else { |
| value = accountResourceLimitMap.get(type); |
| } |
| if (value != null) { |
| if (value < 0) { // return unlimit if value is set to negative |
| return max; |
| } |
| if (type == ResourceType.primary_storage || type == ResourceType.secondary_storage) { |
| value = value * ResourceType.bytesToGiB; |
| } |
| return value; |
| } |
| } |
| |
| return max; |
| } |
| |
| @Override |
| public long findCorrectResourceLimitForDomain(Domain domain, ResourceType type) { |
| long max = Resource.RESOURCE_UNLIMITED; |
| |
| // no limits on ROOT domain |
| if (domain.getId() == Domain.ROOT_DOMAIN) { |
| return Resource.RESOURCE_UNLIMITED; |
| } |
| // Check account |
| ResourceLimitVO limit = _resourceLimitDao.findByOwnerIdAndType(domain.getId(), ResourceOwnerType.Domain, type); |
| |
| if (limit != null) { |
| max = limit.getMax().longValue(); |
| } else { |
| // check domain hierarchy |
| Long domainId = domain.getParent(); |
| while ((domainId != null) && (limit == null)) { |
| if (domainId == Domain.ROOT_DOMAIN) { |
| break; |
| } |
| limit = _resourceLimitDao.findByOwnerIdAndType(domainId, ResourceOwnerType.Domain, type); |
| DomainVO tmpDomain = _domainDao.findById(domainId); |
| domainId = tmpDomain.getParent(); |
| } |
| |
| if (limit != null) { |
| max = limit.getMax().longValue(); |
| } else { |
| Long value = null; |
| value = domainResourceLimitMap.get(type); |
| if (value != null) { |
| if (value < 0) { // return unlimit if value is set to negative |
| return max; |
| } |
| if (type == ResourceType.primary_storage || type == ResourceType.secondary_storage) { |
| value = value * ResourceType.bytesToGiB; |
| } |
| return value; |
| } |
| } |
| } |
| |
| return max; |
| } |
| |
| private void checkDomainResourceLimit(final Account account, final Project project, final ResourceType type, long numResources) throws ResourceAllocationException { |
| // check all domains in the account's domain hierarchy |
| Long domainId = null; |
| if (project != null) { |
| domainId = project.getDomainId(); |
| } else { |
| domainId = account.getDomainId(); |
| } |
| |
| while (domainId != null) { |
| DomainVO domain = _domainDao.findById(domainId); |
| // no limit check if it is ROOT domain |
| if (domainId != Domain.ROOT_DOMAIN) { |
| long domainResourceLimit = findCorrectResourceLimitForDomain(domain, type); |
| long currentDomainResourceCount = _resourceCountDao.getResourceCount(domainId, ResourceOwnerType.Domain, type); |
| long currentResourceReservation = reservationDao.getDomainReservation(domainId, type); |
| long requestedDomainResourceCount = currentDomainResourceCount + currentResourceReservation + numResources; |
| |
| String convDomainResourceLimit = String.valueOf(domainResourceLimit); |
| String convCurrentDomainResourceCount = String.valueOf(currentDomainResourceCount); |
| String convCurrentResourceReservation = String.valueOf(currentResourceReservation); |
| String convNumResources = String.valueOf(numResources); |
| |
| if (type == ResourceType.secondary_storage || type == ResourceType.primary_storage){ |
| convDomainResourceLimit = toHumanReadableSize(domainResourceLimit); |
| convCurrentDomainResourceCount = toHumanReadableSize(currentDomainResourceCount); |
| convCurrentResourceReservation = toHumanReadableSize(currentResourceReservation); |
| convNumResources = toHumanReadableSize(numResources); |
| } |
| |
| String messageSuffix = String.format( |
| " domain resource limits of Type '%s' for Domain Id = %s is exceeded: Domain Resource Limit = %s, " + |
| "Current Domain Resource Amount = %s, Current Resource Reservation = %s, Requested Resource Amount = %s.", |
| type, domainId, convDomainResourceLimit, |
| convCurrentDomainResourceCount, convCurrentResourceReservation, convNumResources |
| ); |
| |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Checking if" + messageSuffix); |
| } |
| |
| if (domainResourceLimit != Resource.RESOURCE_UNLIMITED && requestedDomainResourceCount > domainResourceLimit) { |
| String message = "Maximum" + messageSuffix; |
| ResourceAllocationException e = new ResourceAllocationException(message, type); |
| s_logger.error(message, e); |
| throw e; |
| } |
| } |
| domainId = domain.getParent(); |
| } |
| } |
| |
| private void checkAccountResourceLimit(final Account account, final Project project, final ResourceType type, long numResources) throws ResourceAllocationException { |
| // Check account limits |
| long accountResourceLimit = findCorrectResourceLimitForAccount(account, type); |
| long currentResourceCount = _resourceCountDao.getResourceCount(account.getId(), ResourceOwnerType.Account, type); |
| long currentResourceReservation = reservationDao.getAccountReservation(account.getId(), type); |
| long requestedResourceCount = currentResourceCount + currentResourceReservation + numResources; |
| |
| String convertedAccountResourceLimit = String.valueOf(accountResourceLimit); |
| String convertedCurrentResourceCount = String.valueOf(currentResourceCount); |
| String convertedCurrentResourceReservation = String.valueOf(currentResourceReservation); |
| String convertedNumResources = String.valueOf(numResources); |
| |
| if (type == ResourceType.secondary_storage || type == ResourceType.primary_storage){ |
| convertedAccountResourceLimit = toHumanReadableSize(accountResourceLimit); |
| convertedCurrentResourceCount = toHumanReadableSize(currentResourceCount); |
| convertedCurrentResourceReservation = toHumanReadableSize(currentResourceReservation); |
| convertedNumResources = toHumanReadableSize(numResources); |
| } |
| |
| String messageSuffix = String.format( |
| " amount of resources of Type = '%s' for %s in Domain Id = %s is exceeded: " + |
| "Account Resource Limit = %s, Current Account Resource Amount = %s, Current Account Resource Reservation = %s, Requested Resource Amount = %s.", |
| type, (project == null ? "Account Name = " + account.getAccountName() : "Project Name = " + project.getName()), account.getDomainId(), |
| convertedAccountResourceLimit, convertedCurrentResourceCount, convertedCurrentResourceReservation, convertedNumResources |
| ); |
| |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Checking if" + messageSuffix); |
| } |
| |
| if (accountResourceLimit != Resource.RESOURCE_UNLIMITED && requestedResourceCount > accountResourceLimit) { |
| String message = "Maximum" + messageSuffix; |
| ResourceAllocationException e = new ResourceAllocationException(message, type); |
| s_logger.error(message, e); |
| throw e; |
| } |
| } |
| |
| private List<ResourceCountVO> lockAccountAndOwnerDomainRows(long accountId, final ResourceType type) { |
| Set<Long> rowIdsToLock = _resourceCountDao.listAllRowsToUpdate(accountId, ResourceOwnerType.Account, type); |
| SearchCriteria<ResourceCountVO> sc = ResourceCountSearch.create(); |
| sc.setParameters("id", rowIdsToLock.toArray()); |
| return _resourceCountDao.lockRows(sc, null, true); |
| } |
| |
| private List<ResourceCountVO> lockDomainRows(long domainId, final ResourceType type) { |
| Set<Long> rowIdsToLock = _resourceCountDao.listAllRowsToUpdate(domainId, ResourceOwnerType.Domain, type); |
| SearchCriteria<ResourceCountVO> sc = ResourceCountSearch.create(); |
| sc.setParameters("id", rowIdsToLock.toArray()); |
| return _resourceCountDao.lockRows(sc, null, true); |
| } |
| |
| @Override |
| public long findDefaultResourceLimitForDomain(ResourceType resourceType) { |
| Long resourceLimit = null; |
| resourceLimit = domainResourceLimitMap.get(resourceType); |
| if (resourceLimit != null && (resourceType == ResourceType.primary_storage || resourceType == ResourceType.secondary_storage)) { |
| if (! Long.valueOf(Resource.RESOURCE_UNLIMITED).equals(resourceLimit)) { |
| resourceLimit = resourceLimit * ResourceType.bytesToGiB; |
| } |
| } else { |
| resourceLimit = Long.valueOf(Resource.RESOURCE_UNLIMITED); |
| } |
| return resourceLimit; |
| } |
| |
| @Override |
| public long findCorrectResourceLimitForAccountAndDomain(Account account, Domain domain, ResourceType type) { |
| long maxSecondaryStorageForAccount = findCorrectResourceLimitForAccount(account, type); |
| long maxSecondaryStorageForDomain = findCorrectResourceLimitForDomain(domain, type); |
| |
| if (maxSecondaryStorageForDomain == Resource.RESOURCE_UNLIMITED || maxSecondaryStorageForAccount == Resource.RESOURCE_UNLIMITED) { |
| return Math.max(maxSecondaryStorageForDomain, maxSecondaryStorageForAccount); |
| } |
| |
| return Math.min(maxSecondaryStorageForDomain, maxSecondaryStorageForAccount); |
| } |
| |
| @Override |
| @DB |
| public void checkResourceLimit(final Account account, final ResourceType type, long... count) throws ResourceAllocationException { |
| final long numResources = ((count.length == 0) ? 1 : count[0]); |
| Project project = null; |
| |
| // Don't place any limits on system or root admin accounts |
| if (_accountMgr.isRootAdmin(account.getId())) { |
| return; |
| } |
| |
| if (account.getType() == Account.Type.PROJECT) { |
| project = _projectDao.findByProjectAccountId(account.getId()); |
| } |
| |
| final Project projectFinal = project; |
| Transaction.execute(new TransactionCallbackWithExceptionNoReturn<ResourceAllocationException>() { |
| @Override |
| public void doInTransactionWithoutResult(TransactionStatus status) throws ResourceAllocationException { |
| // Lock all rows first so nobody else can read it |
| lockAccountAndOwnerDomainRows(account.getId(), type); |
| // Check account limits |
| checkAccountResourceLimit(account, projectFinal, type, numResources); |
| // check all domains in the account's domain hierarchy |
| checkDomainResourceLimit(account, projectFinal, type, numResources); |
| } |
| }); |
| } |
| |
| @Override |
| public List<ResourceLimitVO> searchForLimits(Long id, Long accountId, Long domainId, ResourceType resourceType, Long startIndex, Long pageSizeVal) { |
| Account caller = CallContext.current().getCallingAccount(); |
| List<ResourceLimitVO> limits = new ArrayList<ResourceLimitVO>(); |
| boolean isAccount = true; |
| |
| if (!_accountMgr.isAdmin(caller.getId())) { |
| accountId = caller.getId(); |
| domainId = null; |
| } else { |
| if (domainId != null) { |
| // verify domain information and permissions |
| Domain domain = _domainDao.findById(domainId); |
| if (domain == null) { |
| // return empty set |
| return limits; |
| } |
| |
| _accountMgr.checkAccess(caller, domain); |
| |
| if (accountId != null) { |
| // Verify account information and permissions |
| Account account = _accountDao.findById(accountId); |
| if (account == null) { |
| // return empty set |
| return limits; |
| } |
| |
| _accountMgr.checkAccess(caller, null, true, account); |
| domainId = null; |
| } |
| } |
| } |
| |
| // If id is passed in, get the record and return it if permission check has passed |
| if (id != null) { |
| ResourceLimitVO vo = _resourceLimitDao.findById(id); |
| if (vo.getAccountId() != null) { |
| _accountMgr.checkAccess(caller, null, true, _accountDao.findById(vo.getAccountId())); |
| limits.add(vo); |
| } else if (vo.getDomainId() != null) { |
| _accountMgr.checkAccess(caller, _domainDao.findById(vo.getDomainId())); |
| limits.add(vo); |
| } |
| |
| return limits; |
| } |
| |
| // If account is not specified, default it to caller account |
| if (accountId == null) { |
| if (domainId == null) { |
| accountId = caller.getId(); |
| isAccount = true; |
| } else { |
| isAccount = false; |
| } |
| } else { |
| isAccount = true; |
| } |
| |
| SearchBuilder<ResourceLimitVO> sb = _resourceLimitDao.createSearchBuilder(); |
| sb.and("accountId", sb.entity().getAccountId(), SearchCriteria.Op.EQ); |
| sb.and("domainId", sb.entity().getDomainId(), SearchCriteria.Op.EQ); |
| sb.and("type", sb.entity().getType(), SearchCriteria.Op.EQ); |
| |
| SearchCriteria<ResourceLimitVO> sc = sb.create(); |
| Filter filter = new Filter(ResourceLimitVO.class, "id", true, startIndex, pageSizeVal); |
| |
| if (accountId != null) { |
| sc.setParameters("accountId", accountId); |
| } |
| |
| if (domainId != null) { |
| sc.setParameters("domainId", domainId); |
| sc.setParameters("accountId", (Object[])null); |
| } |
| |
| if (resourceType != null) { |
| sc.setParameters("type", resourceType); |
| } |
| |
| List<ResourceLimitVO> foundLimits = _resourceLimitDao.search(sc, filter); |
| |
| if (resourceType != null) { |
| if (foundLimits.isEmpty()) { |
| if (isAccount) { |
| limits.add(new ResourceLimitVO(resourceType, findCorrectResourceLimitForAccount(_accountMgr.getAccount(accountId), resourceType), accountId, ResourceOwnerType.Account)); |
| } else { |
| limits.add(new ResourceLimitVO(resourceType, findCorrectResourceLimitForDomain(_domainDao.findById(domainId), resourceType), domainId, ResourceOwnerType.Domain)); |
| } |
| } else { |
| limits.addAll(foundLimits); |
| } |
| } else { |
| limits.addAll(foundLimits); |
| |
| // see if any limits are missing from the table, and if yes - get it from the config table and add |
| ResourceType[] resourceTypes = ResourceCount.ResourceType.values(); |
| if (foundLimits.size() != resourceTypes.length) { |
| List<String> accountLimitStr = new ArrayList<String>(); |
| List<String> domainLimitStr = new ArrayList<String>(); |
| for (ResourceLimitVO foundLimit : foundLimits) { |
| if (foundLimit.getAccountId() != null) { |
| accountLimitStr.add(foundLimit.getType().toString()); |
| } else { |
| domainLimitStr.add(foundLimit.getType().toString()); |
| } |
| } |
| |
| // get default from config values |
| if (isAccount) { |
| if (accountLimitStr.size() < resourceTypes.length) { |
| for (ResourceType rt : resourceTypes) { |
| if (!accountLimitStr.contains(rt.toString())) { |
| limits.add(new ResourceLimitVO(rt, findCorrectResourceLimitForAccount(_accountMgr.getAccount(accountId), rt), accountId, ResourceOwnerType.Account)); |
| } |
| } |
| } |
| |
| } else { |
| if (domainLimitStr.size() < resourceTypes.length) { |
| for (ResourceType rt : resourceTypes) { |
| if (!domainLimitStr.contains(rt.toString())) { |
| limits.add(new ResourceLimitVO(rt, findCorrectResourceLimitForDomain(_domainDao.findById(domainId), rt), domainId, ResourceOwnerType.Domain)); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| return limits; |
| } |
| |
| @Override |
| public ResourceLimitVO updateResourceLimit(Long accountId, Long domainId, Integer typeId, Long max) { |
| Account caller = CallContext.current().getCallingAccount(); |
| |
| if (max == null) { |
| max = new Long(Resource.RESOURCE_UNLIMITED); |
| } else if (max.longValue() < Resource.RESOURCE_UNLIMITED) { |
| throw new InvalidParameterValueException("Please specify either '-1' for an infinite limit, or a limit that is at least '0'."); |
| } |
| |
| // Map resource type |
| ResourceType resourceType = null; |
| if (typeId != null) { |
| for (ResourceType type : Resource.ResourceType.values()) { |
| if (type.getOrdinal() == typeId.intValue()) { |
| resourceType = type; |
| } |
| } |
| if (resourceType == null) { |
| throw new InvalidParameterValueException("Please specify valid resource type"); |
| } |
| } |
| |
| //Convert max storage size from GiB to bytes |
| if ((resourceType == ResourceType.primary_storage || resourceType == ResourceType.secondary_storage) && max >= 0) { |
| max *= ResourceType.bytesToGiB; |
| } |
| |
| ResourceOwnerType ownerType = null; |
| Long ownerId = null; |
| |
| if (accountId != null) { |
| Account account = _entityMgr.findById(Account.class, accountId); |
| if (account == null) { |
| throw new InvalidParameterValueException("Unable to find account " + accountId); |
| } |
| if (account.getId() == Account.ACCOUNT_ID_SYSTEM) { |
| throw new InvalidParameterValueException("Can't update system account"); |
| } |
| |
| //only Unlimited value is accepted if account is Root Admin |
| if (_accountMgr.isRootAdmin(account.getId()) && max.shortValue() != Resource.RESOURCE_UNLIMITED) { |
| throw new InvalidParameterValueException("Only " + Resource.RESOURCE_UNLIMITED + " limit is supported for Root Admin accounts"); |
| } |
| |
| if ((caller.getAccountId() == accountId.longValue()) && (_accountMgr.isDomainAdmin(caller.getId()) || caller.getType() == Account.Type.RESOURCE_DOMAIN_ADMIN)) { |
| // If the admin is trying to update their own account, disallow. |
| throw new PermissionDeniedException("Unable to update resource limit for their own account " + accountId + ", permission denied"); |
| } |
| |
| if (account.getType() == Account.Type.PROJECT) { |
| _accountMgr.checkAccess(caller, AccessType.ModifyProject, true, account); |
| } else { |
| _accountMgr.checkAccess(caller, null, true, account); |
| } |
| |
| ownerType = ResourceOwnerType.Account; |
| ownerId = accountId; |
| } else if (domainId != null) { |
| Domain domain = _entityMgr.findById(Domain.class, domainId); |
| |
| _accountMgr.checkAccess(caller, domain); |
| |
| if (Domain.ROOT_DOMAIN == domainId.longValue()) { |
| // no one can add limits on ROOT domain, disallow... |
| throw new PermissionDeniedException("Cannot update resource limit for ROOT domain " + domainId + ", permission denied"); |
| } |
| |
| if ((caller.getDomainId() == domainId.longValue()) && caller.getType() == Account.Type.DOMAIN_ADMIN || caller.getType() == Account.Type.RESOURCE_DOMAIN_ADMIN) { |
| // if the admin is trying to update their own domain, disallow... |
| throw new PermissionDeniedException("Unable to update resource limit for domain " + domainId + ", permission denied"); |
| } |
| Long parentDomainId = domain.getParent(); |
| if (parentDomainId != null) { |
| DomainVO parentDomain = _domainDao.findById(parentDomainId); |
| long parentMaximum = findCorrectResourceLimitForDomain(parentDomain, resourceType); |
| if ((parentMaximum >= 0) && (max.longValue() > parentMaximum)) { |
| throw new InvalidParameterValueException("Domain " + domain.getName() + "(id: " + parentDomain.getId() + ") has maximum allowed resource limit " + parentMaximum + " for " |
| + resourceType + ", please specify a value less that or equal to " + parentMaximum); |
| } |
| } |
| ownerType = ResourceOwnerType.Domain; |
| ownerId = domainId; |
| } |
| |
| if (ownerId == null) { |
| throw new InvalidParameterValueException("AccountId or domainId have to be specified in order to update resource limit"); |
| } |
| |
| ResourceLimitVO limit = _resourceLimitDao.findByOwnerIdAndType(ownerId, ownerType, resourceType); |
| if (limit != null) { |
| // Update the existing limit |
| _resourceLimitDao.update(limit.getId(), max); |
| return _resourceLimitDao.findById(limit.getId()); |
| } else { |
| return _resourceLimitDao.persist(new ResourceLimitVO(resourceType, max, ownerId, ownerType)); |
| } |
| } |
| |
| @Override |
| public List<ResourceCountVO> recalculateResourceCount(Long accountId, Long domainId, Integer typeId) throws InvalidParameterValueException, CloudRuntimeException, PermissionDeniedException { |
| Account callerAccount = CallContext.current().getCallingAccount(); |
| long count = 0; |
| List<ResourceCountVO> counts = new ArrayList<ResourceCountVO>(); |
| List<ResourceType> resourceTypes = new ArrayList<ResourceType>(); |
| |
| ResourceType resourceType = null; |
| |
| if (typeId != null) { |
| for (ResourceType type : Resource.ResourceType.values()) { |
| if (type.getOrdinal() == typeId.intValue()) { |
| resourceType = type; |
| } |
| } |
| if (resourceType == null) { |
| throw new InvalidParameterValueException("Please specify valid resource type"); |
| } |
| } |
| |
| DomainVO domain = _domainDao.findById(domainId); |
| if (domain == null) { |
| throw new InvalidParameterValueException("Please specify a valid domain ID."); |
| } |
| _accountMgr.checkAccess(callerAccount, domain); |
| |
| if (resourceType != null) { |
| resourceTypes.add(resourceType); |
| } else { |
| resourceTypes = Arrays.asList(Resource.ResourceType.values()); |
| } |
| |
| for (ResourceType type : resourceTypes) { |
| if (accountId != null) { |
| count = recalculateAccountResourceCount(accountId, type); |
| counts.add(new ResourceCountVO(type, count, accountId, ResourceOwnerType.Account)); |
| |
| } else { |
| count = recalculateDomainResourceCount(domainId, type); |
| counts.add(new ResourceCountVO(type, count, domainId, ResourceOwnerType.Domain)); |
| } |
| } |
| |
| return counts; |
| } |
| |
| @DB |
| protected boolean updateResourceCountForAccount(final long accountId, final ResourceType type, final boolean increment, final long delta) { |
| if (s_logger.isDebugEnabled()) { |
| String convertedDelta = String.valueOf(delta); |
| if (type == ResourceType.secondary_storage || type == ResourceType.primary_storage){ |
| convertedDelta = toHumanReadableSize(delta); |
| } |
| s_logger.debug("Updating resource Type = " + type + " count for Account = " + accountId + " Operation = " + (increment ? "increasing" : "decreasing") + " Amount = " + convertedDelta); |
| } |
| try { |
| return Transaction.execute(new TransactionCallback<Boolean>() { |
| @Override |
| public Boolean doInTransaction(TransactionStatus status) { |
| boolean result = true; |
| List<ResourceCountVO> rowsToUpdate = lockAccountAndOwnerDomainRows(accountId, type); |
| 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; |
| } |
| } |
| return result; |
| } |
| }); |
| } catch (Exception ex) { |
| s_logger.error("Failed to update resource count for account id=" + accountId); |
| return false; |
| } |
| } |
| |
| /** |
| * This will take care of re-calculation of resource counts for root and sub-domains |
| * and accounts of the sub-domains also. so just loop through immediate children of root domain |
| * |
| * @param domainId the domain level to start at |
| * @param type the resource type to do the recalculation for |
| * @return the resulting new resource count |
| */ |
| @DB |
| protected long recalculateDomainResourceCount(final long domainId, final ResourceType type) { |
| return Transaction.execute(new TransactionCallback<Long>() { |
| @Override |
| public Long doInTransaction(TransactionStatus status) { |
| long newResourceCount = 0; |
| lockDomainRows(domainId, type); |
| ResourceCountVO domainRC = _resourceCountDao.findByOwnerAndType(domainId, ResourceOwnerType.Domain, type); |
| long oldResourceCount = domainRC.getCount(); |
| |
| List<DomainVO> domainChildren = _domainDao.findImmediateChildrenForParent(domainId); |
| // for each child domain update the resource count |
| |
| // calculate project count here |
| if (type == ResourceType.project) { |
| newResourceCount += _projectDao.countProjectsForDomain(domainId); |
| } |
| |
| for (DomainVO childDomain : domainChildren) { |
| long childDomainResourceCount = recalculateDomainResourceCount(childDomain.getId(), type); |
| newResourceCount += childDomainResourceCount; // add the child domain count to parent domain count |
| } |
| List<AccountVO> accounts = _accountDao.findActiveAccountsForDomain(domainId); |
| for (AccountVO account : accounts) { |
| long accountResourceCount = recalculateAccountResourceCount(account.getId(), type); |
| newResourceCount += accountResourceCount; // add account's resource count to parent domain count |
| } |
| _resourceCountDao.setResourceCount(domainId, ResourceOwnerType.Domain, type, newResourceCount); |
| |
| if (oldResourceCount != newResourceCount) { |
| s_logger.warn("Discrepency in the resource count has been detected " + "(original count = " + oldResourceCount + " correct count = " + newResourceCount + ") for Type = " + type |
| + " for Domain ID = " + domainId + " is fixed during resource count recalculation."); |
| } |
| |
| return newResourceCount; |
| } |
| }); |
| } |
| |
| @DB |
| protected long recalculateAccountResourceCount(final long accountId, final ResourceType type) { |
| final Long newCount; |
| if (type == Resource.ResourceType.user_vm) { |
| newCount = _userVmDao.countAllocatedVMsForAccount(accountId, VirtualMachineManager.ResourceCountRunningVMsonly.value()); |
| } else if (type == Resource.ResourceType.volume) { |
| long virtualRouterCount = _vmDao.findIdsOfAllocatedVirtualRoutersForAccount(accountId).size(); |
| newCount = _volumeDao.countAllocatedVolumesForAccount(accountId) - virtualRouterCount; // don't count the volumes of virtual router |
| } else if (type == Resource.ResourceType.snapshot) { |
| newCount = _snapshotDao.countSnapshotsForAccount(accountId); |
| } else if (type == Resource.ResourceType.public_ip) { |
| newCount = calculatePublicIpForAccount(accountId); |
| } else if (type == Resource.ResourceType.template) { |
| newCount = _vmTemplateDao.countTemplatesForAccount(accountId); |
| } else if (type == Resource.ResourceType.project) { |
| newCount = _projectAccountDao.countByAccountIdAndRole(accountId, Role.Admin); |
| } else if (type == Resource.ResourceType.network) { |
| newCount = _networkDao.countNetworksUserCanCreate(accountId); |
| } else if (type == Resource.ResourceType.vpc) { |
| newCount = _vpcDao.countByAccountId(accountId); |
| } else if (type == Resource.ResourceType.cpu) { |
| newCount = countCpusForAccount(accountId); |
| } else if (type == Resource.ResourceType.memory) { |
| newCount = calculateMemoryForAccount(accountId); |
| } else if (type == Resource.ResourceType.primary_storage) { |
| List<Long> virtualRouters = _vmDao.findIdsOfAllocatedVirtualRoutersForAccount(accountId); |
| newCount = _volumeDao.primaryStorageUsedForAccount(accountId, virtualRouters); |
| } else if (type == Resource.ResourceType.secondary_storage) { |
| newCount = calculateSecondaryStorageForAccount(accountId); |
| } else { |
| throw new InvalidParameterValueException("Unsupported resource type " + type); |
| } |
| |
| long oldCount = 0; |
| final ResourceCountVO accountRC = _resourceCountDao.findByOwnerAndType(accountId, ResourceOwnerType.Account, type); |
| if (accountRC != null) { |
| oldCount = accountRC.getCount(); |
| } |
| |
| if (newCount == null || !newCount.equals(oldCount)) { |
| Transaction.execute(new TransactionCallbackNoReturn() { |
| @Override |
| public void doInTransactionWithoutResult(TransactionStatus status) { |
| lockAccountAndOwnerDomainRows(accountId, type); |
| _resourceCountDao.setResourceCount(accountId, ResourceOwnerType.Account, type, (newCount == null) ? 0 : newCount); |
| } |
| }); |
| } |
| |
| // No need to log message for primary and secondary storage because both are recalculating the |
| // resource count which will not lead to any discrepancy. |
| if (newCount != null && !newCount.equals(oldCount) && |
| type != Resource.ResourceType.primary_storage && type != Resource.ResourceType.secondary_storage) { |
| s_logger.warn("Discrepancy in the resource count " + "(original count=" + oldCount + " correct count = " + newCount + ") for type " + type + |
| " for account ID " + accountId + " is fixed during resource count recalculation."); |
| } |
| |
| return (newCount == null) ? 0 : newCount; |
| } |
| |
| public long countCpusForAccount(long accountId) { |
| long cputotal = 0; |
| // user vms |
| SearchBuilder<UserVmJoinVO> userVmSearch = _userVmJoinDao.createSearchBuilder(); |
| userVmSearch.and("accountId", userVmSearch.entity().getAccountId(), Op.EQ); |
| userVmSearch.and("state", userVmSearch.entity().getState(), SearchCriteria.Op.NIN); |
| userVmSearch.and("displayVm", userVmSearch.entity().isDisplayVm(), Op.EQ); |
| userVmSearch.groupBy(userVmSearch.entity().getId()); // select distinct |
| userVmSearch.done(); |
| |
| SearchCriteria<UserVmJoinVO> sc1 = userVmSearch.create(); |
| sc1.setParameters("accountId", accountId); |
| if (VirtualMachineManager.ResourceCountRunningVMsonly.value()) |
| sc1.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging, State.Stopped}); |
| else |
| sc1.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging}); |
| sc1.setParameters("displayVm", 1); |
| List<UserVmJoinVO> userVms = _userVmJoinDao.search(sc1,null); |
| for (UserVmJoinVO vm : userVms) { |
| cputotal += Long.valueOf(vm.getCpu()); |
| } |
| return cputotal; |
| } |
| |
| public long calculateMemoryForAccount(long accountId) { |
| long ramtotal = 0; |
| // user vms |
| SearchBuilder<UserVmJoinVO> userVmSearch = _userVmJoinDao.createSearchBuilder(); |
| userVmSearch.and("accountId", userVmSearch.entity().getAccountId(), Op.EQ); |
| userVmSearch.and("state", userVmSearch.entity().getState(), SearchCriteria.Op.NIN); |
| userVmSearch.and("displayVm", userVmSearch.entity().isDisplayVm(), Op.EQ); |
| userVmSearch.groupBy(userVmSearch.entity().getId()); // select distinct |
| userVmSearch.done(); |
| |
| SearchCriteria<UserVmJoinVO> sc1 = userVmSearch.create(); |
| sc1.setParameters("accountId", accountId); |
| if (VirtualMachineManager.ResourceCountRunningVMsonly.value()) |
| sc1.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging, State.Stopped}); |
| else |
| sc1.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging}); |
| sc1.setParameters("displayVm", 1); |
| List<UserVmJoinVO> userVms = _userVmJoinDao.search(sc1,null); |
| for (UserVmJoinVO vm : userVms) { |
| ramtotal += Long.valueOf(vm.getRamSize()); |
| } |
| return ramtotal; |
| } |
| |
| public long calculateSecondaryStorageForAccount(long accountId) { |
| long totalVolumesSize = _volumeDao.secondaryStorageUsedForAccount(accountId); |
| long totalSnapshotsSize = 0; |
| long totalTemplatesSize = 0; |
| |
| SearchCriteria<SumCount> sc = templateSizeSearch.create(); |
| sc.setParameters("downloadState", Status.DOWNLOADED); |
| sc.setParameters("destroyed", false); |
| sc.setJoinParameters("templates", "accountId", accountId); |
| List<SumCount> templates = _vmTemplateStoreDao.customSearch(sc, null); |
| if (templates != null) { |
| totalTemplatesSize = templates.get(0).sum; |
| } |
| |
| SearchCriteria<SumCount> sc2 = snapshotSizeSearch.create(); |
| sc2.setParameters("state", ObjectInDataStoreStateMachine.State.Ready); |
| sc2.setParameters("storeRole", DataStoreRole.Image); |
| sc2.setJoinParameters("snapshots", "accountId", accountId); |
| List<SumCount> snapshots = _snapshotDataStoreDao.customSearch(sc2, null); |
| if (snapshots != null) { |
| totalSnapshotsSize = snapshots.get(0).sum; |
| } |
| return totalVolumesSize + totalSnapshotsSize + totalTemplatesSize; |
| } |
| |
| private long calculatePublicIpForAccount(long accountId) { |
| Long dedicatedCount = 0L; |
| Long allocatedCount = 0L; |
| |
| List<VlanVO> dedicatedVlans = _vlanDao.listDedicatedVlans(accountId); |
| for (VlanVO dedicatedVlan : dedicatedVlans) { |
| List<IPAddressVO> ips = _ipAddressDao.listByVlanId(dedicatedVlan.getId()); |
| dedicatedCount += new Long(ips.size()); |
| } |
| allocatedCount = _ipAddressDao.countAllocatedIPsForAccount(accountId); |
| if (dedicatedCount > allocatedCount) { |
| return dedicatedCount; |
| } else { |
| return allocatedCount; |
| } |
| } |
| |
| @Override |
| public long getResourceCount(Account account, ResourceType type) { |
| return _resourceCountDao.getResourceCount(account.getId(), ResourceOwnerType.Account, type); |
| } |
| |
| private boolean isDisplayFlagOn(Boolean displayResource) { |
| |
| // 1. If its null assume displayResource = 1 |
| // 2. If its not null then send true if displayResource = 1 |
| return ! Boolean.FALSE.equals(displayResource); |
| } |
| |
| @Override |
| public void checkResourceLimit(Account account, ResourceType type, Boolean displayResource, long... count) throws ResourceAllocationException { |
| |
| if (isDisplayFlagOn(displayResource)) { |
| checkResourceLimit(account, type, count); |
| } |
| } |
| |
| @Override |
| public void incrementResourceCount(long accountId, ResourceType type, Boolean displayResource, Long... delta) { |
| |
| if (isDisplayFlagOn(displayResource)) { |
| incrementResourceCount(accountId, type, delta); |
| } |
| } |
| |
| @Override |
| public void decrementResourceCount(long accountId, ResourceType type, Boolean displayResource, Long... delta) { |
| |
| if (isDisplayFlagOn(displayResource)) { |
| decrementResourceCount(accountId, type, delta); |
| } |
| } |
| |
| @Override |
| public void changeResourceCount(long accountId, ResourceType type, Boolean displayResource, Long... delta) { |
| |
| // meaning that the display flag is not changed so neither increment or decrement |
| if (displayResource == null) { |
| return; |
| } |
| |
| // Increment because the display is turned on. |
| if (displayResource) { |
| incrementResourceCount(accountId, type, delta); |
| } else { |
| decrementResourceCount(accountId, type, delta); |
| } |
| } |
| |
| @Override |
| public ResourceReservation getReservation(final Account account, final Boolean displayResource, final Resource.ResourceType type, final Long delta) throws ResourceAllocationException { |
| if (! Boolean.FALSE.equals(displayResource)) { |
| return new CheckedReservation(account, type, delta, reservationDao, resourceLimitService); |
| } |
| throw new CloudRuntimeException("no reservation needed for resources that display as false"); |
| } |
| |
| @Override |
| public String getConfigComponentName() { |
| return ResourceLimitManagerImpl.class.getName(); |
| } |
| |
| @Override |
| public ConfigKey<?>[] getConfigKeys() { |
| return new ConfigKey<?>[] {ResourceCountCheckInterval, MaxAccountSecondaryStorage, MaxProjectSecondaryStorage}; |
| } |
| |
| protected class ResourceCountCheckTask extends ManagedContextRunnable { |
| public ResourceCountCheckTask() { |
| |
| } |
| |
| @Override |
| protected void runInContext() { |
| GlobalLock lock = GlobalLock.getInternLock("ResourceCheckTask"); |
| try { |
| if (lock.lock(30)) { |
| try { |
| ManagementServerHostVO msHost = managementServerHostDao.findOneByLongestRuntime(); |
| if (msHost == null || (msHost.getMsid() != ManagementServerNode.getManagementServerId())) { |
| s_logger.trace("Skipping the resource counters recalculation task on this management server"); |
| return; |
| } |
| runResourceCheckTaskInternal(); |
| } finally { |
| lock.unlock(); |
| } |
| } |
| } finally { |
| lock.releaseRef(); |
| } |
| } |
| |
| private void runResourceCheckTaskInternal() { |
| s_logger.info("Started resource counters recalculation periodic task."); |
| List<DomainVO> domains; |
| List<AccountVO> accounts; |
| // try/catch task, otherwise it won't be rescheduled in case of exception |
| try { |
| domains = _domainDao.findImmediateChildrenForParent(Domain.ROOT_DOMAIN); |
| } catch (Exception e) { |
| s_logger.warn("Resource counters recalculation periodic task failed, unable to fetch immediate children for the domain " + Domain.ROOT_DOMAIN, e); |
| // initialize domains as empty list to do best effort recalculation |
| domains = new ArrayList<>(); |
| } |
| // try/catch task, otherwise it won't be rescheduled in case of exception |
| try { |
| accounts = _accountDao.findActiveAccountsForDomain(Domain.ROOT_DOMAIN); |
| } catch (Exception e) { |
| s_logger.warn("Resource counters recalculation periodic task failed, unable to fetch active accounts for domain " + Domain.ROOT_DOMAIN, e); |
| // initialize accounts as empty list to do best effort recalculation |
| accounts = new ArrayList<>(); |
| } |
| |
| for (ResourceType type : ResourceType.values()) { |
| if (CollectionUtils.isEmpty(domains)) { |
| recalculateDomainResourceCountInContext(Domain.ROOT_DOMAIN, type); |
| } else { |
| for (Domain domain : domains) { |
| recalculateDomainResourceCount(domain.getId(), type); |
| } |
| } |
| |
| // run through the accounts in the root domain |
| for (AccountVO account : accounts) { |
| recalculateAccountResourceCountInContext(account.getId(), type); |
| } |
| } |
| s_logger.info("Finished resource counters recalculation periodic task."); |
| } |
| |
| private void recalculateDomainResourceCountInContext(long domainId, ResourceType type) { |
| try { |
| recalculateDomainResourceCount(domainId, type); |
| } catch (Exception e) { |
| s_logger.warn("Resource counters recalculation periodic task failed for the domain " + domainId + " and the resource type " + type + " .", e); |
| } |
| } |
| private void recalculateAccountResourceCountInContext(long accountId, ResourceType type) { |
| try { |
| recalculateAccountResourceCount(accountId, type); |
| } catch (Exception e) { |
| s_logger.warn("Resource counters recalculation periodic task failed for the account " + accountId + " and the resource type " + type + " .", e); |
| } |
| } |
| } |
| } |