From aa4f654929b6845da642444764d0a12c7bf8f48f Mon Sep 17 00:00:00 2001 From: Murali Reddy Date: Mon, 13 Jun 2011 10:55:57 +0530 Subject: [PATCH] bug 9419: implement api to reset resource count added a command to reset resource count for account/domain based on real usage of resources --- api/src/com/cloud/api/ResponseGenerator.java | 4 + .../api/commands/UpdateResourceCountCmd.java | 4 +- .../api/response/ResourceCountResponse.java | 6 +- api/src/com/cloud/user/AccountService.java | 12 ++ client/tomcatconf/commands.properties.in | 1 + .../src/com/cloud/api/ApiResponseHelper.java | 24 +++ .../configuration/dao/ResourceCountDao.java | 16 ++ .../dao/ResourceCountDaoImpl.java | 28 ++++ .../src/com/cloud/domain/dao/DomainDao.java | 1 + .../com/cloud/domain/dao/DomainDaoImpl.java | 14 +- .../com/cloud/network/dao/IPAddressDao.java | 4 +- .../cloud/network/dao/IPAddressDaoImpl.java | 18 ++- .../com/cloud/storage/dao/SnapshotDao.java | 2 +- .../cloud/storage/dao/SnapshotDaoImpl.java | 29 +++- .../com/cloud/storage/dao/VMTemplateDao.java | 1 + .../cloud/storage/dao/VMTemplateDaoImpl.java | 23 ++- .../src/com/cloud/storage/dao/VolumeDao.java | 2 +- .../com/cloud/storage/dao/VolumeDaoImpl.java | 22 ++- server/src/com/cloud/user/AccountManager.java | 13 ++ .../com/cloud/user/AccountManagerImpl.java | 147 +++++++++++++++++- server/src/com/cloud/user/dao/AccountDao.java | 1 + .../com/cloud/user/dao/AccountDaoImpl.java | 13 ++ server/src/com/cloud/vm/dao/UserVmDao.java | 2 +- .../src/com/cloud/vm/dao/UserVmDaoImpl.java | 18 +++ .../src/com/cloud/vm/dao/VMInstanceDao.java | 1 + .../com/cloud/vm/dao/VMInstanceDaoImpl.java | 23 ++- 26 files changed, 402 insertions(+), 27 deletions(-) diff --git a/api/src/com/cloud/api/ResponseGenerator.java b/api/src/com/cloud/api/ResponseGenerator.java index 28b631c633b..6a1ed80b4ae 100644 --- a/api/src/com/cloud/api/ResponseGenerator.java +++ b/api/src/com/cloud/api/ResponseGenerator.java @@ -45,6 +45,7 @@ import com.cloud.api.response.NetworkResponse; import com.cloud.api.response.PodResponse; import com.cloud.api.response.RemoteAccessVpnResponse; import com.cloud.api.response.ResourceLimitResponse; +import com.cloud.api.response.ResourceCountResponse; import com.cloud.api.response.SecurityGroupResponse; import com.cloud.api.response.ServiceOfferingResponse; import com.cloud.api.response.SnapshotPolicyResponse; @@ -63,6 +64,7 @@ import com.cloud.async.AsyncJob; import com.cloud.capacity.Capacity; import com.cloud.configuration.Configuration; import com.cloud.configuration.ResourceLimit; +import com.cloud.configuration.ResourceCount; import com.cloud.dc.DataCenter; import com.cloud.dc.Pod; import com.cloud.dc.Vlan; @@ -108,6 +110,8 @@ public interface ResponseGenerator { ResourceLimitResponse createResourceLimitResponse(ResourceLimit limit); + ResourceCountResponse createResourceCountResponse(ResourceCount resourceCount); + ServiceOfferingResponse createServiceOfferingResponse(ServiceOffering offering); ConfigurationResponse createConfigurationResponse(Configuration cfg); diff --git a/api/src/com/cloud/api/commands/UpdateResourceCountCmd.java b/api/src/com/cloud/api/commands/UpdateResourceCountCmd.java index 7fae8226930..5326ab4b298 100644 --- a/api/src/com/cloud/api/commands/UpdateResourceCountCmd.java +++ b/api/src/com/cloud/api/commands/UpdateResourceCountCmd.java @@ -41,10 +41,10 @@ public class UpdateResourceCountCmd extends BaseCmd { //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// - @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="Update resource for a specified account. Must be used with the domainId parameter.") + @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="Update resource count for a specified account. Must be used with the domainId parameter.") private String accountName; - @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.LONG, description="Update resource limits for all accounts in specified domain. If used with the account parameter, updates resource limits for a specified account in specified domain.") + @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.LONG, description="Update resource counts for all accounts & child domains in specified domain. If used with the account parameter, updates resource counts for a specified account in specified domain.") private Long domainId; @Parameter(name=ApiConstants.RESOURCE_TYPE, type=CommandType.INTEGER, required=true, description="Type of resource to update. Values are 0, 1, 2, 3, and 4. 0 - Instance. Number of instances a user can create. " + diff --git a/api/src/com/cloud/api/response/ResourceCountResponse.java b/api/src/com/cloud/api/response/ResourceCountResponse.java index 7e2fb8470f4..609c31b98f4 100644 --- a/api/src/com/cloud/api/response/ResourceCountResponse.java +++ b/api/src/com/cloud/api/response/ResourceCountResponse.java @@ -21,13 +21,13 @@ import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; public class ResourceCountResponse extends BaseResponse { - @SerializedName("account") @Param(description="the account of the resource count") + @SerializedName("account") @Param(description="the account for which resource count's are updated") private String accountName; - @SerializedName("domainid") @Param(description="the domain ID of the resource count") + @SerializedName("domainid") @Param(description="the domain ID for which resource count's are updated") private Long domainId; - @SerializedName("domain") @Param(description="the domain name of the resource count") + @SerializedName("domain") @Param(description="the domain name for which resource count's are updated") private String domainName; @SerializedName("resourcetype") @Param(description="resource type. Values include 0, 1, 2, 3, 4. See the resourceType parameter for more information on these values.") diff --git a/api/src/com/cloud/user/AccountService.java b/api/src/com/cloud/user/AccountService.java index d8d92e21f32..914eb1b3844 100644 --- a/api/src/com/cloud/user/AccountService.java +++ b/api/src/com/cloud/user/AccountService.java @@ -32,8 +32,10 @@ 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.UpdateUserCmd; import com.cloud.configuration.ResourceLimit; +import com.cloud.configuration.ResourceCount; import com.cloud.domain.Domain; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ResourceUnavailableException; @@ -141,6 +143,16 @@ public interface AccountService { */ ResourceLimit updateResourceLimit(UpdateResourceLimitCmd cmd); + + /** + * Updates an existing resource count details for the account/domain + * + * @param cmd + * the command that wraps the domainId, accountId, resource type parameters + * @return the updated/created resource count + */ + ResourceCount updateResourceCount(UpdateResourceCountCmd cmd); + /** * Search for resource limits for the given id and/or account and/or type and/or domain. * diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index a6ea8e27212..1db91f8139f 100755 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -32,6 +32,7 @@ getCloudIdentifier=com.cloud.api.commands.GetCloudIdentifierCmd;15 #### Limit commands updateResourceLimit=com.cloud.api.commands.UpdateResourceLimitCmd;7 +updateResourceCount=com.cloud.api.commands.UpdateResourceCountCmd;7 listResourceLimits=com.cloud.api.commands.ListResourceLimitsCmd;15 #### VM commands diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 7d9a51aa836..566f065edcf 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -59,6 +59,7 @@ import com.cloud.api.response.NicResponse; import com.cloud.api.response.PodResponse; import com.cloud.api.response.RemoteAccessVpnResponse; import com.cloud.api.response.ResourceLimitResponse; +import com.cloud.api.response.ResourceCountResponse; import com.cloud.api.response.SecurityGroupResponse; import com.cloud.api.response.SecurityGroupResultObject; import com.cloud.api.response.ServiceOfferingResponse; @@ -82,6 +83,7 @@ import com.cloud.capacity.CapacityVO; import com.cloud.configuration.Configuration; import com.cloud.configuration.ResourceCount.ResourceType; import com.cloud.configuration.ResourceLimit; +import com.cloud.configuration.ResourceCount; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; @@ -396,6 +398,28 @@ public class ApiResponseHelper implements ResponseGenerator { return resourceLimitResponse; } + @Override + public ResourceCountResponse createResourceCountResponse(ResourceCount resourceCount) { + ResourceCountResponse resourceCountResponse = new ResourceCountResponse(); + + if (resourceCount.getAccountId() != null) { + Account accountTemp = ApiDBUtils.findAccountById(resourceCount.getAccountId()); + if (accountTemp != null) { + resourceCountResponse.setAccountName(accountTemp.getAccountName()); + resourceCountResponse.setDomainId(accountTemp.getDomainId()); + resourceCountResponse.setDomainName(ApiDBUtils.findDomainById(accountTemp.getDomainId()).getName()); + } + } else if (resourceCount.getDomainId() != null) { + resourceCountResponse.setDomainId(resourceCount.getDomainId()); + resourceCountResponse.setDomainName(ApiDBUtils.findDomainById(resourceCount.getDomainId()).getName()); + } + + resourceCountResponse.setResourceType(Integer.valueOf(resourceCount.getType().ordinal()).toString()); + resourceCountResponse.setResourceCount(resourceCount.getCount()); + resourceCountResponse.setObjectName("resourcecount"); + return resourceCountResponse; + } + @Override public ServiceOfferingResponse createServiceOfferingResponse(ServiceOffering offering) { ServiceOfferingResponse offeringResponse = new ServiceOfferingResponse(); diff --git a/server/src/com/cloud/configuration/dao/ResourceCountDao.java b/server/src/com/cloud/configuration/dao/ResourceCountDao.java index 6925f5c08b2..fe6197487ec 100644 --- a/server/src/com/cloud/configuration/dao/ResourceCountDao.java +++ b/server/src/com/cloud/configuration/dao/ResourceCountDao.java @@ -40,6 +40,22 @@ public interface ResourceCountDao extends GenericDao { */ public long getDomainCount(long domainId, ResourceType type); + /** + * Set the count of in use resources for an account by type + * @param accountId the id of the account to set the resource count + * @param type the type of resource (e.g. user_vm, public_ip, volume) + * @param the count of resources in use for the given type and account + */ + public void setAccountCount(long accountId, ResourceType type, long count); + + /** + * Get the count of in use resources for a domain by type + * @param domainId the id of the domain to set the resource count + * @param type the type of resource (e.g. user_vm, public_ip, volume) + * @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 diff --git a/server/src/com/cloud/configuration/dao/ResourceCountDaoImpl.java b/server/src/com/cloud/configuration/dao/ResourceCountDaoImpl.java index e829cf7e2ef..b05898374d3 100644 --- a/server/src/com/cloud/configuration/dao/ResourceCountDaoImpl.java +++ b/server/src/com/cloud/configuration/dao/ResourceCountDaoImpl.java @@ -79,6 +79,34 @@ public class ResourceCountDaoImpl extends GenericDaoBase return (resourceCountVO != null) ? resourceCountVO.getCount() : 0; } + @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 { + 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 { + resourceCountVO.setCount(count); + update(resourceCountVO.getId(), resourceCountVO); + } + } + @Override public void updateAccountCount(long accountId, ResourceType type, boolean increment, long delta) { delta = increment ? delta : delta * -1; diff --git a/server/src/com/cloud/domain/dao/DomainDao.java b/server/src/com/cloud/domain/dao/DomainDao.java index d94260fc7df..0edf66cba54 100644 --- a/server/src/com/cloud/domain/dao/DomainDao.java +++ b/server/src/com/cloud/domain/dao/DomainDao.java @@ -29,5 +29,6 @@ public interface DomainDao extends GenericDao { public DomainVO findDomainByPath(String domainPath); public boolean isChildDomain(Long parentId, Long childId); DomainVO findImmediateChildForParent(Long parentId); + List findImmediateChildrenForParent(Long parentId); List findAllChildren(String path, Long parentId); } diff --git a/server/src/com/cloud/domain/dao/DomainDaoImpl.java b/server/src/com/cloud/domain/dao/DomainDaoImpl.java index 27c10bf2402..51d2be29077 100644 --- a/server/src/com/cloud/domain/dao/DomainDaoImpl.java +++ b/server/src/com/cloud/domain/dao/DomainDaoImpl.java @@ -66,7 +66,8 @@ public class DomainDaoImpl extends GenericDaoBase implements Dom FindAllChildrenSearch = createSearchBuilder(); FindAllChildrenSearch.and("path", FindAllChildrenSearch.entity().getPath(), SearchCriteria.Op.LIKE); FindAllChildrenSearch.and("id", FindAllChildrenSearch.entity().getId(), SearchCriteria.Op.NEQ); - FindAllChildrenSearch.done(); + FindAllChildrenSearch.done(); + } public void update(Long id, String domainName, String domainPath) { @@ -196,14 +197,21 @@ public class DomainDaoImpl extends GenericDaoBase implements Dom sc.addAnd("path", SearchCriteria.Op.EQ, domainPath); return findOneBy(sc); } - + @Override public DomainVO findImmediateChildForParent(Long parentId){ SearchCriteria sc = ImmediateChildDomainSearch.create(); sc.setParameters("parent", parentId); return (listBy(sc).size() > 0 ? listBy(sc).get(0) : null);//may need to revisit for multiple children case } - + + @Override + public List findImmediateChildrenForParent(Long parentId){ + SearchCriteria sc = ImmediateChildDomainSearch.create(); + sc.setParameters("parent", parentId); + return listBy(sc); + } + @Override public List findAllChildren(String path, Long parentId){ SearchCriteria sc = FindAllChildrenSearch.create(); diff --git a/server/src/com/cloud/network/dao/IPAddressDao.java b/server/src/com/cloud/network/dao/IPAddressDao.java index 8c8d858f480..708111b5b0a 100644 --- a/server/src/com/cloud/network/dao/IPAddressDao.java +++ b/server/src/com/cloud/network/dao/IPAddressDao.java @@ -42,7 +42,9 @@ public interface IPAddressDao extends GenericDao { int countIPs(long dcId, long vlanDbId, boolean onlyCountAllocated); - int countIPs(long dcId, Long accountId, String vlanId, String vlanGateway, String vlanNetmask); + int countIPs(long dcId, Long accountId, String vlanId, String vlanGateway, String vlanNetmask); + + long countAllocatedIPsForAccount(long accountId); boolean mark(long dcId, Ip ip); diff --git a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java index d1248972cc3..3a1f3614ff6 100644 --- a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java +++ b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java @@ -40,6 +40,7 @@ import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.Ip; +import com.cloud.vm.VirtualMachine; @Local(value = { IPAddressDao.class }) @DB @@ -52,7 +53,7 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen protected final GenericSearchBuilder AllocatedIpCount; protected final GenericSearchBuilder AllIpCountForDashboard; protected final GenericSearchBuilder AllocatedIpCountForDashboard; - + protected final GenericSearchBuilder AllocatedIpCountForAccount; @@ -98,7 +99,12 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen AllocatedIpCountForDashboard.and("dc", AllocatedIpCountForDashboard.entity().getDataCenterId(), Op.EQ); AllocatedIpCountForDashboard.and("allocated", AllocatedIpCountForDashboard.entity().getAllocatedTime(), Op.NNULL); AllocatedIpCountForDashboard.done(); - + + AllocatedIpCountForAccount = createSearchBuilder(Long.class); + AllocatedIpCountForAccount.select(null, Func.COUNT, AllocatedIpCountForAccount.entity().getAddress()); + AllocatedIpCountForAccount.and("account", AllocatedIpCountForAccount.entity().getAllocatedToAccountId(), Op.EQ); + AllocatedIpCountForAccount.and("allocated", AllocatedIpCountForAccount.entity().getAllocatedTime(), Op.NNULL); + AllocatedIpCountForAccount.done(); } @Override @@ -278,5 +284,11 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen return findOneBy(sc); } - + + @Override + public long countAllocatedIPsForAccount(long accountId) { + SearchCriteria sc = AllocatedIpCountForAccount.create(); + sc.setParameters("account", accountId); + return customSearch(sc, null).get(0); + } } diff --git a/server/src/com/cloud/storage/dao/SnapshotDao.java b/server/src/com/cloud/storage/dao/SnapshotDao.java index 5875feb0312..98f8904e08c 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDao.java +++ b/server/src/com/cloud/storage/dao/SnapshotDao.java @@ -39,5 +39,5 @@ public interface SnapshotDao extends GenericDao { long updateSnapshotSecHost(long dcId, long secHostId); List listByHostId(Filter filter, long hostId); List listByHostId(long hostId); - + public Long countSnapshotsForAccount(long accountId); } diff --git a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java index bc1285802c3..1c1c00a4fee 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java +++ b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java @@ -31,9 +31,14 @@ import com.cloud.storage.Snapshot.Type; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.SearchCriteria.Func; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.State; @Local (value={SnapshotDao.class}) public class SnapshotDaoImpl extends GenericDaoBase implements SnapshotDao { @@ -49,7 +54,9 @@ public class SnapshotDaoImpl extends GenericDaoBase implements private final SearchBuilder backupUuidSearch; private final SearchBuilder VolumeIdVersionSearch; private final SearchBuilder HostIdSearch; - + private final SearchBuilder AccountIdSearch; + private final GenericSearchBuilder CountSnapshotsByAccount; + @Override public SnapshotVO findNextSnapshot(long snapshotId) { SearchCriteria sc = ParentIdSearch.create(); @@ -99,7 +106,7 @@ public class SnapshotDaoImpl extends GenericDaoBase implements sc.setParameters("status", Status.DOWNLOADED); return listBy(sc, filter); } - + @Override public List listByVolumeIdIncludingRemoved(long volumeId) { SearchCriteria sc = VolumeIdSearch.create(); @@ -148,7 +155,16 @@ public class SnapshotDaoImpl extends GenericDaoBase implements backupUuidSearch = createSearchBuilder(); backupUuidSearch.and("backupUuid", backupUuidSearch.entity().getBackupSnapshotId(), SearchCriteria.Op.EQ); backupUuidSearch.done(); - + + AccountIdSearch = createSearchBuilder(); + AccountIdSearch.and("accountId", AccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ); + AccountIdSearch.done(); + + CountSnapshotsByAccount = createSearchBuilder(Long.class); + CountSnapshotsByAccount.select(null, Func.COUNT, null); + CountSnapshotsByAccount.and("account", CountSnapshotsByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); + CountSnapshotsByAccount.and("removed", CountSnapshotsByAccount.entity().getRemoved(), SearchCriteria.Op.NNULL); + CountSnapshotsByAccount.done(); } @Override @@ -221,4 +237,11 @@ public class SnapshotDaoImpl extends GenericDaoBase implements } return 0; } + + @Override + public Long countSnapshotsForAccount(long accountId) { + SearchCriteria sc = CountSnapshotsByAccount.create(); + sc.setParameters("account", accountId); + return customSearch(sc, null).get(0); + } } diff --git a/server/src/com/cloud/storage/dao/VMTemplateDao.java b/server/src/com/cloud/storage/dao/VMTemplateDao.java index 18c802bef26..30e0f00837c 100644 --- a/server/src/com/cloud/storage/dao/VMTemplateDao.java +++ b/server/src/com/cloud/storage/dao/VMTemplateDao.java @@ -72,5 +72,6 @@ public interface VMTemplateDao extends GenericDao { VMTemplateVO findRoutingTemplate(HypervisorType type); List listPrivateTemplatesByHost(Long hostId); + public Long countTemplatesForAccount(long accountId); } diff --git a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java index c9dbb9fe3a2..6b43ab51887 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java @@ -46,6 +46,7 @@ import com.cloud.info.RunningHostCountInfo; import com.cloud.storage.Storage; import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; +import com.cloud.storage.SnapshotVO; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VMTemplateZoneVO; import com.cloud.template.VirtualMachineTemplate.TemplateFilter; @@ -56,10 +57,12 @@ import com.cloud.utils.component.Inject; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; +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.Transaction; +import com.cloud.utils.db.SearchCriteria.Func; @Local(value={VMTemplateDao.class}) public class VMTemplateDaoImpl extends GenericDaoBase implements VMTemplateDao { @@ -90,7 +93,8 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem private SearchBuilder PublicSearch; private SearchBuilder NameAccountIdSearch; private SearchBuilder PublicIsoSearch; - + private GenericSearchBuilder CountTemplatesByAccount; + private String routerTmpltName; private String consoleProxyTmpltName; @@ -278,7 +282,13 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem TmpltsInZoneSearch.join("tmpltzone", tmpltZoneSearch, tmpltZoneSearch.entity().getTemplateId(), TmpltsInZoneSearch.entity().getId(), JoinBuilder.JoinType.INNER); tmpltZoneSearch.done(); TmpltsInZoneSearch.done(); - + + CountTemplatesByAccount = createSearchBuilder(Long.class); + CountTemplatesByAccount.select(null, Func.COUNT, null); + CountTemplatesByAccount.and("account", CountTemplatesByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); + CountTemplatesByAccount.and("removed", CountTemplatesByAccount.entity().getRemoved(), SearchCriteria.Op.NNULL); + CountTemplatesByAccount.done(); + return result; } @@ -534,5 +544,12 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem } else { return null; } - } + } + + @Override + public Long countTemplatesForAccount(long accountId) { + SearchCriteria sc = CountTemplatesByAccount.create(); + sc.setParameters("account", accountId); + return customSearch(sc, null).get(0); + } } diff --git a/server/src/com/cloud/storage/dao/VolumeDao.java b/server/src/com/cloud/storage/dao/VolumeDao.java index e756cc76b7a..e7f4bca9481 100755 --- a/server/src/com/cloud/storage/dao/VolumeDao.java +++ b/server/src/com/cloud/storage/dao/VolumeDao.java @@ -44,7 +44,7 @@ public interface VolumeDao extends GenericDao { List findByPoolId(long poolId); List findByInstanceAndDeviceId(long instanceId, long deviceId); List findUsableVolumesForInstance(long instanceId); - + Long countAllocatedVolumesForAccount(long accountId); /** * Updates the volume only if the state in memory matches the state in the database. * @param vol Volume to be updated. diff --git a/server/src/com/cloud/storage/dao/VolumeDaoImpl.java b/server/src/com/cloud/storage/dao/VolumeDaoImpl.java index 9ca6708f9d6..49db3566395 100755 --- a/server/src/com/cloud/storage/dao/VolumeDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VolumeDaoImpl.java @@ -45,6 +45,8 @@ import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; import com.cloud.utils.db.UpdateBuilder; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VirtualMachine.State; @Local(value=VolumeDao.class) @DB(txn=false) public class VolumeDaoImpl extends GenericDaoBase implements VolumeDao { @@ -55,7 +57,7 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol protected final GenericSearchBuilder ActiveTemplateSearch; protected final SearchBuilder InstanceStatesSearch; protected final SearchBuilder AllFieldsSearch; - + protected GenericSearchBuilder CountByAccount; protected final Attribute _stateAttr; protected static final String SELECT_VM_SQL = "SELECT DISTINCT instance_id from volumes v where v.host_id = ? and v.mirror_state = ?"; @@ -73,7 +75,7 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol public List findByAccount(long accountId) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("accountId", accountId); - sc.setParameters("notDestroyed", Volume.State.Destroy); + sc.setParameters("state", Volume.State.Ready); return listBy(sc); } @@ -305,6 +307,12 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol InstanceStatesSearch.and("states", InstanceStatesSearch.entity().getState(), Op.IN); InstanceStatesSearch.done(); + CountByAccount = createSearchBuilder(Long.class); + CountByAccount.select(null, Func.COUNT, null); + CountByAccount.and("account", CountByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); + CountByAccount.and("state", CountByAccount.entity().getState(), SearchCriteria.Op.NIN); + CountByAccount.done(); + _stateAttr = _allAttributes.get("state"); assert _stateAttr != null : "Couldn't get the state attribute"; } @@ -317,7 +325,15 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol SumCount sumCount = results.get(0); return new Pair(sumCount.count, sumCount.sum); } - + + @Override + public Long countAllocatedVolumesForAccount(long accountId) { + SearchCriteria sc = CountByAccount.create(); + sc.setParameters("account", accountId); + sc.setParameters("state", new Object[] {Volume.State.Destroy, State.Expunging}); + return customSearch(sc, null).get(0); + } + public static class SumCount { public long sum; public long count; diff --git a/server/src/com/cloud/user/AccountManager.java b/server/src/com/cloud/user/AccountManager.java index 52a07a18a9c..bbf7c146b77 100755 --- a/server/src/com/cloud/user/AccountManager.java +++ b/server/src/com/cloud/user/AccountManager.java @@ -63,6 +63,19 @@ public interface AccountManager extends AccountService { */ public long findCorrectResourceLimit(DomainVO domain, ResourceType type); + /** + * Updates the resource count of an account to reflect current usage by account + * @param accountId + * @param type + */ + public long updateAccountResourceCount(long accountId, ResourceType type); + + /** + * Updates the resource count of the domain to reflect current usage in the domain + * @param domainId + * @param type + */ + public long updateDomainResourceCount(long domainId, ResourceType type); /** * Increments the resource count * @param accountId diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 9ab15778add..1dfe81564ea 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -47,12 +47,15 @@ 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.UpdateResourceCountCmd; import com.cloud.api.commands.UpdateResourceLimitCmd; import com.cloud.api.commands.UpdateUserCmd; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; -import com.cloud.configuration.ResourceCount.ResourceType; +import com.cloud.configuration.ResourceCount; +import com.cloud.configuration.ResourceCountVO; import com.cloud.configuration.ResourceLimitVO; +import com.cloud.configuration.ResourceCount.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.configuration.dao.ResourceCountDao; import com.cloud.configuration.dao.ResourceLimitDao; @@ -67,6 +70,7 @@ import com.cloud.event.UsageEventVO; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.PermissionDeniedException; @@ -75,6 +79,7 @@ import com.cloud.network.NetworkManager; import com.cloud.network.NetworkVO; import com.cloud.network.RemoteAccessVpnVO; import com.cloud.network.VpnUserVO; +import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.RemoteAccessVpnDao; import com.cloud.network.dao.VpnUserDao; @@ -86,6 +91,7 @@ import com.cloud.storage.StorageManager; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.snapshot.SnapshotManager; @@ -113,6 +119,7 @@ import com.cloud.vm.ReservationContextImpl; import com.cloud.vm.UserVmManager; import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.dao.InstanceGroupDao; import com.cloud.vm.dao.UserVmDao; @@ -151,6 +158,12 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag private SecurityGroupDao _securityGroupDao; @Inject private VMInstanceDao _vmDao; + @Inject + private IPAddressDao _ipAddressDao; + @Inject + protected SnapshotDao _snapshotDao; + @Inject + protected VMTemplateDao _vmTemplateDao; @Inject private SecurityGroupManager _networkGroupMgr; @@ -730,6 +743,130 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag } } + @Override + public long updateAccountResourceCount(long accountId, ResourceType type) { + long count=0; + + // 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); + } catch (Exception e) { + throw new CloudRuntimeException("Failed to update resource count for account with Id" + accountId); + } finally { + m_resourceCountLock.unlock(); + } + } + + return count; + } + + @Override + public long updateDomainResourceCount(long domainId, ResourceType type) { + long count=0; + Domain domain =_domainDao.findById(domainId); + + if (m_resourceCountLock.lock(120)) { // 2 minutes + try { + List domainChildren = _domainDao.findImmediateChildrenForParent(domain.getId()); + // 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 accounts = _accountDao.findActiveAccountsForDomain(domainChild.getId()); + 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(); + } + } + + return count; + } + + @Override + public ResourceCountVO updateResourceCount(UpdateResourceCountCmd cmd) throws InvalidParameterValueException, CloudRuntimeException, PermissionDeniedException{ + Account currentAccount = UserContext.current().getCaller(); + String accountName = cmd.getAccountName(); + Long domainId = cmd.getDomainId(); + Long accountId = null; + long count=0; + + ResourceType resourceType; + Integer type = cmd.getResourceType(); + try { + resourceType = ResourceType.values()[type]; + } catch (ArrayIndexOutOfBoundsException e) { + throw new InvalidParameterValueException("Please specify a valid resource type."); + } + + // Either a domainId or an account name with domainId must be passed in + if ((domainId == null) && (accountName == null)) { + throw new InvalidParameterValueException("Either a domainId or account name with domainId must be passed in."); + } + + if (domainId != null) { + DomainVO domain = _domainDao.findById(domainId); + if (domain == null) { + throw new InvalidParameterValueException("Please specify a valid domain ID."); + } else if (domain.getRemoved() != null) { + throw new InvalidParameterValueException("Please specify an active domain."); + } + checkAccess(currentAccount, domain); + } + + if (accountName != null) { + if (domainId == null) { + throw new InvalidParameterValueException("domainId parameter is required if account name is specified"); + } + Account userAccount = _accountDao.findActiveAccount(accountName, domainId); + if (userAccount == null) { + throw new InvalidParameterValueException("unable to find account by name " + accountName + " in domain with id " + domainId); + } + accountId = userAccount.getId(); + checkAccess(currentAccount, userAccount); + } + + try { + if (accountId != null) { + count = updateAccountResourceCount(accountId, resourceType); + } else { + count = updateDomainResourceCount(domainId, resourceType); + } + } catch (Exception e) { + throw new CloudRuntimeException(e.getMessage()); + } + + return new ResourceCountVO(accountId, domainId, resourceType, count); + } + @Override public AccountVO getSystemAccount() { if (_systemAccount == null) { @@ -1657,6 +1794,14 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag return _userDao.remove(id); } + + public class ResourceCountCalculateTask implements Runnable { + @Override + public void run() { + + } + } + protected class AccountCleanupTask implements Runnable { @Override public void run() { diff --git a/server/src/com/cloud/user/dao/AccountDao.java b/server/src/com/cloud/user/dao/AccountDao.java index 6e2ac0647eb..9969bba19c0 100644 --- a/server/src/com/cloud/user/dao/AccountDao.java +++ b/server/src/com/cloud/user/dao/AccountDao.java @@ -39,6 +39,7 @@ public interface AccountDao extends GenericDao { List findNewAccounts(Long minAccountId, Filter filter); List findCleanups(); List findAdminAccountsForDomain(Long domainId); + List findActiveAccountsForDomain(Long domain); void markForCleanup(long accountId); List listAccounts(String accountName, Long domainId, Filter filter); } diff --git a/server/src/com/cloud/user/dao/AccountDaoImpl.java b/server/src/com/cloud/user/dao/AccountDaoImpl.java index 966c8b0d7ec..b2045ff83c0 100755 --- a/server/src/com/cloud/user/dao/AccountDaoImpl.java +++ b/server/src/com/cloud/user/dao/AccountDaoImpl.java @@ -50,6 +50,7 @@ public class AccountDaoImpl extends GenericDaoBase implements A protected final SearchBuilder AccountNameSearch; protected final SearchBuilder AccountTypeSearch; + protected final SearchBuilder DomainAccountsSearch; protected final SearchBuilder CleanupSearch; @@ -62,6 +63,11 @@ public class AccountDaoImpl extends GenericDaoBase implements A AccountTypeSearch.and("domainId", AccountTypeSearch.entity().getDomainId(), SearchCriteria.Op.EQ); AccountTypeSearch.and("type", AccountTypeSearch.entity().getType(), SearchCriteria.Op.EQ); AccountTypeSearch.done(); + + DomainAccountsSearch = createSearchBuilder(); + DomainAccountsSearch.and("domainId", DomainAccountsSearch.entity().getDomainId(), SearchCriteria.Op.EQ); + DomainAccountsSearch.and("removed", DomainAccountsSearch.entity().getRemoved(), SearchCriteria.Op.NNULL); + DomainAccountsSearch.done(); CleanupSearch = createSearchBuilder(); CleanupSearch.and("cleanup", CleanupSearch.entity().getNeedsCleanup(), SearchCriteria.Op.EQ); @@ -190,6 +196,13 @@ public class AccountDaoImpl extends GenericDaoBase implements A sc.addAnd("type", Op.IN, Account.ACCOUNT_TYPE_ADMIN, Account.ACCOUNT_TYPE_DOMAIN_ADMIN, Account.ACCOUNT_TYPE_READ_ONLY_ADMIN, Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN); return null; } + + @Override + public List findActiveAccountsForDomain(Long domain) { + SearchCriteria sc = DomainAccountsSearch.create(); + sc.addAnd("domainId", Op.EQ, domain); + return listBy(sc); + } @Override public void markForCleanup(long accountId) { diff --git a/server/src/com/cloud/vm/dao/UserVmDao.java b/server/src/com/cloud/vm/dao/UserVmDao.java index c3e6feb8c48..0db42f26458 100755 --- a/server/src/com/cloud/vm/dao/UserVmDao.java +++ b/server/src/com/cloud/vm/dao/UserVmDao.java @@ -66,5 +66,5 @@ public interface UserVmDao extends GenericDao { void saveDetails(UserVmVO vm); List listPodIdsHavingVmsforAccount(long zoneId, long accountId); - + public Long countAllocatedVMsForAccount(long accountId); } diff --git a/server/src/com/cloud/vm/dao/UserVmDaoImpl.java b/server/src/com/cloud/vm/dao/UserVmDaoImpl.java index 9ea3efdaa94..a9d3200073a 100755 --- a/server/src/com/cloud/vm/dao/UserVmDaoImpl.java +++ b/server/src/com/cloud/vm/dao/UserVmDaoImpl.java @@ -41,6 +41,7 @@ import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.NicVO; import com.cloud.vm.UserVmVO; +import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; @Local(value={UserVmDao.class}) @@ -60,6 +61,7 @@ public class UserVmDaoImpl extends GenericDaoBase implements Use protected final SearchBuilder DestroySearch; protected SearchBuilder AccountDataCenterVirtualSearch; protected GenericSearchBuilder CountByAccountPod; + protected GenericSearchBuilder CountByAccount; protected GenericSearchBuilder PodsHavingVmsForAccount; protected SearchBuilder UserVmSearch; @@ -128,6 +130,13 @@ public class UserVmDaoImpl extends GenericDaoBase implements Use CountByAccountPod.and("pod", CountByAccountPod.entity().getPodIdToDeployIn(), SearchCriteria.Op.EQ); CountByAccountPod.done(); + CountByAccount = createSearchBuilder(Long.class); + CountByAccount.select(null, Func.COUNT, null); + CountByAccount.and("account", CountByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); + CountByAccount.and("type", CountByAccount.entity().getType(), SearchCriteria.Op.EQ); + CountByAccount.and("state", CountByAccount.entity().getState(), SearchCriteria.Op.NIN); + CountByAccount.done(); + _updateTimeAttr = _allAttributes.get("updateTime"); assert _updateTimeAttr != null : "Couldn't get this updateTime attribute"; } @@ -297,4 +306,13 @@ public class UserVmDaoImpl extends GenericDaoBase implements Use throw new CloudRuntimeException("Caught: " + LIST_PODS_HAVING_VMS_FOR_ACCOUNT, e); } } + + @Override + public Long countAllocatedVMsForAccount(long accountId) { + SearchCriteria sc = CountByAccount.create(); + sc.setParameters("account", accountId); + sc.setParameters("type", VirtualMachine.Type.User); + sc.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging}); + return customSearch(sc, null).get(0); + } } diff --git a/server/src/com/cloud/vm/dao/VMInstanceDao.java b/server/src/com/cloud/vm/dao/VMInstanceDao.java index 13b0a023137..61c9be500ca 100644 --- a/server/src/com/cloud/vm/dao/VMInstanceDao.java +++ b/server/src/com/cloud/vm/dao/VMInstanceDao.java @@ -79,4 +79,5 @@ public interface VMInstanceDao extends GenericDao, StateDao< List listByTypeAndState(State state, VirtualMachine.Type type); List listByAccountId(long accountId); + public Long countAllocatedVirtualRoutersForAccount(long accountId); } diff --git a/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java b/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java index ba513989ce4..ddfbd4baca8 100644 --- a/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java +++ b/server/src/com/cloud/vm/dao/VMInstanceDaoImpl.java @@ -28,10 +28,13 @@ import org.apache.log4j.Logger; import com.cloud.utils.db.Attribute; import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.GenericSearchBuilder; 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.UpdateBuilder; +import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Event; @@ -54,7 +57,8 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem protected final SearchBuilder HostIdTypesSearch; protected final SearchBuilder HostIdUpTypesSearch; protected final SearchBuilder HostUpSearch; - + protected final GenericSearchBuilder CountVirtualRoutersByAccount; + protected final Attribute _updateTimeAttr; protected VMInstanceDaoImpl() { @@ -119,7 +123,13 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem HostUpSearch.and("states", HostUpSearch.entity().getState(), Op.IN); HostUpSearch.done(); - + CountVirtualRoutersByAccount = createSearchBuilder(Long.class); + CountVirtualRoutersByAccount.select(null, Func.COUNT, null); + CountVirtualRoutersByAccount.and("account", CountVirtualRoutersByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); + CountVirtualRoutersByAccount.and("type", CountVirtualRoutersByAccount.entity().getType(), SearchCriteria.Op.EQ); + CountVirtualRoutersByAccount.and("state", CountVirtualRoutersByAccount.entity().getState(), SearchCriteria.Op.NIN); + CountVirtualRoutersByAccount.done(); + _updateTimeAttr = _allAttributes.get("updateTime"); assert _updateTimeAttr != null : "Couldn't get this updateTime attribute"; } @@ -287,4 +297,13 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem sc.setParameters("state", State.Stopped); return listBy(sc); } + + @Override + public Long countAllocatedVirtualRoutersForAccount(long accountId) { + SearchCriteria sc = CountVirtualRoutersByAccount.create(); + sc.setParameters("account", accountId); + sc.setParameters("type", VirtualMachine.Type.DomainRouter); + sc.setParameters("state", new Object[] {State.Destroyed, State.Error, State.Expunging}); + return customSearch(sc, null).get(0); + } }