quota: added checks for quota enforce and threshold per account

This commit is contained in:
Abhinandan Prateek 2015-08-04 10:29:33 +05:30
parent d5eabfb7b2
commit b38f73805a
9 changed files with 58 additions and 48 deletions

View File

@ -23,15 +23,6 @@ public interface QuotaConfig {
public static final ConfigKey<Boolean> QuotaPluginEnabled = new ConfigKey<Boolean>("Advanced", Boolean.class, "quota.enable.service", "false",
"Indicates whether Quota plugin is enabled or not", true);
public static final ConfigKey<String> QuotaPeriodType = new ConfigKey<String>("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<String> QuotaPeriod = new ConfigKey<String>("Advanced", String.class, "quota.period.config", "15",
"The period config in number of days for the quota period type", true);
public static final ConfigKey<String> QuotaGenerateActivity = new ConfigKey<String>("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<String> QuotaEmailRecordOutgoing = new ConfigKey<String>("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<String> QuotaCurrencySymbol = new ConfigKey<String>("Advanced", String.class, "quota.currency.symbol", "R",
"The symbol for the currency in use to measure usage.", true);
public static final ConfigKey<String> QuotaLimitCritical = new ConfigKey<String>("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<String> QuotaLimitIncremental = new ConfigKey<String>("Advanced", String.class, "quota.limit.increment", "5",
"Quota limit incremental", true);
public static final ConfigKey<String> QuotaSmtpHost = new ConfigKey<String>("Advanced", String.class, "quota.usage.smtp.host", "",
"Quota SMTP host for quota related emails", true);

View File

@ -168,8 +168,7 @@ public class QuotaBalanceDaoImpl extends GenericDaoBase<QuotaBalanceVO, Long> 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
}
}

View File

@ -70,10 +70,10 @@ public class QuotaTariffDaoImpl extends GenericDaoBase<QuotaTariffVO, Long> 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;
}
}

View File

@ -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) {

View File

@ -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();

View File

@ -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

View File

@ -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...");

View File

@ -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<DeferredQuotaEmail> deferredQuotaEmailList = new ArrayList<DeferredQuotaEmail>();
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 {

View File

@ -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);