From b38f73805a6e0ec5da6818a300e53cb370b3dfca Mon Sep 17 00:00:00 2001 From: Abhinandan Prateek Date: Tue, 4 Aug 2015 10:29:33 +0530 Subject: [PATCH] quota: added checks for quota enforce and threshold per account --- .../quota/constant/QuotaConfig.java | 15 ----- .../quota/dao/QuotaBalanceDaoImpl.java | 3 +- .../quota/dao/QuotaTariffDaoImpl.java | 4 +- .../cloudstack/quota/vo/QuotaAccountVO.java | 6 +- .../response/QuotaResponseBuilderImpl.java | 3 +- .../cloudstack/quota/QuotaServiceImpl.java | 4 +- .../src/com/cloud/usage/UsageManagerImpl.java | 13 +++-- .../quota/job/QuotaAlertManagerImpl.java | 55 +++++++++++++------ .../quota/job/QuotaManagerImpl.java | 3 +- 9 files changed, 58 insertions(+), 48 deletions(-) diff --git a/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaConfig.java b/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaConfig.java index b5fa5723c3f..dd7c5a76591 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaConfig.java +++ b/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaConfig.java @@ -23,15 +23,6 @@ public interface QuotaConfig { public static final ConfigKey QuotaPluginEnabled = new ConfigKey("Advanced", Boolean.class, "quota.enable.service", "false", "Indicates whether Quota plugin is enabled or not", true); - public static final ConfigKey QuotaPeriodType = new ConfigKey("Advanced", String.class, "quota.period.type", "2", - "Quota period type: 1 for every x days, 2 for certain day of the month, 3 for yearly on activation day - default quota usage reporting cycl", true); - - public static final ConfigKey QuotaPeriod = new ConfigKey("Advanced", String.class, "quota.period.config", "15", - "The period config in number of days for the quota period type", true); - - public static final ConfigKey QuotaGenerateActivity = new ConfigKey("Advanced", String.class, "quota.activity.generate", "true", - "Set true to enable a detailed log of the quota usage, rating and billing activity, on daily basis. Valid values (true, false)", true); - public static final ConfigKey QuotaEmailRecordOutgoing = new ConfigKey("Advanced", String.class, "quota.email.outgoing.record", "false", "true means all the emails sent out will be stored in local DB, by default it is false", true); @@ -41,12 +32,6 @@ public interface QuotaConfig { public static final ConfigKey QuotaCurrencySymbol = new ConfigKey("Advanced", String.class, "quota.currency.symbol", "R", "The symbol for the currency in use to measure usage.", true); - public static final ConfigKey QuotaLimitCritical = new ConfigKey("Advanced", String.class, "quota.limit.critical", "80", - "The quota amount when reached, the account users are sent low quota email alerts.", true); - - public static final ConfigKey QuotaLimitIncremental = new ConfigKey("Advanced", String.class, "quota.limit.increment", "5", - "Quota limit incremental", true); - public static final ConfigKey QuotaSmtpHost = new ConfigKey("Advanced", String.class, "quota.usage.smtp.host", "", "Quota SMTP host for quota related emails", true); diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java index 4830a52ad11..4cb4b3f6d8f 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java @@ -168,8 +168,7 @@ public class QuotaBalanceDaoImpl extends GenericDaoBase im trimmedRecords.add(entry); } else { trimmedRecords.add(entry); - break; // add only consecutive credit entries and last - // balance entry + break; // add only consecutive credit entries and last balance entry } } diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java index 029ef6bb9f3..38aad156d0c 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java @@ -70,10 +70,10 @@ public class QuotaTariffDaoImpl extends GenericDaoBase impl // Switch back TransactionLegacy.open(opendb).close(); if (result.size() > 0) { - s_logger.info("findTariffPlanByUsageType: " + effectiveDate + "quota type " + quotaType + " val=" + result.get(0).getCurrencyValue()); + //s_logger.info("findTariffPlanByUsageType: " + effectiveDate + "quota type " + quotaType + " val=" + result.get(0).getCurrencyValue()); return result.get(0); } else { - s_logger.info("Missing quota type " + quotaType); + //s_logger.info("Missing quota type " + quotaType); return null; } } diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaAccountVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaAccountVO.java index f2159b0f45e..e9fcf37a544 100644 --- a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaAccountVO.java +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaAccountVO.java @@ -80,7 +80,7 @@ public class QuotaAccountVO implements InternalIdentity { } public Integer getQuotaEnforce() { - return quotaEnforce; + return quotaEnforce == null ? 0 : quotaEnforce; } public void setQuotaEnforce(Integer quotaEnforce) { @@ -96,7 +96,7 @@ public class QuotaAccountVO implements InternalIdentity { } public BigDecimal getQuotaMinBalance() { - return quotaMinBalance; + return quotaMinBalance == null ? new BigDecimal(0) : quotaMinBalance; } public void setQuotaMinBalance(BigDecimal quotaMinBalance) { @@ -112,7 +112,7 @@ public class QuotaAccountVO implements InternalIdentity { } public Date getQuotaAlertDate() { - return quotaAlertDate; + return quotaAlertDate == null ? new Date() : quotaAlertDate; } public void setQuotaAlertDate(Date quotaAlertDate) { diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java index 9131a8d4882..21f3ca26318 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java @@ -175,8 +175,9 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder { BigDecimal totalUsage = new BigDecimal(0); quotaUsage.add(new QuotaUsageVO());// boundary QuotaUsageVO prev = quotaUsage.get(0); + s_logger.info("createQuotaStatementResponse record count=" + quotaUsage.size()); for (final QuotaUsageVO quotaRecord : quotaUsage) { - s_logger.info("createQuotaStatementResponse Type=" + quotaRecord.getUsageType() + " usage=" + usage + " name" + quotaRecord.getUsageItemId()); + //s_logger.info("createQuotaStatementResponse Type=" + quotaRecord.getUsageType() + " usage=" + usage + " name" + quotaRecord.getUsageItemId()); if (type != quotaRecord.getUsageType()) { if (type != -1) { lineitem = new QuotaStatementItemResponse(); diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java index 55f5f876f22..06702061bff 100644 --- a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java @@ -132,8 +132,8 @@ public class QuotaServiceImpl extends ManagerBase implements QuotaService, Confi @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] { QuotaPluginEnabled, QuotaPeriodType, QuotaPeriod, QuotaGenerateActivity, QuotaEmailRecordOutgoing, QuotaEnableEnforcement, QuotaCurrencySymbol, QuotaLimitCritical, - QuotaLimitIncremental, QuotaSmtpHost, QuotaSmtpPort, QuotaSmtpTimeout, QuotaSmtpUser, QuotaSmtpPassword, QuotaSmtpAuthType, QuotaSmtpSender }; + return new ConfigKey[] { QuotaPluginEnabled, QuotaEmailRecordOutgoing, QuotaEnableEnforcement, QuotaCurrencySymbol, QuotaSmtpHost, QuotaSmtpPort, QuotaSmtpTimeout, QuotaSmtpUser, + QuotaSmtpPassword, QuotaSmtpAuthType, QuotaSmtpSender }; } @Override diff --git a/usage/src/com/cloud/usage/UsageManagerImpl.java b/usage/src/com/cloud/usage/UsageManagerImpl.java index dad2389c514..06fe7bdf455 100644 --- a/usage/src/com/cloud/usage/UsageManagerImpl.java +++ b/usage/src/com/cloud/usage/UsageManagerImpl.java @@ -154,6 +154,7 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna private final Calendar _jobExecTime = Calendar.getInstance(); private int _aggregationDuration = 0; private int _sanityCheckInterval = 0; + private boolean _runQuota=false; String _hostname = null; int _pid = 0; TimeZone _usageTimezone = TimeZone.getTimeZone("GMT");; @@ -207,6 +208,8 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna String execTimeZone = configs.get("usage.execution.timezone"); String aggreagationTimeZone = configs.get("usage.aggregation.timezone"); String sanityCheckInterval = configs.get("usage.sanity.check.interval"); + String quotaEnable = configs.get("quota.enable.service"); + _runQuota = Boolean.valueOf(quotaEnable == null ? "false" : quotaEnable ); if (sanityCheckInterval != null) { _sanityCheckInterval = Integer.parseInt(sanityCheckInterval); } @@ -381,10 +384,12 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna } parse(job, startDate, endDate); - // after usage is calculated run quota calculations - _quotaManager.calculateQuotaUsage(); - // run alert manager - _alertManager.checkAndSendQuotaAlertEmails(); + if (_runQuota){ + // after usage is calculated run quota calculations + _quotaManager.calculateQuotaUsage(); + // run alert manager + _alertManager.checkAndSendQuotaAlertEmails(); + } } else { if (s_logger.isDebugEnabled()) { s_logger.debug("Not owner of usage job, skipping..."); diff --git a/usage/src/org/apache/cloudstack/quota/job/QuotaAlertManagerImpl.java b/usage/src/org/apache/cloudstack/quota/job/QuotaAlertManagerImpl.java index 59c5019898e..94f9c360c19 100644 --- a/usage/src/org/apache/cloudstack/quota/job/QuotaAlertManagerImpl.java +++ b/usage/src/org/apache/cloudstack/quota/job/QuotaAlertManagerImpl.java @@ -37,8 +37,9 @@ import com.sun.mail.smtp.SMTPTransport; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.quota.constant.QuotaConfig; -import org.apache.cloudstack.quota.dao.QuotaBalanceDao; +import org.apache.cloudstack.quota.dao.QuotaAccountDao; import org.apache.cloudstack.quota.dao.QuotaEmailTemplatesDao; +import org.apache.cloudstack.quota.vo.QuotaAccountVO; import org.apache.cloudstack.quota.vo.QuotaEmailTemplatesVO; import org.apache.commons.lang3.text.StrSubstitutor; import org.apache.log4j.Logger; @@ -73,17 +74,18 @@ public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertMana @Inject private AccountDao _accountDao; @Inject + private QuotaAccountDao _quotaAcc; + @Inject private UserDao _userDao; @Inject private DomainDao _domainDao; @Inject private QuotaEmailTemplatesDao _quotaEmailTemplateDao; @Inject - private QuotaBalanceDao _quotaBalanceDao; - @Inject private ConfigurationDao _configDao; private EmailQuotaAlert _emailQuotaAlert; + private boolean _lockAccountEnforcement = false; final static BigDecimal s_hoursInMonth = new BigDecimal(30 * 24); final static BigDecimal s_minutesInMonth = new BigDecimal(30 * 24 * 60); @@ -118,6 +120,7 @@ public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertMana String smtpUsername = QuotaConfig.QuotaSmtpUser.value(); String smtpPassword = QuotaConfig.QuotaSmtpPassword.value(); String emailSender = QuotaConfig.QuotaSmtpSender.value(); + _lockAccountEnforcement = QuotaConfig.QuotaEnableEnforcement.value().equalsIgnoreCase("true"); boolean smtpDebug = false; _emailQuotaAlert = new EmailQuotaAlert(smtpHost, smtpPort, useAuth, smtpUsername, smtpPassword, emailSender, smtpDebug); @@ -155,20 +158,29 @@ public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertMana @Override public void checkAndSendQuotaAlertEmails() { List deferredQuotaEmailList = new ArrayList(); - final Date currentDate = startOfNextDay(); final BigDecimal zeroBalance = new BigDecimal(0); - final BigDecimal thresholdBalance = new BigDecimal(QuotaConfig.QuotaLimitCritical.value()); - final boolean lockAccountEnforcement = QuotaConfig.QuotaEnableEnforcement.value().equalsIgnoreCase("true"); - for (final AccountVO account : _accountDao.listAll()) { - final BigDecimal accountBalance = _quotaBalanceDao.lastQuotaBalance(account.getId(), account.getDomainId(), currentDate); + for (final QuotaAccountVO quotaAccount : _quotaAcc.listAll()) { + BigDecimal accountBalance = quotaAccount.getQuotaBalance(); + Date balanceDate = quotaAccount.getQuotaBalanceDate(); + Date alertDate = quotaAccount.getQuotaAlertDate(); + int lockable = quotaAccount.getQuotaEnforce(); + BigDecimal thresholdBalance = quotaAccount.getQuotaMinBalance(); if (accountBalance != null) { + AccountVO account = _accountDao.findById(quotaAccount.getId()); + s_logger.info("checkAndSendQuotaAlertEmails accId=" + quotaAccount.getId() + " domId=" + account.getDomainId() + "threshold=" + thresholdBalance + " locakable=" + lockable); if (accountBalance.compareTo(zeroBalance) <= 0) { - if (lockAccountEnforcement && account.getType() == Account.ACCOUNT_TYPE_NORMAL) { - lockAccount(account.getId()); + if (_lockAccountEnforcement && lockable == 1) { + if (account.getType() == Account.ACCOUNT_TYPE_NORMAL) { + lockAccount(account.getId()); + } + } + if (balanceDate.compareTo(alertDate) > 0) { + deferredQuotaEmailList.add(new DeferredQuotaEmail(account, quotaAccount, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_EMPTY)); } - deferredQuotaEmailList.add(new DeferredQuotaEmail(account, accountBalance, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_EMPTY)); } else if (accountBalance.compareTo(thresholdBalance) <= 0) { - deferredQuotaEmailList.add(new DeferredQuotaEmail(account, accountBalance, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_LOW)); + if (balanceDate.compareTo(alertDate) > 0) { + deferredQuotaEmailList.add(new DeferredQuotaEmail(account, quotaAccount, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_LOW)); + } } } } @@ -179,8 +191,8 @@ public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertMana } } - public void sendQuotaAlert(AccountVO account, BigDecimal balance, QuotaConfig.QuotaEmailTemplateTypes emailType) { - sendQuotaAlert(new DeferredQuotaEmail(account, balance, emailType)); + public void sendQuotaAlert(AccountVO account, QuotaAccountVO quotaAccount, QuotaConfig.QuotaEmailTemplateTypes emailType) { + sendQuotaAlert(new DeferredQuotaEmail(account, quotaAccount, emailType)); } private void sendQuotaAlert(DeferredQuotaEmail emailToBeSent) { @@ -218,6 +230,7 @@ public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertMana final String body = templateEngine.replace(emailTemplate.getTemplateBody()); try { _emailQuotaAlert.sendQuotaAlert(emailRecipients, subject, body); + emailToBeSent.sentSuccessfully(); } catch (Exception e) { s_logger.error(String.format("Unable to send quota alert email (subject=%s; body=%s) to account %s (%s) recipients (%s) due to error (%s)", subject, body, account.getAccountName(), account.getUuid(), emailRecipients, e)); @@ -229,12 +242,12 @@ public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertMana class DeferredQuotaEmail { AccountVO account; - BigDecimal quotaBalance; + QuotaAccountVO quotaAccount; QuotaConfig.QuotaEmailTemplateTypes emailTemplateType; - public DeferredQuotaEmail(AccountVO account, BigDecimal quotaBalance, QuotaConfig.QuotaEmailTemplateTypes emailTemplateType) { + public DeferredQuotaEmail(AccountVO account, QuotaAccountVO quotaAccount, QuotaConfig.QuotaEmailTemplateTypes emailTemplateType) { this.account = account; - this.quotaBalance = quotaBalance; + this.quotaAccount = quotaAccount; this.emailTemplateType = emailTemplateType; } @@ -243,12 +256,18 @@ public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertMana } public BigDecimal getQuotaBalance() { - return quotaBalance; + return quotaAccount.getQuotaBalance(); } public QuotaConfig.QuotaEmailTemplateTypes getEmailTemplateType() { return emailTemplateType; } + + public void sentSuccessfully() { + quotaAccount.setQuotaAlertDate(new Date()); + quotaAccount.setQuotaAlertType(emailTemplateType.ordinal()); + _quotaAcc.update(quotaAccount.getAccountId(), quotaAccount); + } }; class EmailQuotaAlert { diff --git a/usage/src/org/apache/cloudstack/quota/job/QuotaManagerImpl.java b/usage/src/org/apache/cloudstack/quota/job/QuotaManagerImpl.java index a58315237f9..140c814ffdb 100644 --- a/usage/src/org/apache/cloudstack/quota/job/QuotaManagerImpl.java +++ b/usage/src/org/apache/cloudstack/quota/job/QuotaManagerImpl.java @@ -228,7 +228,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Runna } } while ((usageRecords != null) && !usageRecords.first().isEmpty()); // list of quotas for this account - s_logger.info("Quota entries size = " + quotalistforaccount.size()); + s_logger.info("Quota entries size = " + quotalistforaccount.size() + ", accId" + account.getAccountId() + ", domId" + account.getDomainId()); if (quotalistforaccount.size() > 0) { // balance to be processed quotalistforaccount.add(new QuotaUsageVO()); Date startDate = quotalistforaccount.get(0).getStartDate(); @@ -261,6 +261,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager, Runna } // update is quota_accounts QuotaAccountVO quota_account = _quotaAcc.findById(account.getAccountId()); + s_logger.info("Updating quota account bal=" + aggrUsage + " date=" + endDate); if (quota_account == null) { quota_account = new QuotaAccountVO(account.getAccountId()); quota_account.setQuotaBalance(aggrUsage);