diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 0889d5a526f..03b1918312d 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -789,6 +789,7 @@ quotaTariffUpdate=7 quotaRefresh=15 quotaCredits=15 quotaStatement=15 +quotaBalance=15 quotaEmailTemplateUpdate=15 quotaEmailTemplateDelete=15 quotaEmailTemplateAdd=15 diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaBalanceCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaBalanceCmd.java new file mode 100644 index 00000000000..bcc65573a39 --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaBalanceCmd.java @@ -0,0 +1,135 @@ +//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 org.apache.cloudstack.api.command; + +import java.util.Date; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.log4j.Logger; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.AccountResponse; +import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.QuotaBalanceResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.quota.QuotaBalanceVO; +import org.apache.cloudstack.quota.QuotaDBUtils; +import org.apache.cloudstack.quota.QuotaManager; +import org.apache.cloudstack.api.response.QuotaStatementItemResponse; + +import com.cloud.user.Account; + +@APICommand(name = "quotaBalance", responseObject = QuotaStatementItemResponse.class, description = "Create a quota balance statement", since = "4.2.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class QuotaBalanceCmd extends BaseCmd { + + public static final Logger s_logger = Logger.getLogger(QuotaBalanceCmd.class.getName()); + + private static final String s_name = "quotabalanceresponse"; + + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = true, description = "Optional, Account Id for which statement needs to be generated") + private String accountName; + + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class, description = "Optional, If domain Id is given and the caller is domain admin then the statement is generated for domain.") + private Long domainId; + + @Parameter(name = ApiConstants.END_DATE, type = CommandType.DATE, required = true, description = "End date range for quota query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.") + private Date endDate; + + @Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, required = true, description = "Start date range quota query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-01.") + private Date startDate; + + @Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, description = "List usage records for the specified account") + private Long accountId; + + @Inject + QuotaManager _quotaManager; + @Inject + QuotaDBUtils _quotaDBUtils; + + public Long getAccountId() { + return accountId; + } + + public void setAccountId(Long accountId) { + this.accountId = accountId; + } + + public String getAccountName() { + return accountName; + } + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public Long getDomainId() { + return domainId; + } + + public void setDomainId(Long domainId) { + this.domainId = domainId; + } + + public Date getEndDate() { + return endDate; + } + + public void setEndDate(Date endDate) { + this.endDate = endDate; + } + + public Date getStartDate() { + return startDate; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public QuotaBalanceCmd() { + super(); + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + Long accountId = _accountService.finalyzeAccountId(accountName, domainId, null, true); + if (accountId == null) { + return CallContext.current().getCallingAccount().getId(); + } + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute() { + List quotaUsage = _quotaManager.getQuotaBalance(this); + + QuotaBalanceResponse response = _quotaDBUtils.createQuotaBalanceResponse(quotaUsage); + + response.setResponseName(getCommandName()); + setResponseObject(response); + } + +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaStatementCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaStatementCmd.java index 80249948422..5cb9d131bf4 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaStatementCmd.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaStatementCmd.java @@ -36,7 +36,6 @@ import org.apache.cloudstack.quota.QuotaUsageVO; import org.apache.cloudstack.api.response.QuotaStatementItemResponse; import com.cloud.user.Account; -import com.cloud.utils.Pair; @APICommand(name = "quotaStatement", responseObject = QuotaStatementItemResponse.class, description = "Create a quota statement", since = "4.2.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class QuotaStatementCmd extends BaseCmd { @@ -136,9 +135,9 @@ public class QuotaStatementCmd extends BaseCmd { @Override public void execute() { - Pair, Integer> result = _quotaManager.getQuotaUsage(this); + List quotaUsage = _quotaManager.getQuotaUsage(this); - QuotaStatementResponse response = _quotaDBUtils.createQuotaStatementResponse(result.first()); + QuotaStatementResponse response = _quotaDBUtils.createQuotaStatementResponse(quotaUsage); response.setResponseName(getCommandName()); setResponseObject(response); diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementBalanceResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaBalanceResponse.java similarity index 63% rename from plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementBalanceResponse.java rename to plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaBalanceResponse.java index 153ced11f47..86e2b74ff54 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementBalanceResponse.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaBalanceResponse.java @@ -17,15 +17,18 @@ package org.apache.cloudstack.api.response; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import com.google.gson.annotations.SerializedName; import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.quota.QuotaBalanceVO; import com.cloud.serializer.Param; -public class QuotaStatementBalanceResponse extends BaseResponse { +public class QuotaBalanceResponse extends BaseResponse { @SerializedName("accountid") @Param(description = "account id") @@ -39,13 +42,17 @@ public class QuotaStatementBalanceResponse extends BaseResponse { @Param(description = "domain id") private Long domainId; - @SerializedName("usedquota") - @Param(description = "quota consumed") - private BigDecimal quotaUsed; + @SerializedName("startquota") + @Param(description = "quota started with") + private BigDecimal startQuota; - @SerializedName("quotabalance") - @Param(description = "remaining quota") - private BigDecimal quotaBalance; + @SerializedName("endquota") + @Param(description = "quota by end of this period") + private BigDecimal endQuota; + + @SerializedName("credits") + @Param(description = "list of credits made during this period") + private List credits = null; @SerializedName("startdate") @Param(description = "start date") @@ -55,8 +62,9 @@ public class QuotaStatementBalanceResponse extends BaseResponse { @Param(description = "end date") private Date endDate = null; - public QuotaStatementBalanceResponse() { + public QuotaBalanceResponse() { super(); + credits = new ArrayList(); } public Long getAccountId() { @@ -83,20 +91,35 @@ public class QuotaStatementBalanceResponse extends BaseResponse { this.domainId = domainId; } - public BigDecimal getQuotaUsed() { - return quotaUsed; + public BigDecimal getStartQuota() { + return startQuota; } - public void setQuotaUsed(BigDecimal quotaUsed) { - this.quotaUsed = quotaUsed; + public void setStartQuota(BigDecimal startQuota) { + this.startQuota = startQuota; } - public BigDecimal getQuotaBalance() { - return quotaBalance; + public BigDecimal getEndQuota() { + return endQuota; } - public void setQuotaBalance(BigDecimal quotaBalance) { - this.quotaBalance = quotaBalance; + public void setEndQuota(BigDecimal endQuota) { + this.endQuota = endQuota; + } + + public List getCredits() { + return credits; + } + + public void setCredits(List credits) { + this.credits = credits; + } + + public void addCredits(QuotaBalanceVO credit) { + QuotaCreditsResponse cr = new QuotaCreditsResponse(); + cr.setCredits(credit.getCreditBalance()); + cr.setUpdatedOn(credit.getUpdatedOn()); + credits.add(cr); } public Date getStartDate() { @@ -115,5 +138,4 @@ public class QuotaStatementBalanceResponse extends BaseResponse { this.endDate = endDate; } - } diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaCreditsResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaCreditsResponse.java index 6326b764405..1a54d4d78c8 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaCreditsResponse.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaCreditsResponse.java @@ -24,7 +24,7 @@ import org.apache.cloudstack.quota.QuotaCreditsVO; import java.math.BigDecimal; import java.math.RoundingMode; -import java.sql.Timestamp; +import java.util.Date; public class QuotaCreditsResponse extends BaseResponse { @@ -38,7 +38,7 @@ public class QuotaCreditsResponse extends BaseResponse { @SerializedName("updated_on") @Param(description = "the account name of the admin who updated the credits") - private Timestamp updatedOn; + private Date updatedOn; public QuotaCreditsResponse() { super(); @@ -49,7 +49,7 @@ public class QuotaCreditsResponse extends BaseResponse { if (result != null) { this.credits = result.getCredit().setScale(2, RoundingMode.HALF_EVEN); this.updatedBy = updatedBy; - this.updatedOn = new Timestamp(System.currentTimeMillis()); + this.updatedOn = new Date(); } } @@ -69,11 +69,11 @@ public class QuotaCreditsResponse extends BaseResponse { this.updatedBy = updatedBy; } - public Timestamp getUpdatedOn() { + public Date getUpdatedOn() { return updatedOn; } - public void setUpdatedOn(Timestamp updatedOn) { + public void setUpdatedOn(Date updatedOn) { this.updatedOn = updatedOn; } diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementResponse.java index 4abd5df7049..814dfa4e982 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementResponse.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementResponse.java @@ -16,6 +16,7 @@ //under the License. package org.apache.cloudstack.api.response; +import java.math.BigDecimal; import java.util.Date; import java.util.List; @@ -42,6 +43,10 @@ public class QuotaStatementResponse extends BaseResponse { @Param(description = "list of quota usage under variosu types", responseObject = QuotaStatementItemResponse.class) private List lineItem; + @SerializedName("totalquota") + @Param(description = "total quota used during this period") + private BigDecimal totalQuota; + @SerializedName("startdate") @Param(description = "start date") private Date startDate = null; @@ -50,10 +55,6 @@ public class QuotaStatementResponse extends BaseResponse { @Param(description = "end date") private Date endDate = null; - @SerializedName("balance") - @Param(description = "The balance of quota reamining", responseObject = QuotaStatementBalanceResponse.class) - private QuotaStatementBalanceResponse balance; - public QuotaStatementResponse() { super(); } @@ -106,12 +107,12 @@ public class QuotaStatementResponse extends BaseResponse { this.endDate = endDate; } - public QuotaStatementBalanceResponse getBalance() { - return balance; + + public BigDecimal getTotalQuota() { + return totalQuota; } - public void setBalance(QuotaStatementBalanceResponse balance) { - this.balance = balance; + public void setTotalQuota(BigDecimal totalQuota) { + this.totalQuota = totalQuota; } - } diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaBalanceVO.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaBalanceVO.java index e1ae45fcc62..b58a7fc529f 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaBalanceVO.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaBalanceVO.java @@ -79,6 +79,7 @@ public class QuotaBalanceVO implements InternalIdentity { this.accountId = accountId; this.domainId = domainId; this.creditBalance = creditBalance; + this.creditsId=0L; this.updatedOn = updatedOn; this.previousUpdateId = previousUpdateId; this.previousUpdateOn = previousUpdateOn; diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtils.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtils.java index 51dc974449c..7aaa52b424e 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtils.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtils.java @@ -22,6 +22,7 @@ import com.cloud.service.ServiceOfferingVO; import org.apache.cloudstack.api.command.QuotaTariffListCmd; import org.apache.cloudstack.api.command.QuotaTariffUpdateCmd; +import org.apache.cloudstack.api.response.QuotaBalanceResponse; import org.apache.cloudstack.api.response.QuotaCreditsResponse; import org.apache.cloudstack.api.response.QuotaStatementResponse; import org.apache.cloudstack.api.response.QuotaTariffResponse; @@ -38,6 +39,8 @@ public interface QuotaDBUtils { QuotaStatementResponse createQuotaStatementResponse(List quotaUsage); + QuotaBalanceResponse createQuotaBalanceResponse(List quotaUsage); + Pair, Integer> getUsageRecords(long accountId, long domainId); ServiceOfferingVO findServiceOffering(Long vmId, long serviceOfferingId); diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtilsImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtilsImpl.java index 72ad98448be..7e6e1cd5788 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtilsImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtilsImpl.java @@ -27,15 +27,15 @@ import com.cloud.utils.Pair; import com.cloud.utils.db.Filter; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.TransactionLegacy; +import com.cloud.utils.exception.CloudRuntimeException; import org.apache.cloudstack.api.command.QuotaTariffListCmd; import org.apache.cloudstack.api.command.QuotaTariffUpdateCmd; import org.apache.cloudstack.api.response.QuotaTariffResponse; import org.apache.cloudstack.api.response.QuotaCreditsResponse; -import org.apache.cloudstack.api.response.QuotaStatementBalanceResponse; +import org.apache.cloudstack.api.response.QuotaBalanceResponse; import org.apache.cloudstack.api.response.QuotaStatementItemResponse; import org.apache.cloudstack.api.response.QuotaStatementResponse; -import org.apache.cloudstack.quota.dao.QuotaBalanceDao; import org.apache.cloudstack.quota.dao.QuotaCreditsDao; import org.apache.cloudstack.quota.dao.QuotaTariffDao; import org.apache.log4j.Logger; @@ -50,6 +50,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; +import java.util.Iterator; import java.util.List; @Component @@ -63,8 +64,6 @@ public class QuotaDBUtilsImpl implements QuotaDBUtils { @Inject private QuotaCreditsDao _quotaCreditsDao; @Inject - private QuotaBalanceDao _quotaBalanceDao; - @Inject private ServiceOfferingDao _serviceOfferingDao; @Inject private UserDao _userDao; @@ -86,6 +85,38 @@ public class QuotaDBUtilsImpl implements QuotaDBUtils { return response; } + @Override + public QuotaBalanceResponse createQuotaBalanceResponse(List quotaBalance) { + Collections.sort(quotaBalance, new Comparator() { + public int compare(QuotaBalanceVO o1, QuotaBalanceVO o2) { + return o1.getUpdatedOn().compareTo(o2.getUpdatedOn()); + } + }); + QuotaBalanceResponse resp = new QuotaBalanceResponse(); + + for (Iterator it = quotaBalance.iterator(); it.hasNext();) { + QuotaBalanceVO entry = it.next(); + if (entry.getCreditsId() > 0) { + resp.addCredits(entry); + it.remove(); + } + } + + if (quotaBalance.size() > 0) { + QuotaBalanceVO startItem = quotaBalance.get(0); + QuotaBalanceVO endItem = quotaBalance.get(quotaBalance.size() - 1); + resp.setStartDate(startItem.getUpdatedOn()); + resp.setStartQuota(startItem.getCreditBalance()); + resp.setEndDate(endItem.getUpdatedOn()); + resp.setEndQuota(endItem.getCreditBalance()); + } else { + new CloudRuntimeException("The request period is small and does not contain balance entries to provide any meaningful values."); + } + + resp.setObjectName("balance"); + return resp; + } + @Override public QuotaStatementResponse createQuotaStatementResponse(List quotaUsage) { QuotaStatementResponse statement = new QuotaStatementResponse(); @@ -109,7 +140,7 @@ public class QuotaDBUtilsImpl implements QuotaDBUtils { int type = -1; BigDecimal usage = new BigDecimal(0); BigDecimal totalUsage = new BigDecimal(0); - quotaUsage.add(new QuotaUsageVO());// boundry + quotaUsage.add(new QuotaUsageVO());// boundary QuotaUsageVO prev = quotaUsage.get(0); for (final QuotaUsageVO quotaRecord : quotaUsage) { if (type != quotaRecord.getUsageType()) { @@ -135,12 +166,8 @@ public class QuotaDBUtilsImpl implements QuotaDBUtils { } statement.setLineItem(items); - // calculate total quota used and balance - QuotaStatementBalanceResponse balance = new QuotaStatementBalanceResponse(); - balance.setObjectName("balance"); - balance.setQuotaUsed(totalUsage); - - statement.setBalance(balance); + statement.setTotalQuota(totalUsage); + statement.setObjectName("statement"); TransactionLegacy.open(TransactionLegacy.CLOUD_DB).close(); return statement; } diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManager.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManager.java index 4d5edf03408..11ab126ed59 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManager.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManager.java @@ -16,8 +16,9 @@ //under the License. package org.apache.cloudstack.quota; -import com.cloud.utils.Pair; import com.cloud.utils.component.PluggableService; + +import org.apache.cloudstack.api.command.QuotaBalanceCmd; import org.apache.cloudstack.api.command.QuotaStatementCmd; import java.util.List; @@ -26,6 +27,8 @@ public interface QuotaManager extends PluggableService { public boolean calculateQuotaUsage(); - public Pair,Integer> getQuotaUsage(QuotaStatementCmd cmd); + public List getQuotaUsage(QuotaStatementCmd cmd); + + List getQuotaBalance(QuotaBalanceCmd cmd); } diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java index 4915a2bf874..da478ae4f1c 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java @@ -24,15 +24,15 @@ import com.cloud.service.ServiceOfferingVO; import com.cloud.usage.UsageVO; import com.cloud.usage.dao.UsageDao; import com.cloud.user.Account; -import com.cloud.user.AccountService; import com.cloud.user.AccountVO; import com.cloud.user.dao.AccountDao; import com.cloud.utils.Pair; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; -import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.TransactionLegacy; + +import org.apache.cloudstack.api.command.QuotaBalanceCmd; import org.apache.cloudstack.api.command.QuotaCreditsCmd; import org.apache.cloudstack.api.command.QuotaEmailTemplateAddCmd; import org.apache.cloudstack.api.command.QuotaRefreshCmd; @@ -44,6 +44,7 @@ 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.quota.dao.QuotaTariffDao; +import org.apache.cloudstack.quota.dao.QuotaBalanceDao; import org.apache.cloudstack.quota.dao.QuotaUsageDao; import org.apache.cloudstack.utils.usage.UsageUtils; import org.apache.log4j.Logger; @@ -52,6 +53,7 @@ import org.springframework.stereotype.Component; import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; + import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; @@ -80,9 +82,9 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi @Inject private ConfigurationDao _configDao; @Inject - private AccountService _accountService; - @Inject private QuotaDBUtils _quotaDBUtils; + @Inject + private QuotaBalanceDao _quotaBalanceDao; private TimeZone _usageTimezone; private int _aggregationDuration = 0; @@ -123,6 +125,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi cmdList.add(QuotaEmailTemplateAddCmd.class); cmdList.add(QuotaRefreshCmd.class); cmdList.add(QuotaStatementCmd.class); + cmdList.add(QuotaBalanceCmd.class); return cmdList; } @@ -202,10 +205,10 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi quotalistforaccount.add(updateQuotaRaw(usageRecord, quotaTariffMap, aggregationRatio, QuotaTypes.VPN_USERS)); break; case QuotaTypes.NETWORK_BYTES_RECEIVED: - quotalistforaccount.add(updateQuotaRaw(usageRecord, quotaTariffMap, aggregationRatio, QuotaTypes.NETWORK_BYTES_RECEIVED)); + quotalistforaccount.add(updateQuotaNetwork(usageRecord, quotaTariffMap, QuotaTypes.NETWORK_BYTES_RECEIVED)); break; case QuotaTypes.NETWORK_BYTES_SENT: - quotalistforaccount.add(updateQuotaRaw(usageRecord, quotaTariffMap, aggregationRatio, QuotaTypes.NETWORK_BYTES_SENT)); + quotalistforaccount.add(updateQuotaNetwork(usageRecord, quotaTariffMap, QuotaTypes.NETWORK_BYTES_SENT)); break; case QuotaTypes.VM_DISK_IO_READ: case QuotaTypes.VM_DISK_IO_WRITE: @@ -218,19 +221,33 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi } while ((usageRecords != null) && !usageRecords.first().isEmpty()); // list of quotas for this account s_logger.info("Quota entries size = " + quotalistforaccount.size()); - Date startDate = new Date(); - Date endDate = new Date(); - int count = 0; + quotalistforaccount.add(new QuotaUsageVO()); + Date startDate = new Date(0); + Date endDate = new Date(0); BigDecimal aggrUsage = new BigDecimal(0); for (QuotaUsageVO entry : quotalistforaccount) { if (startDate.compareTo(entry.getStartDate()) != 0) { - startDate = entry.getStartDate(); - endDate = entry.getEndDate(); - s_logger.info("Start Date=" + startDate.toString() + " to endDate=" + endDate.toString() + "record count=" + count); - aggrUsage = aggrUsage.add(entry.getQuotaUsed()); - count = 0; + QuotaBalanceVO lastrealbalanceentry = _quotaBalanceDao.getLastBalanceEntry(account.getAccountId(), account.getDomainId(), startDate); + Date lastbalancedate; + if (lastrealbalanceentry != null) { + lastbalancedate = lastrealbalanceentry.getUpdatedOn(); + aggrUsage = aggrUsage.add(lastrealbalanceentry.getCreditBalance()); + } else { + lastbalancedate = new Date(0); + } + + List creditsrcvd = _quotaBalanceDao.getCreditBalance(account.getAccountId(), account.getDomainId(), lastbalancedate, endDate); + for (QuotaBalanceVO credit : creditsrcvd) { + aggrUsage = aggrUsage.add(credit.getCreditBalance()); + } + + QuotaBalanceVO newbalance = new QuotaBalanceVO(account.getAccountId(), account.getDomainId(), aggrUsage, endDate, null, null); + _quotaBalanceDao.persist(newbalance); + aggrUsage = new BigDecimal(0); } - count++; + startDate = entry.getStartDate(); + endDate = entry.getEndDate(); + aggrUsage = aggrUsage.subtract(entry.getQuotaUsed()); } } // END ACCOUNT jobResult = true; @@ -243,9 +260,47 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi return jobResult; } - @SuppressWarnings("deprecation") @Override - public Pair, Integer> getQuotaUsage(QuotaStatementCmd cmd) { + public List getQuotaBalance(QuotaBalanceCmd cmd) { + Long accountId = cmd.getAccountId(); + String accountName = cmd.getAccountName(); + Long domainId = cmd.getDomainId(); + Account userAccount = null; + Account caller = CallContext.current().getCallingAccount(); + + // if accountId is not specified, use accountName and domainId + if ((accountId == null) && (accountName != null) && (domainId != null)) { + if (_domainDao.isChildDomain(caller.getDomainId(), domainId)) { + Filter filter = new Filter(AccountVO.class, "id", Boolean.FALSE, null, null); + List accounts = _accountDao.listAccounts(accountName, domainId, filter); + if (accounts.size() > 0) { + userAccount = accounts.get(0); + } + if (userAccount != null) { + accountId = userAccount.getId(); + } else { + throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId); + } + } else { + throw new PermissionDeniedException("Invalid Domain Id or Account"); + } + } + + Date startDate = cmd.getStartDate(); + Date endDate = cmd.getEndDate(); + if (startDate.after(endDate)) { + throw new InvalidParameterValueException("Incorrect Date Range. Start date: " + startDate + " is after end date:" + endDate); + } + TimeZone usageTZ = getUsageTimezone(); + Date adjustedStartDate = computeAdjustedTime(startDate, usageTZ); + Date adjustedEndDate = computeAdjustedTime(endDate, usageTZ); + + s_logger.debug("getting quota balance records for account: " + accountId + ", domainId: " + domainId + ", between " + adjustedStartDate + " and " + adjustedEndDate); + return _quotaBalanceDao.getQuotaBalance(accountId, domainId, adjustedStartDate, adjustedEndDate); + } + + @Override + public List getQuotaUsage(QuotaStatementCmd cmd) { Long accountId = cmd.getAccountId(); String accountName = cmd.getAccountName(); Long domainId = cmd.getDomainId(); @@ -271,26 +326,6 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi } } - boolean isAdmin = false; - boolean isDomainAdmin = false; - - // If accountId couldn't be found using accountName and domainId, get it - // from userContext - if (accountId == null) { - accountId = caller.getId(); - // List records for all the accounts if the caller account is of - // type admin. - // If account_id or account_name is explicitly mentioned, list - // records for the specified account only even if the caller is of - // type admin - if (_accountService.isRootAdmin(caller.getId())) { - isAdmin = true; - } else if (_accountService.isDomainAdmin(caller.getId())) { - isDomainAdmin = true; - } - s_logger.debug("Account details not available. Using userContext accountId: " + accountId); - } - Date startDate = cmd.getStartDate(); Date endDate = cmd.getEndDate(); if (startDate.after(endDate)) { @@ -301,52 +336,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi Date adjustedEndDate = computeAdjustedTime(endDate, usageTZ); s_logger.debug("getting quota records for account: " + accountId + ", domainId: " + domainId + ", between " + adjustedStartDate + " and " + adjustedEndDate); - - TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); - Pair, Integer> quotaUsageRecords = null; - try { - // TODO instead of max value query with reasonable number and - // iterate - Filter usageFilter = new Filter(QuotaUsageVO.class, "id", true, 0L, Long.MAX_VALUE); - SearchCriteria sc = _quotaUsageDao.createSearchCriteria(); - if (accountId != null) { - sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); - s_logger.debug("Account ID=" + accountId); - } - /* - * if (isDomainAdmin) { SearchCriteria sdc = - * _domainDao.createSearchCriteria(); sdc.addOr("path", - * SearchCriteria.Op.LIKE, - * _domainDao.findById(caller.getDomainId()).getPath() + "%"); - * List domains = _domainDao.search(sdc, null); List - * domainIds = new ArrayList(); for (DomainVO domain : - * domains) domainIds.add(domain.getId()); sc.addAnd("domainId", - * SearchCriteria.Op.IN, domainIds.toArray()); - * s_logger.debug("Account ID=" + accountId); } - */ - if (domainId != null) { - sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); - s_logger.debug("Domain ID=" + domainId); - } - if (usageType != null) { - sc.addAnd("usageType", SearchCriteria.Op.EQ, usageType); - s_logger.debug("usageType ID=" + usageType); - } - if ((adjustedStartDate != null) && (adjustedEndDate != null) && adjustedStartDate.before(adjustedEndDate)) { - sc.addAnd("startDate", SearchCriteria.Op.BETWEEN, adjustedStartDate, adjustedEndDate); - sc.addAnd("endDate", SearchCriteria.Op.BETWEEN, adjustedStartDate, adjustedEndDate); - s_logger.debug("start Date=" + adjustedStartDate + ", enddate=" + adjustedEndDate); - } else { - s_logger.debug("Screwed up start Date=" + adjustedStartDate + ", enddate=" + adjustedEndDate); - return new Pair, Integer>(new ArrayList(), new Integer(0)); - } - quotaUsageRecords = _quotaUsageDao.searchAndCountAllRecords(sc, usageFilter); - } finally { - txn.close(); - } - - TransactionLegacy.open(TransactionLegacy.CLOUD_DB).close(); - return quotaUsageRecords; + return _quotaUsageDao.getQuotaUsage(accountId, domainId, usageType, adjustedStartDate, adjustedEndDate); } @DB diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaUsageVO.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaUsageVO.java index c472dac39ef..d51010a161d 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaUsageVO.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaUsageVO.java @@ -67,6 +67,7 @@ public class QuotaUsageVO implements InternalIdentity { public QuotaUsageVO() { usageType=-1; quotaUsed = new BigDecimal(0); + endDate = startDate = new Date(); } public QuotaUsageVO(Long usageItemId, Long zoneId, Long accountId, Long domainId, int usageType, BigDecimal quotaUsed, Date startDate, Date endDate) { diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDao.java b/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDao.java index afc26cbf39c..eb511129e0b 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDao.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDao.java @@ -16,19 +16,21 @@ //under the License. package org.apache.cloudstack.quota.dao; +import java.util.Date; import java.util.List; import org.apache.cloudstack.quota.QuotaBalanceVO; -import com.cloud.utils.Pair; -import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDao; -import com.cloud.utils.db.SearchCriteria; public interface QuotaBalanceDao extends GenericDao { - Pair, Integer> searchBalance(SearchCriteria sc, Filter filter); - void saveQuotaBalance(List credits); + List getCreditBalance(long accountId, long domainId, Date startDate, Date endDate); + + QuotaBalanceVO getLastBalanceEntry(long accountId, long domainId, Date beforeThis); + + List getQuotaBalance(Long accountId, Long domainId, Date startDate, Date endDate); + } diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java index 48322f55236..18183d2fb0a 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java @@ -16,6 +16,8 @@ //under the License. package org.apache.cloudstack.quota.dao; +import java.util.ArrayList; +import java.util.Date; import java.util.List; import javax.ejb.Local; @@ -23,25 +25,90 @@ import javax.ejb.Local; import org.springframework.stereotype.Component; import org.apache.cloudstack.quota.QuotaBalanceVO; -import com.cloud.utils.Pair; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.TransactionLegacy; @Component @Local(value = { QuotaBalanceDao.class }) public class QuotaBalanceDaoImpl extends GenericDaoBase implements QuotaBalanceDao { + @SuppressWarnings("deprecation") @Override - public Pair, Integer> searchBalance(SearchCriteria sc, Filter filter) { - // TODO Auto-generated method stub - return null; + public QuotaBalanceVO getLastBalanceEntry(long accountId, long domainId, Date beforeThis) { + Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", false, 0L, 1L); + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + sc.addAnd("creditsId", SearchCriteria.Op.EQ, 0); + sc.addAnd("updatedOn", SearchCriteria.Op.LT, beforeThis); + List quotab = this.search(sc, filter); + return quotab.size() > 0 ? quotab.get(0) : null; } @Override public void saveQuotaBalance(List credits) { - // TODO Auto-generated method stub - + for (QuotaBalanceVO credit : credits) { + persist(credit); + } } + @SuppressWarnings("deprecation") + @Override + public List getCreditBalance(long accountId, long domainId, Date lastbalancedate, Date beforeThis) { + Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", true, 0L, Long.MAX_VALUE); + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + sc.addAnd("creditsId", SearchCriteria.Op.GT, 0); + if ((lastbalancedate != null) && (beforeThis != null) && lastbalancedate.before(beforeThis)) { + sc.addAnd("updatedOn", SearchCriteria.Op.BETWEEN, lastbalancedate, beforeThis); + } else { + return new ArrayList(); + } + return search(sc, filter); + } + + + @SuppressWarnings("deprecation") + @Override + public List getQuotaBalance(Long accountId, Long domainId, Date startDate, Date endDate) { + + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); + List quotaUsageRecords = null; + try { + // TODO instead of max value query with reasonable number and + // iterate + SearchCriteria sc = createSearchCriteria(); + if (accountId != null) { + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + } + /* + * if (isDomainAdmin) { SearchCriteria sdc = + * _domainDao.createSearchCriteria(); sdc.addOr("path", + * SearchCriteria.Op.LIKE, + * _domainDao.findById(caller.getDomainId()).getPath() + "%"); + * List domains = _domainDao.search(sdc, null); List + * domainIds = new ArrayList(); for (DomainVO domain : + * domains) domainIds.add(domain.getId()); sc.addAnd("domainId", + * SearchCriteria.Op.IN, domainIds.toArray()); + * s_logger.debug("Account ID=" + accountId); } + */ + if (domainId != null) { + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + } + if ((startDate != null) && (endDate != null) && startDate.before(endDate)) { + sc.addAnd("updatedOn", SearchCriteria.Op.BETWEEN, startDate, endDate); + } else { + return new ArrayList(); + } + quotaUsageRecords = listBy(sc); + } finally { + txn.close(); + } + + TransactionLegacy.open(TransactionLegacy.CLOUD_DB).close(); + return quotaUsageRecords; + } } diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDaoImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDaoImpl.java index 24fbbf30440..7e9a024dc57 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDaoImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDaoImpl.java @@ -27,6 +27,7 @@ import org.springframework.stereotype.Component; import org.apache.cloudstack.quota.QuotaBalanceVO; import org.apache.cloudstack.quota.QuotaCreditsVO; +import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchCriteria; @@ -39,14 +40,16 @@ public class QuotaCreditsDaoImpl extends GenericDaoBase im @SuppressWarnings("deprecation") @Override public List getCredits(long accountId, long domainId, Date startDate, Date endDate) { + Filter filter = new Filter(QuotaCreditsVO.class, "updatedOn", true, 0L, Long.MAX_VALUE); SearchCriteria sc = createSearchCriteria(); + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); if ((startDate != null) && (endDate != null) && startDate.before(endDate)) { - sc.addAnd("startDate", SearchCriteria.Op.BETWEEN, startDate, endDate); - sc.addAnd("endDate", SearchCriteria.Op.BETWEEN, startDate, endDate); + sc.addAnd("updatedOn", SearchCriteria.Op.BETWEEN, startDate, endDate); } else { return new ArrayList(); } - return listBy(sc); + return this.search(sc, filter); } @Override diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDao.java b/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDao.java index 602a4cdf57e..6669f37552e 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDao.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDao.java @@ -16,6 +16,7 @@ //under the License. package org.apache.cloudstack.quota.dao; +import java.util.Date; import java.util.List; import org.apache.cloudstack.quota.QuotaUsageVO; @@ -27,6 +28,8 @@ import com.cloud.utils.db.SearchCriteria; public interface QuotaUsageDao extends GenericDao { + List getQuotaUsage(Long accountId, Long domainId, Integer usageType, Date startDate, Date endDate); + Pair, Integer> searchAndCountAllRecords(SearchCriteria sc, Filter filter); void saveQuotaUsage(List credits); diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDaoImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDaoImpl.java index df69cef0afc..d5cd20af736 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDaoImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDaoImpl.java @@ -16,15 +16,20 @@ //under the License. package org.apache.cloudstack.quota.dao; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.ejb.Local; + +import org.springframework.stereotype.Component; +import org.apache.cloudstack.quota.QuotaUsageVO; + import com.cloud.utils.Pair; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchCriteria; -import org.apache.cloudstack.quota.QuotaUsageVO; -import org.springframework.stereotype.Component; - -import javax.ejb.Local; -import java.util.List; +import com.cloud.utils.db.TransactionLegacy; @Component @Local(value = { QuotaUsageDao.class }) @@ -42,4 +47,49 @@ public class QuotaUsageDaoImpl extends GenericDaoBase implem } } + @SuppressWarnings("deprecation") + @Override + public List getQuotaUsage(Long accountId, Long domainId, Integer usageType, Date startDate, Date endDate) { + + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); + List quotaUsageRecords = null; + try { + // TODO instead of max value query with reasonable number and + // iterate + SearchCriteria sc = createSearchCriteria(); + if (accountId != null) { + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + } + /* + * if (isDomainAdmin) { SearchCriteria sdc = + * _domainDao.createSearchCriteria(); sdc.addOr("path", + * SearchCriteria.Op.LIKE, + * _domainDao.findById(caller.getDomainId()).getPath() + "%"); + * List domains = _domainDao.search(sdc, null); List + * domainIds = new ArrayList(); for (DomainVO domain : + * domains) domainIds.add(domain.getId()); sc.addAnd("domainId", + * SearchCriteria.Op.IN, domainIds.toArray()); + * s_logger.debug("Account ID=" + accountId); } + */ + if (domainId != null) { + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + } + if (usageType != null) { + sc.addAnd("usageType", SearchCriteria.Op.EQ, usageType); + } + if ((startDate != null) && (endDate != null) && startDate.before(endDate)) { + sc.addAnd("startDate", SearchCriteria.Op.BETWEEN, startDate, endDate); + sc.addAnd("endDate", SearchCriteria.Op.BETWEEN, startDate, endDate); + } else { + return new ArrayList(); + } + quotaUsageRecords = listBy(sc); + } finally { + txn.close(); + } + + TransactionLegacy.open(TransactionLegacy.CLOUD_DB).close(); + return quotaUsageRecords; + } + }