From ae0eb6e334dfa0cebc6c1d8c529ee6643b1491fe Mon Sep 17 00:00:00 2001 From: Abhinandan Prateek Date: Tue, 14 Jul 2015 11:15:55 +0530 Subject: [PATCH] CLOUDSTACK-8592: first cut implementation of quota statement --- .../api/command/QuotaStatementCmd.java | 96 +++++- .../api/response/QuotaStatementResponse.java | 82 +++-- .../apache/cloudstack/quota/QuotaDBUtils.java | 7 +- .../cloudstack/quota/QuotaDBUtilsImpl.java | 55 +++- .../apache/cloudstack/quota/QuotaManager.java | 8 + .../cloudstack/quota/QuotaManagerImpl.java | 297 ++++++++++++++---- .../cloudstack/quota/QuotaMappingVO.java | 5 +- .../apache/cloudstack/quota/QuotaUsageVO.java | 38 ++- .../quota/dao/QuotaUsageDaoImpl.java | 10 +- setup/db/db/schema-451to452.sql | 68 ++-- 10 files changed, 500 insertions(+), 166 deletions(-) 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 723080474fa..e97846a0db7 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 @@ -16,17 +16,27 @@ //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.BaseListCmd; 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.ListResponse; import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.quota.QuotaDBUtils; +import org.apache.cloudstack.quota.QuotaManager; +import org.apache.cloudstack.quota.QuotaUsageVO; import org.apache.cloudstack.api.response.QuotaStatementResponse; import com.cloud.user.Account; +import com.cloud.utils.Pair; @APICommand(name = "quotaStatement", responseObject = QuotaStatementResponse.class, description = "Create a quota statement", since = "4.2.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class QuotaStatementCmd extends BaseListCmd { @@ -35,12 +45,77 @@ public class QuotaStatementCmd extends BaseListCmd { private static final String s_name = "quotastatementresponse"; - @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required=true, description = "Optional, Account Id for which statement needs to be generated") + @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.") + @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.TYPE, type = CommandType.INTEGER, description = "List quota usage records for the specified usage type") + private Integer usageType; + + @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 Integer getUsageType() { + return usageType; + } + + public void setUsageType(Integer usageType) { + this.usageType = usageType; + } + + 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 QuotaStatementCmd() { super(); } @@ -61,21 +136,12 @@ public class QuotaStatementCmd extends BaseListCmd { @Override public void execute() { - /** - * final Pair, Integer> result = - * _quotaManager.listConfigurations(this); - * - * final List responses = new - * ArrayList(); for (final QuotaConfigurationVO - * resource : result.first()) { final QuotaStatementResponse - * configurationResponse = - * _quotaManager.createQuotaConfigurationResponse(resource); - * configurationResponse.setObjectName("QuotaConfiguration"); - * responses.add(configurationResponse); } - **/ + Pair, Integer> result = _quotaManager.getQuotaUsage(this); + + List responses = _quotaDBUtils.createQuotaStatementResponse(result.first()); final ListResponse response = new ListResponse(); - // response.setResponses(responses, responses.size()); + response.setResponses(responses, responses.size()); response.setResponseName(getCommandName()); setResponseObject(response); } 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 7f48f6c2996..78696feebe8 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,9 @@ //under the License. package org.apache.cloudstack.api.response; +import java.math.BigDecimal; +import java.util.Date; + import com.google.gson.annotations.SerializedName; import org.apache.cloudstack.api.BaseResponse; @@ -24,85 +27,80 @@ import com.cloud.serializer.Param; public class QuotaStatementResponse extends BaseResponse { - @SerializedName("usageType") - @Param(description = "usageType") - private String usageType; + @SerializedName("type") + @Param(description = "usage type") + private int usageType; - @SerializedName("usageUnit") - @Param(description = "usageUnit") + @SerializedName("unit") + @Param(description = "usage unit") private String usageUnit; - @SerializedName("usageDiscriminator") - @Param(description = "usageDiscriminator") - private String usageDiscriminator; + @SerializedName("quota") + @Param(description = "quota consumed") + private BigDecimal quotaUsed; - @SerializedName("currencyValue") - @Param(description = "currencyValue") - private int currencyValue; + @SerializedName("startdate") + @Param(description = "start date") + private Date startDate = null; - @SerializedName("include") - @Param(description = "include") - private int include; + @SerializedName("enddate") + @Param(description = "end date") + private Date endDate = null; - @SerializedName("description") - @Param(description = "description") - private String description; public QuotaStatementResponse() { super(); } - public QuotaStatementResponse(final String usageType) { - super(); - this.usageType = usageType; - } - public String getUsageType() { + public int getUsageType() { return usageType; } - public void setUsageType(String usageType) { + + public void setUsageType(int usageType) { this.usageType = usageType; } + public String getUsageUnit() { return usageUnit; } + public void setUsageUnit(String usageUnit) { this.usageUnit = usageUnit; } - public String getUsageDiscriminator() { - return usageDiscriminator; + + public BigDecimal getQuotaUsed() { + return quotaUsed; } - public void setUsageDiscriminator(String usageDiscriminator) { - this.usageDiscriminator = usageDiscriminator; + + public void setQuotaUsed(BigDecimal quotaUsed) { + this.quotaUsed = quotaUsed; } - public int getCurrencyValue() { - return currencyValue; + + public Date getStartDate() { + return startDate; } - public void setCurrencyValue(int currencyValue) { - this.currencyValue = currencyValue; + + public void setStartDate(Date startDate) { + this.startDate = startDate; } - public int getInclude() { - return include; + + public Date getEndDate() { + return endDate; } - public void setInclude(int include) { - this.include = include; + + public void setEndDate(Date endDate) { + this.endDate = endDate; } - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } } 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 551dc94eef5..e68d431c118 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtils.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtils.java @@ -22,11 +22,11 @@ import org.apache.cloudstack.api.command.QuotaEditMappingCmd; import org.apache.cloudstack.api.command.QuotaMapping; import org.apache.cloudstack.api.response.QuotaConfigurationResponse; import org.apache.cloudstack.api.response.QuotaCreditsResponse; +import org.apache.cloudstack.api.response.QuotaStatementResponse; import com.cloud.utils.Pair; -import com.cloud.utils.component.PluggableService; -public interface QuotaDBUtils extends PluggableService { +public interface QuotaDBUtils { Pair, Integer> editQuotaMapping(QuotaEditMappingCmd cmd); @@ -34,7 +34,8 @@ public interface QuotaDBUtils extends PluggableService { QuotaConfigurationResponse createQuotaConfigurationResponse(QuotaMappingVO configuration); + List createQuotaStatementResponse(List quotaUsage); + QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Integer amount, Long updatedBy); - } 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 8d0f5adef67..2e63621f9ac 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtilsImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaDBUtilsImpl.java @@ -17,7 +17,11 @@ package org.apache.cloudstack.quota; import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.Date; +import java.util.HashMap; import java.util.List; import javax.ejb.Local; @@ -27,6 +31,7 @@ import org.apache.cloudstack.api.command.QuotaEditMappingCmd; import org.apache.cloudstack.api.command.QuotaMapping; import org.apache.cloudstack.api.response.QuotaConfigurationResponse; import org.apache.cloudstack.api.response.QuotaCreditsResponse; +import org.apache.cloudstack.api.response.QuotaStatementResponse; import org.apache.cloudstack.quota.dao.QuotaMappingDao; import org.apache.cloudstack.quota.dao.QuotaCreditsDao; import org.apache.log4j.Logger; @@ -38,7 +43,7 @@ import com.cloud.utils.db.TransactionLegacy; @Component @Local(value = QuotaDBUtilsImpl.class) -public class QuotaDBUtilsImpl { +public class QuotaDBUtilsImpl implements QuotaDBUtils { private static final Logger s_logger = Logger.getLogger(QuotaDBUtilsImpl.class.getName()); @Inject @@ -47,8 +52,8 @@ public class QuotaDBUtilsImpl { @Inject private QuotaCreditsDao _quotaCreditsDao; - - public QuotaConfigurationResponse createQuotaConfigurationResponse(final QuotaMappingVO configuration) { + @Override + public QuotaConfigurationResponse createQuotaConfigurationResponse(QuotaMappingVO configuration) { final QuotaConfigurationResponse response = new QuotaConfigurationResponse(); response.setUsageType(configuration.getUsageType()); response.setUsageName(configuration.getUsageName()); @@ -60,12 +65,54 @@ public class QuotaDBUtilsImpl { return response; } + @Override + public List createQuotaStatementResponse(List quotaUsage) { + TransactionLegacy.open(TransactionLegacy.USAGE_DB); + Collections.sort(quotaUsage, new Comparator() { + public int compare(QuotaUsageVO o1, QuotaUsageVO o2) { + if (o1.getUsageType() == o2.getUsageType()) + return 0; + return o1.getUsageType() < o2.getUsageType() ? -1 : 1; + } + }); + + HashMap map = new HashMap(); + List result = _quotaMappingDao.listAll(); + for (QuotaMappingVO mapping : result) { + map.put(mapping.getUsageType(), mapping.getUsageUnit()); + } + + List statement = new ArrayList(); + QuotaStatementResponse lineitem; + int type = -1; + BigDecimal totalUsage = new BigDecimal(0); + for (final QuotaUsageVO quotaRecord : quotaUsage) { + if (type != quotaRecord.getUsageType()) { + if (type != -1) { + lineitem = new QuotaStatementResponse(); + lineitem.setUsageType(type); + lineitem.setQuotaUsed(totalUsage); + lineitem.setUsageUnit(map.get(type)); + statement.add(lineitem); + totalUsage = new BigDecimal(0); + } + type = quotaRecord.getUsageType(); + } + totalUsage = totalUsage.add(quotaRecord.getQuotaUsed()); + } + + TransactionLegacy.open(TransactionLegacy.CLOUD_DB); + return statement; + } + + @Override public Pair, Integer> listConfigurations(final QuotaMapping cmd) { final Pair, Integer> result = _quotaMappingDao.listAllMapping(); TransactionLegacy.open(TransactionLegacy.CLOUD_DB); return result; } + @Override public Pair, Integer> editQuotaMapping(QuotaEditMappingCmd cmd) { int resourceType = cmd.getUsageType(); BigDecimal quotaCost = new BigDecimal(cmd.getValue()); @@ -86,6 +133,7 @@ public class QuotaDBUtilsImpl { return result; } + @Override public QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Integer amount, Long updatedBy) { QuotaCreditsVO result = null; TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); @@ -100,5 +148,4 @@ public class QuotaDBUtilsImpl { return new QuotaCreditsResponse(result); } - } 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 0a1ee9d41d9..a3ce6777036 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManager.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManager.java @@ -16,10 +16,18 @@ //under the License. package org.apache.cloudstack.quota; +import java.util.List; + +import org.apache.cloudstack.api.command.QuotaStatementCmd; + +import com.cloud.utils.Pair; import com.cloud.utils.component.PluggableService; public interface QuotaManager extends PluggableService { public void calculateQuotaUsage(); + public Pair,Integer> getQuotaUsage(QuotaStatementCmd 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 9ceeb6f0ca0..56ad5374612 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaManagerImpl.java @@ -19,11 +19,16 @@ package org.apache.cloudstack.quota; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.TimeZone; import javax.ejb.Local; import javax.inject.Inject; +import javax.naming.ConfigurationException; import org.apache.cloudstack.api.command.QuotaMapping; import org.apache.cloudstack.api.command.QuotaCreditsCmd; @@ -31,18 +36,26 @@ import org.apache.cloudstack.api.command.QuotaEditMappingCmd; import org.apache.cloudstack.api.command.QuotaEmailTemplateAddCmd; import org.apache.cloudstack.api.command.QuotaRefreshCmd; import org.apache.cloudstack.api.command.QuotaStatementCmd; +import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; -import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.quota.dao.QuotaMappingDao; import org.apache.cloudstack.quota.dao.QuotaUsageDao; +import org.apache.cloudstack.utils.usage.UsageUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import com.cloud.configuration.Config; +import com.cloud.domain.dao.DomainDao; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; 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; @@ -54,7 +67,7 @@ import com.cloud.utils.db.TransactionLegacy; @Component @Local(value = QuotaManager.class) -public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Configurable, QuotaConfig, Runnable { +public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Configurable, QuotaConfig { private static final Logger s_logger = Logger.getLogger(QuotaManagerImpl.class.getName()); @Inject @@ -67,14 +80,43 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi private QuotaUsageDao _quotaUsageDao; @Inject private ServiceOfferingDao _serviceOfferingDao; + @Inject + private DomainDao _domainDao; + @Inject + private ConfigurationDao _configDao; + @Inject + private AccountService _accountService; - static BigDecimal s_hoursInMonth = new BigDecimal(30.00 * 24.00); + private TimeZone _usageTimezone; + private int _aggregationDuration = 0; + + static BigDecimal s_hoursInMonth = new BigDecimal(30 * 24); + static BigDecimal s_minutesInMonth = new BigDecimal(30 * 24 * 60); static BigDecimal s_gb = new BigDecimal(1024 * 1024 * 1024); public QuotaManagerImpl() { super(); } + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + super.configure(name, params); + String timeZoneStr = _configDao.getValue(Config.UsageAggregationTimezone.toString()); + String aggregationRange = _configDao.getValue(Config.UsageStatsJobAggregationRange.toString()); + if (timeZoneStr == null) { + timeZoneStr = "GMT"; + } + _usageTimezone = TimeZone.getTimeZone(timeZoneStr); + + _aggregationDuration = Integer.parseInt(aggregationRange); + if (_aggregationDuration < UsageUtils.USAGE_AGGREGATION_RANGE_MIN) { + s_logger.warn("Usage stats job aggregation range is to small, using the minimum value of " + UsageUtils.USAGE_AGGREGATION_RANGE_MIN); + _aggregationDuration = UsageUtils.USAGE_AGGREGATION_RANGE_MIN; + } + s_logger.info("Usage timezone = " + _usageTimezone + " AggregationDuration=" + _aggregationDuration); + return true; + } + @Override public List> getCommands() { final List> cmdList = new ArrayList>(); @@ -116,53 +158,56 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi s_logger.info("Account =" + account.getAccountName()); Pair, Integer> usageRecords = getUsageRecords(account.getAccountId(), account.getDomainId()); s_logger.debug("Usage records found " + usageRecords.second()); + for (UsageVO usageRecord : usageRecords.first()) { - s_logger.info("Type=" + usageRecord.getUsageType()); + + BigDecimal aggregationRatio = new BigDecimal(_aggregationDuration).divide(s_minutesInMonth, 8, RoundingMode.HALF_EVEN); + switch (usageRecord.getUsageType()) { case QuotaTypes.RUNNING_VM: - updateQuotaRunningVMUsage(usageRecord, mapping); + updateQuotaRunningVMUsage(usageRecord, mapping, aggregationRatio); break; case QuotaTypes.ALLOCATED_VM: - updateQuotaAllocatedVMUsage(usageRecord, mapping); + updateQuotaAllocatedVMUsage(usageRecord, mapping, aggregationRatio); break; case QuotaTypes.SNAPSHOT: - updateQuotaDiskUsage(usageRecord, mapping, QuotaTypes.SNAPSHOT); + updateQuotaDiskUsage(usageRecord, mapping, aggregationRatio, QuotaTypes.SNAPSHOT); break; case QuotaTypes.TEMPLATE: - updateQuotaDiskUsage(usageRecord, mapping, QuotaTypes.TEMPLATE); + updateQuotaDiskUsage(usageRecord, mapping, aggregationRatio, QuotaTypes.TEMPLATE); break; case QuotaTypes.ISO: - updateQuotaDiskUsage(usageRecord, mapping, QuotaTypes.ISO); + updateQuotaDiskUsage(usageRecord, mapping, aggregationRatio, QuotaTypes.ISO); break; case QuotaTypes.VOLUME: - updateQuotaDiskUsage(usageRecord, mapping, QuotaTypes.VOLUME); + updateQuotaDiskUsage(usageRecord, mapping, aggregationRatio, QuotaTypes.VOLUME); break; case QuotaTypes.VM_SNAPSHOT: - updateQuotaDiskUsage(usageRecord, mapping, QuotaTypes.VM_SNAPSHOT); + updateQuotaDiskUsage(usageRecord, mapping, aggregationRatio, QuotaTypes.VM_SNAPSHOT); break; case QuotaTypes.LOAD_BALANCER_POLICY: - updateQuotaRaw(usageRecord, mapping, QuotaTypes.LOAD_BALANCER_POLICY); + updateQuotaRaw(usageRecord, mapping, aggregationRatio, QuotaTypes.LOAD_BALANCER_POLICY); break; case QuotaTypes.PORT_FORWARDING_RULE: - updateQuotaRaw(usageRecord, mapping, QuotaTypes.PORT_FORWARDING_RULE); + updateQuotaRaw(usageRecord, mapping, aggregationRatio, QuotaTypes.PORT_FORWARDING_RULE); break; case QuotaTypes.IP_ADDRESS: - updateQuotaRaw(usageRecord, mapping, QuotaTypes.IP_ADDRESS); + updateQuotaRaw(usageRecord, mapping, aggregationRatio, QuotaTypes.IP_ADDRESS); break; case QuotaTypes.NETWORK_OFFERING: - updateQuotaRaw(usageRecord, mapping, QuotaTypes.NETWORK_OFFERING); + updateQuotaRaw(usageRecord, mapping, aggregationRatio, QuotaTypes.NETWORK_OFFERING); break; case QuotaTypes.SECURITY_GROUP: - updateQuotaRaw(usageRecord, mapping, QuotaTypes.SECURITY_GROUP); + updateQuotaRaw(usageRecord, mapping, aggregationRatio, QuotaTypes.SECURITY_GROUP); break; case QuotaTypes.VPN_USERS: - updateQuotaRaw(usageRecord, mapping, QuotaTypes.VPN_USERS); + updateQuotaRaw(usageRecord, mapping, aggregationRatio, QuotaTypes.VPN_USERS); break; case QuotaTypes.NETWORK_BYTES_RECEIVED: - updateQuotaRaw(usageRecord, mapping, QuotaTypes.NETWORK_BYTES_RECEIVED); + updateQuotaRaw(usageRecord, mapping, aggregationRatio, QuotaTypes.NETWORK_BYTES_RECEIVED); break; case QuotaTypes.NETWORK_BYTES_SENT: - updateQuotaRaw(usageRecord, mapping, QuotaTypes.NETWORK_BYTES_SENT); + updateQuotaRaw(usageRecord, mapping, aggregationRatio, QuotaTypes.NETWORK_BYTES_SENT); break; case QuotaTypes.VM_DISK_IO_READ: case QuotaTypes.VM_DISK_IO_WRITE: @@ -182,19 +227,127 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi } } + @SuppressWarnings("deprecation") + @Override + public Pair, Integer> getQuotaUsage(QuotaStatementCmd cmd) { + Long accountId = cmd.getAccountId(); + String accountName = cmd.getAccountName(); + Long domainId = cmd.getDomainId(); + Account userAccount = null; + Account caller = CallContext.current().getCallingAccount(); + Integer usageType = cmd.getUsageType(); + + // 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"); + } + } + + 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)) { + 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 records for account: " + accountId + ", domainId: " + domainId + ", between " + adjustedStartDate + " and " + adjustedEndDate + ", using pageSize: " + + cmd.getPageSizeVal() + " and startIndex: " + cmd.getStartIndex()); + + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); + Pair, Integer> quotaUsageRecords = null; + try { + Filter usageFilter = new Filter(QuotaUsageVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal()); + 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(); + } + + // switch back to VMOPS_DB + TransactionLegacy.open(TransactionLegacy.CLOUD_DB); + return quotaUsageRecords; + } + @DB - private void updateQuotaDiskUsage(UsageVO usageRecord, HashMap mapping, int quotaType) { + private void updateQuotaDiskUsage(UsageVO usageRecord, HashMap mapping, BigDecimal aggregationRatio, int quotaType) { if (mapping.get(quotaType) != null) { QuotaUsageVO quota_usage; BigDecimal quotaUsgage; BigDecimal onehourcostpergb; BigDecimal noofgbinuse; - s_logger.info(usageRecord.getDescription() + ", " + usageRecord.getType() + ", " + usageRecord.getOfferingId() + ", " + usageRecord.getTemplateId() + ", " + usageRecord.getUsageDisplay()); - onehourcostpergb = mapping.get(quotaType).getCurrencyValue().divide(s_hoursInMonth, 4, RoundingMode.HALF_EVEN); - noofgbinuse = new BigDecimal(usageRecord.getSize()).divide(s_gb, 4, RoundingMode.HALF_EVEN); + s_logger.info(usageRecord.getDescription() + ", " + usageRecord.getType() + ", " + usageRecord.getOfferingId() + ", " + usageRecord.getTemplateId() + ", " + usageRecord.getUsageDisplay() + + ", aggrR=" + aggregationRatio); + onehourcostpergb = mapping.get(quotaType).getCurrencyValue().multiply(aggregationRatio); + noofgbinuse = new BigDecimal(usageRecord.getSize()).divide(s_gb, 8, RoundingMode.HALF_EVEN); quotaUsgage = new BigDecimal(usageRecord.getRawUsage()).multiply(onehourcostpergb).multiply(noofgbinuse); s_logger.info(" No of GB In use = " + noofgbinuse + " onehour cost=" + onehourcostpergb); - quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getUsageType(), quotaUsgage, usageRecord.getStartDate(), usageRecord.getEndDate()); + quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), usageRecord.getUsageType(), quotaUsgage, + usageRecord.getStartDate(), usageRecord.getEndDate()); _quotaUsageDao.persist(quota_usage); } usageRecord.setQuotaCalculated(1); @@ -202,41 +355,46 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi } @DB - private void updateQuotaRunningVMUsage(UsageVO usageRecord, HashMap mapping) { + private void updateQuotaRunningVMUsage(UsageVO usageRecord, HashMap mapping, BigDecimal aggregationRatio) { QuotaUsageVO quota_usage; BigDecimal cpuquotausgage, speedquotausage, memoryquotausage, vmusage; BigDecimal onehourcostpercpu, onehourcostper100mhz, onehourcostper1mb, onehourcostforvmusage; BigDecimal rawusage; - s_logger.info(usageRecord.getDescription() + ", " + usageRecord.getType() + ", " + usageRecord.getOfferingId() + ", " + usageRecord.getVmInstanceId() + ", " + usageRecord.getUsageDisplay()); + s_logger.info(usageRecord.getDescription() + ", " + usageRecord.getType() + ", " + usageRecord.getOfferingId() + ", " + usageRecord.getVmInstanceId() + ", " + usageRecord.getUsageDisplay() + + ", aggrR=" + aggregationRatio); // get service offering details ServiceOfferingVO serviceoffering = findServiceOffering(usageRecord.getVmInstanceId(), usageRecord.getOfferingId()); rawusage = new BigDecimal(usageRecord.getRawUsage()); - if (mapping.get(QuotaTypes.CPU_NUMBER) == null) { + if (mapping.get(QuotaTypes.CPU_NUMBER) != null) { BigDecimal cpu = new BigDecimal(serviceoffering.getCpu()); - onehourcostpercpu = mapping.get(QuotaTypes.CPU_NUMBER).getCurrencyValue().divide(s_hoursInMonth, 4, RoundingMode.HALF_EVEN); + onehourcostpercpu = mapping.get(QuotaTypes.CPU_NUMBER).getCurrencyValue().multiply(aggregationRatio); cpuquotausgage = rawusage.multiply(onehourcostpercpu).multiply(cpu); - quota_usage = new QuotaUsageVO(usageRecord.getId(), QuotaTypes.CPU_NUMBER, cpuquotausgage, usageRecord.getStartDate(), usageRecord.getEndDate()); + quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.CPU_NUMBER, cpuquotausgage, + usageRecord.getStartDate(), usageRecord.getEndDate()); _quotaUsageDao.persist(quota_usage); } - if (mapping.get(QuotaTypes.CPU_CLOCK_RATE) == null) { + if (mapping.get(QuotaTypes.CPU_CLOCK_RATE) != null) { BigDecimal speed = new BigDecimal(serviceoffering.getSpeed() / 100.00); - onehourcostper100mhz = mapping.get(QuotaTypes.CPU_CLOCK_RATE).getCurrencyValue().divide(s_hoursInMonth, 4, RoundingMode.HALF_EVEN); + onehourcostper100mhz = mapping.get(QuotaTypes.CPU_CLOCK_RATE).getCurrencyValue().multiply(aggregationRatio); speedquotausage = rawusage.multiply(onehourcostper100mhz).multiply(speed); - quota_usage = new QuotaUsageVO(usageRecord.getId(), QuotaTypes.CPU_CLOCK_RATE, speedquotausage, usageRecord.getStartDate(), usageRecord.getEndDate()); + quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.CPU_CLOCK_RATE, speedquotausage, + usageRecord.getStartDate(), usageRecord.getEndDate()); _quotaUsageDao.persist(quota_usage); } - if (mapping.get(QuotaTypes.MEMORY) == null) { + if (mapping.get(QuotaTypes.MEMORY) != null) { BigDecimal memory = new BigDecimal(serviceoffering.getRamSize()); - onehourcostper1mb = mapping.get(QuotaTypes.MEMORY).getCurrencyValue().divide(s_hoursInMonth, 4, RoundingMode.HALF_EVEN); + onehourcostper1mb = mapping.get(QuotaTypes.MEMORY).getCurrencyValue().multiply(aggregationRatio); memoryquotausage = rawusage.multiply(onehourcostper1mb).multiply(memory); - quota_usage = new QuotaUsageVO(usageRecord.getId(), QuotaTypes.MEMORY, memoryquotausage, usageRecord.getStartDate(), usageRecord.getEndDate()); + quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.MEMORY, memoryquotausage, + usageRecord.getStartDate(), usageRecord.getEndDate()); _quotaUsageDao.persist(quota_usage); } - if (mapping.get(QuotaTypes.RUNNING_VM) == null) { - onehourcostforvmusage = mapping.get(QuotaTypes.RUNNING_VM).getCurrencyValue().divide(s_hoursInMonth, 4, RoundingMode.HALF_EVEN); + if (mapping.get(QuotaTypes.RUNNING_VM) != null) { + onehourcostforvmusage = mapping.get(QuotaTypes.RUNNING_VM).getCurrencyValue().multiply(aggregationRatio); vmusage = rawusage.multiply(onehourcostforvmusage); - quota_usage = new QuotaUsageVO(usageRecord.getId(), QuotaTypes.RUNNING_VM, vmusage, usageRecord.getStartDate(), usageRecord.getEndDate()); + quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.RUNNING_VM, vmusage, + usageRecord.getStartDate(), usageRecord.getEndDate()); _quotaUsageDao.persist(quota_usage); } @@ -245,17 +403,18 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi } @DB - private void updateQuotaAllocatedVMUsage(UsageVO usageRecord, HashMap mapping) { + private void updateQuotaAllocatedVMUsage(UsageVO usageRecord, HashMap mapping, BigDecimal aggregationRatio) { if (mapping.get(QuotaTypes.ALLOCATED_VM) != null) { QuotaUsageVO quota_usage; BigDecimal vmusage; BigDecimal onehourcostforvmusage; s_logger.info(usageRecord.getDescription() + ", " + usageRecord.getType() + ", " + usageRecord.getOfferingId() + ", " + usageRecord.getVmInstanceId() + ", " - + usageRecord.getUsageDisplay()); + + usageRecord.getUsageDisplay() + ", aggrR=" + aggregationRatio); - onehourcostforvmusage = mapping.get(QuotaTypes.ALLOCATED_VM).getCurrencyValue().divide(s_hoursInMonth, 4, RoundingMode.HALF_EVEN); + onehourcostforvmusage = mapping.get(QuotaTypes.ALLOCATED_VM).getCurrencyValue().multiply(aggregationRatio); vmusage = new BigDecimal(usageRecord.getRawUsage()).multiply(onehourcostforvmusage); - quota_usage = new QuotaUsageVO(usageRecord.getId(), QuotaTypes.ALLOCATED_VM, vmusage, usageRecord.getStartDate(), usageRecord.getEndDate()); + quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.ALLOCATED_VM, vmusage, + usageRecord.getStartDate(), usageRecord.getEndDate()); _quotaUsageDao.persist(quota_usage); } @@ -264,17 +423,18 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi } @DB - private void updateQuotaRaw(UsageVO usageRecord, HashMap mapping, int ruleType) { + private void updateQuotaRaw(UsageVO usageRecord, HashMap mapping, BigDecimal aggregationRatio, int ruleType) { if (mapping.get(ruleType) != null) { QuotaUsageVO quota_usage; BigDecimal ruleusage; BigDecimal onehourcost; s_logger.info(usageRecord.getDescription() + ", " + usageRecord.getType() + ", " + usageRecord.getOfferingId() + ", " + usageRecord.getVmInstanceId() + ", " - + usageRecord.getUsageDisplay()); + + usageRecord.getUsageDisplay() + ", aggrR=" + aggregationRatio); - onehourcost = mapping.get(ruleType).getCurrencyValue().divide(s_hoursInMonth, 4, RoundingMode.HALF_EVEN); + onehourcost = mapping.get(ruleType).getCurrencyValue().multiply(aggregationRatio); ruleusage = new BigDecimal(usageRecord.getRawUsage()).multiply(onehourcost); - quota_usage = new QuotaUsageVO(usageRecord.getId(), ruleType, ruleusage, usageRecord.getStartDate(), usageRecord.getEndDate()); + quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), ruleType, ruleusage, usageRecord.getStartDate(), + usageRecord.getEndDate()); _quotaUsageDao.persist(quota_usage); } @@ -286,16 +446,17 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi private void updateQuotaNetwork(UsageVO usageRecord, HashMap mapping, int transferType) { if (mapping.get(transferType) != null) { QuotaUsageVO quota_usage; - BigDecimal onehourcost; + BigDecimal onegbcost; BigDecimal rawusageingb; BigDecimal networkusage; s_logger.info(usageRecord.getDescription() + ", " + usageRecord.getType() + ", " + usageRecord.getOfferingId() + ", " + usageRecord.getVmInstanceId() + ", " + usageRecord.getUsageDisplay()); - onehourcost = mapping.get(transferType).getCurrencyValue().divide(s_hoursInMonth, 4, RoundingMode.HALF_EVEN); - rawusageingb = new BigDecimal(usageRecord.getRawUsage()).divide(s_gb, 4, RoundingMode.HALF_EVEN); - networkusage = rawusageingb.multiply(onehourcost); - quota_usage = new QuotaUsageVO(usageRecord.getId(), transferType, networkusage, usageRecord.getStartDate(), usageRecord.getEndDate()); + onegbcost = mapping.get(transferType).getCurrencyValue(); + rawusageingb = new BigDecimal(usageRecord.getRawUsage()).divide(s_gb, 8, RoundingMode.HALF_EVEN); + networkusage = rawusageingb.multiply(onegbcost); + quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), transferType, networkusage, usageRecord.getStartDate(), + usageRecord.getEndDate()); _quotaUsageDao.persist(quota_usage); } @@ -332,14 +493,32 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Confi return result; } - @Override - public void run() { - (new ManagedContextRunnable() { - @Override - protected void runInContext() { - calculateQuotaUsage(); - } - }).run(); + public TimeZone getUsageTimezone() { + return _usageTimezone; + } + + private Date computeAdjustedTime(Date initialDate, TimeZone targetTZ) { + Calendar cal = Calendar.getInstance(); + cal.setTime(initialDate); + TimeZone localTZ = cal.getTimeZone(); + int timezoneOffset = cal.get(Calendar.ZONE_OFFSET); + if (localTZ.inDaylightTime(initialDate)) { + timezoneOffset += (60 * 60 * 1000); + } + cal.add(Calendar.MILLISECOND, timezoneOffset); + + Date newTime = cal.getTime(); + + Calendar calTS = Calendar.getInstance(targetTZ); + calTS.setTime(newTime); + timezoneOffset = calTS.get(Calendar.ZONE_OFFSET); + if (targetTZ.inDaylightTime(initialDate)) { + timezoneOffset += (60 * 60 * 1000); + } + + calTS.add(Calendar.MILLISECOND, -1 * timezoneOffset); + + return calTS.getTime(); } } diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaMappingVO.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaMappingVO.java index f9b2c7ae494..e0c6bab090a 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaMappingVO.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaMappingVO.java @@ -31,9 +31,6 @@ public class QuotaMappingVO implements InternalIdentity { private static final long serialVersionUID = -7117933766387653203L; @Id - @Column(name = "id") - private Long id; - @Column(name = "usage_type") private int usageType; @@ -127,6 +124,6 @@ public class QuotaMappingVO implements InternalIdentity { @Override public long getId() { // TODO Auto-generated method stub - return this.id; + return this.usageType; } } \ No newline at end of file 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 3f7a2eb41fd..97901642a2b 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaUsageVO.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaUsageVO.java @@ -38,6 +38,15 @@ public class QuotaUsageVO implements InternalIdentity { @Column(name = "id") private Long id; + @Column(name = "zone_id") + private Long zoneId = null; + + @Column(name = "account_id") + private Long accountId = null; + + @Column(name = "domain_id") + private Long domainId = null; + @Column(name = "usage_item_id") private Long usageItemId; @@ -58,15 +67,42 @@ public class QuotaUsageVO implements InternalIdentity { public QuotaUsageVO() { } - public QuotaUsageVO(Long usageItemId, int usageType, BigDecimal quotaUsed, Date startDate, Date endDate) { + public QuotaUsageVO(Long usageItemId, Long zoneId, Long accountId, Long domainId, int usageType, BigDecimal quotaUsed, Date startDate, Date endDate) { super(); this.usageItemId = usageItemId; + this.zoneId = zoneId; + this.accountId = accountId; + this.domainId = domainId; this.usageType = usageType; this.quotaUsed = quotaUsed; this.startDate = startDate; this.endDate = endDate; } + public Long getZoneId() { + return zoneId; + } + + public void setZoneId(Long zoneId) { + this.zoneId = zoneId; + } + + public Long getAccountId() { + return accountId; + } + + public void setAccountId(Long accountId) { + this.accountId = accountId; + } + + public Long getDomainId() { + return domainId; + } + + public void setDomainId(Long domainId) { + this.domainId = domainId; + } + @Override public long getId() { // TODO Auto-generated method stub 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 1253bd42ac5..c8a40673e73 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 @@ -34,14 +34,14 @@ public class QuotaUsageDaoImpl extends GenericDaoBase implem @Override public Pair, Integer> searchAndCountAllRecords(SearchCriteria sc, Filter filter) { - // TODO Auto-generated method stub - return null; + return listAndCountIncludingRemovedBy(sc, filter); } @Override - public void saveQuotaUsage(List credits) { - // TODO Auto-generated method stub - + public void saveQuotaUsage(List records) { + for (QuotaUsageVO usageRecord : records) { + persist(usageRecord); + } } } diff --git a/setup/db/db/schema-451to452.sql b/setup/db/db/schema-451to452.sql index 226224d9ebb..490ab62792a 100644 --- a/setup/db/db/schema-451to452.sql +++ b/setup/db/db/schema-451to452.sql @@ -21,6 +21,7 @@ -- SAML + DELETE FROM `cloud`.`configuration` WHERE name like 'saml%' and component='management-server'; ALTER TABLE `cloud`.`user` ADD COLUMN `external_entity` text DEFAULT NULL COMMENT "reference to external federation entity"; @@ -37,8 +38,7 @@ CREATE TABLE `cloud`.`saml_token` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `quota_mapping` ( - `id` bigint(20) unsigned NOT NULL COMMENT 'id', +CREATE TABLE `quota_mapping` ( `usage_type` int(2) unsigned DEFAULT NULL, `usage_name` varchar(255) NOT NULL COMMENT 'usage type', `usage_unit` varchar(255) NOT NULL COMMENT 'usage type', @@ -46,34 +46,34 @@ CREATE TABLE IF NOT EXISTS `quota_mapping` ( `currency_value` decimal(15,2) NOT NULL COMMENT 'usage type', `include` tinyint(1) NOT NULL COMMENT 'usage type', `description` varchar(255) NOT NULL COMMENT 'usage type', - PRIMARY KEY (`id`) + PRIMARY KEY (`usage_type`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; LOCK TABLES `quota_mapping` WRITE; INSERT INTO `quota_mapping` VALUES - (1,1,'RUNNING_VM','Compute-Month','',5.00,1,'Quota mapping for running VM'), - (2,2,'ALLOCATED_VM','Compute-Month','',10.00,1,'Quota mapping for allocsated VM'), - (3,3,'IP_ADDRESS','IP-Month','',5.12,1,'Quota mapping for IP address in use'), - (4,4,'NETWORK_BYTES_SENT','GB','',1.00,1,'Quota mapping for network bytes sent'), - (5,5,'NETWORK_BYTES_RECEIVED','GB','',1.00,1,'Quota mapping for network bytes received'), - (6,6,'VOLUME','GB-Month','',5.00,1,'Quota mapping for volume usage per month'), - (7,7,'TEMPLATE','GB-Month','',5.00,1,'Quota mapping for template usage per month'), - (8,8,'ISO','GB-Month','',5.00,1,'Quota mapping for ISO storage per month'), - (9,9,'SNAPSHOT','GB-Month','',5.00,1,'Quota mapping for snapshot usage per month'), - (10,10,'SECURITY_GROUP','Policy-Month','',5.00,1,'Quota mapping for Security groups'), - (11,11,'LOAD_BALANCER_POLICY','Policy-Month','',5.00,1,'Quota mapping load balancer policy use per hour'), - (12,12,'PORT_FORWARDING_RULE','Policy-Month','',5.00,1,'Quota mapping port forwarding rule useper hour'), - (13,13,'NETWORK_OFFERING','Policy-Month','',5.00,1,'Quota mapping for network offering usage per hour'), - (14,14,'VPN_USERS','Policy-Month','',5.00,1,'Quota mapping for using VPN'), - (15,15,'CPU_SPEED','Compute-Month','100MHz',5.00,1,'Quota mapping for 100 MHz of CPU running for an hour'), - (16,16,'vCPU','Compute-Month','1VCPU',5.00,1,'Quota mapping for running VM that has 1vCPU'), - (17,17,'MEMORY','Compute-Month','1MB',5.00,1,'Quota mapping for usign 1MB or RAM for 1 hour'), - (18,21,'VM_DISK_IO_READ','GB','1',5.00,1,'Quota mapping for 1GB of disk IO read'), - (19,22,'VM_DISK_IO_WRITE','GB','1',5.00,1,'Quota mapping for 1GB of disk data write'), - (20,23,'VM_DISK_BYTES_READ','GB','1',5.00,1,'Quota mapping for disk bytes read'), - (21,24,'VM_DISK_BYTES_WRITE','GB','1',5.00,1,'Quota mapping for disk bytes write'), - (22,25,'VM_SNAPSHOT','GB-Month','',5.00,1,'Quota mapping for running VM'); + (1,'RUNNING_VM','Compute-Month','',5.00,1,'Quota mapping for running VM'), + (2,'ALLOCATED_VM','Compute-Month','',10.00,1,'Quota mapping for allocsated VM'), + (3,'IP_ADDRESS','IP-Month','',5.12,1,'Quota mapping for IP address in use'), + (4,'NETWORK_BYTES_SENT','GB','',1.00,1,'Quota mapping for network bytes sent'), + (5,'NETWORK_BYTES_RECEIVED','GB','',1.00,1,'Quota mapping for network bytes received'), + (6,'VOLUME','GB-Month','',5.00,1,'Quota mapping for volume usage per month'), + (7,'TEMPLATE','GB-Month','',5.00,1,'Quota mapping for template usage per month'), + (8,'ISO','GB-Month','',5.00,1,'Quota mapping for ISO storage per month'), + (9,'SNAPSHOT','GB-Month','',5.00,1,'Quota mapping for snapshot usage per month'), + (10,'SECURITY_GROUP','Policy-Month','',5.00,1,'Quota mapping for Security groups'), + (11,'LOAD_BALANCER_POLICY','Policy-Month','',5.00,1,'Quota mapping load balancer policy use per hour'), + (12,'PORT_FORWARDING_RULE','Policy-Month','',5.00,1,'Quota mapping port forwarding rule useper hour'), + (13,'NETWORK_OFFERING','Policy-Month','',5.00,1,'Quota mapping for network offering usage per hour'), + (14,'VPN_USERS','Policy-Month','',5.00,1,'Quota mapping for using VPN'), + (15,'CPU_SPEED','Compute-Month','100MHz',5.00,1,'Quota mapping for 100 MHz of CPU running for an hour'), + (16,'vCPU','Compute-Month','1VCPU',5.00,1,'Quota mapping for running VM that has 1vCPU'), + (17,'MEMORY','Compute-Month','1MB',5.00,1,'Quota mapping for usign 1MB or RAM for 1 hour'), + (21,'VM_DISK_IO_READ','GB','1',5.00,1,'Quota mapping for 1GB of disk IO read'), + (22,'VM_DISK_IO_WRITE','GB','1',5.00,1,'Quota mapping for 1GB of disk data write'), + (23,'VM_DISK_BYTES_READ','GB','1',5.00,1,'Quota mapping for disk bytes read'), + (24,'VM_DISK_BYTES_WRITE','GB','1',5.00,1,'Quota mapping for disk bytes write'), + (25,'VM_SNAPSHOT','GB-Month','',5.00,1,'Quota mapping for running VM'); UNLOCK TABLES; @@ -81,22 +81,24 @@ CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_credits` ( `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', `account_id` bigint unsigned NOT NULL, `domain_id` bigint(20) unsigned NOT NULL, - `credit` decimal(15,2) COMMENT 'amount credited', + `credit` decimal(15,4) COMMENT 'amount credited', `updated_on` datetime NOT NULL COMMENT 'date created', `updated_by` bigint unsigned NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_usage` ( - `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', - `usage_item_id` bigint unsigned NOT NULL, +CREATE TABLE IF NOT EXISTS `quota_usage` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `usage_item_id` bigint(20) unsigned NOT NULL, + `zone_id` bigint(20) unsigned NOT NULL, + `account_id` bigint(20) unsigned NOT NULL, + `domain_id` bigint(20) unsigned NOT NULL, `usage_type` varchar(64) DEFAULT NULL, - `quota_used` int unsigned NOT NULL, + `quota_used` decimal(15,4) unsigned NOT NULL, `start_date` datetime NOT NULL COMMENT 'start time for this usage item', `end_date` datetime NOT NULL COMMENT 'end time for this usage item', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_balance` (