mirror of https://github.com/apache/cloudstack.git
quota: added checks for quota enforce and threshold per account
This commit is contained in:
parent
d5eabfb7b2
commit
b38f73805a
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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...");
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue