From bf29695d74b1547c03d202a36526872eec2349e2 Mon Sep 17 00:00:00 2001 From: Julien Hervot de Mattos Vaz Date: Wed, 2 Apr 2025 14:47:47 -0300 Subject: [PATCH 1/4] Use account Quota settings --- ...s-between-management-and-usage-context.xml | 3 ++ .../quota/QuotaAlertManagerImpl.java | 2 +- .../apache/cloudstack/quota/QuotaManager.java | 3 ++ .../cloudstack/quota/QuotaManagerImpl.java | 42 ++++++++++++++++++- .../quota/QuotaAlertManagerImplTest.java | 5 +-- 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml index d6d72f9228e1..edb4b8dcecc7 100644 --- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml +++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-common-daos-between-management-and-usage-context.xml @@ -28,6 +28,9 @@ > + + + diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java index b26b3171f5b5..843febb032c5 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java @@ -149,7 +149,7 @@ public boolean stop() { */ @Override public boolean isQuotaEmailTypeEnabledForAccount(AccountVO account, QuotaEmailTemplateTypes quotaEmailTemplateType) { - boolean quotaEmailsEnabled = QuotaConfig.QuotaEnableEmails.valueIn(account.getAccountId()); + boolean quotaEmailsEnabled = _quotaManager.findConfigurationValue(account, QuotaConfig.QuotaEnableEmails); if (!quotaEmailsEnabled) { logger.debug("Configuration [{}] is disabled for account [{}]. Therefore, the account will not receive Quota email of type [{}].", QuotaConfig.QuotaEnableEmails.key(), account, quotaEmailTemplateType); return false; diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManager.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManager.java index 7811bcbccad7..94a5de8a54ff 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManager.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManager.java @@ -18,6 +18,7 @@ import com.cloud.user.AccountVO; import com.cloud.utils.component.Manager; +import org.apache.cloudstack.framework.config.ConfigKey; public interface QuotaManager extends Manager { @@ -25,4 +26,6 @@ public interface QuotaManager extends Manager { boolean isLockable(AccountVO account); + boolean findConfigurationValue(AccountVO accountVO, ConfigKey key); + } diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java index a03f82a43586..be9ef110bd7c 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java @@ -32,7 +32,12 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.domain.DomainDetailVO; +import com.cloud.domain.dao.DomainDetailsDao; import com.cloud.user.Account; +import com.cloud.user.AccountDetailVO; +import com.cloud.user.AccountDetailsDao; +import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.quota.activationrule.presetvariables.Configuration; import org.apache.cloudstack.quota.activationrule.presetvariables.GenericPresetVariable; @@ -89,6 +94,10 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager { @Inject protected PresetVariableHelper presetVariableHelper; + @Inject + protected AccountDetailsDao accountDetailsDao; + @Inject + protected DomainDetailsDao domainDetailsDao; private static TimeZone usageAggregationTimeZone = TimeZone.getTimeZone("GMT"); static final BigDecimal GiB_DECIMAL = BigDecimal.valueOf(ByteScaleUtils.GiB); @@ -340,12 +349,41 @@ protected List createQuotaUsagesAccordingToQuotaTariffs(AccountVO } protected boolean shouldCalculateUsageRecord(AccountVO accountVO, UsageVO usageRecord) { - if (Boolean.FALSE.equals(QuotaConfig.QuotaAccountEnabled.valueIn(accountVO.getAccountId()))) { + boolean calculateUsageRecord = findConfigurationValue(accountVO, QuotaConfig.QuotaAccountEnabled); + if (!calculateUsageRecord && usageRecord != null) { logger.debug("Considering usage record [{}] as calculated and skipping it because account [{}] has the quota plugin disabled.", usageRecord.toString(usageAggregationTimeZone), accountVO.reflectionToString()); return false; } - return true; + return calculateUsageRecord; + } + + @Override + public boolean findConfigurationValue(AccountVO accountVO, ConfigKey key) { + boolean result = Boolean.parseBoolean(getConfigValueOrDefaultValue(key)); + logger.trace("Searching configuration [{}] of account [{}] in its settings.", key.key(), accountVO); + AccountDetailVO accountDetail = accountDetailsDao.findDetail(accountVO.getAccountId(), key.key()); + if (accountDetail != null) { + result = Boolean.TRUE.equals(Boolean.valueOf(accountDetail.getValue())); + logger.trace("Using value [{}] found in account [{}] settings to configuration [{}].", result, accountVO, key.key()); + return result; + } + + if (Boolean.parseBoolean(_configDao.getValue("enable.account.settings.for.domain"))) { + logger.trace("Searching for configuration [{}] of account [{}] in its domain [{}] settings.", key.key(), accountVO, accountVO.getDomainId()); + DomainDetailVO domainDetail = domainDetailsDao.findDetail(accountVO.getDomainId(), key.key()); + if (domainDetail != null) { + result = Boolean.TRUE.equals(Boolean.valueOf(domainDetail.getValue())); + logger.trace("Using value [{}] found in domain [{}] settings to configuration [{}].", result, accountVO.getDomainId(), key.key()); + return result; + } + } + logger.trace("Using default value [{}] to configuration [{}].", result, key.key()); + return result; + } + + protected String getConfigValueOrDefaultValue(ConfigKey key) { + return ObjectUtils.defaultIfNull(_configDao.getValue(key.key()), key.defaultValue()); } protected List persistUsagesAndQuotaUsagesAndRetrievePersistedQuotaUsages(List> pairsUsageAndQuotaUsage) { diff --git a/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaAlertManagerImplTest.java b/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaAlertManagerImplTest.java index 54d4f1d5b690..98a67d8e62ce 100644 --- a/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaAlertManagerImplTest.java +++ b/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaAlertManagerImplTest.java @@ -116,9 +116,6 @@ public void setup() throws IllegalAccessException, NoSuchFieldException, Configu @Test public void isQuotaEmailTypeEnabledForAccountTestConfigurationIsEnabledAndEmailIsConfiguredReturnConfiguredValue() { boolean expectedValue = !QuotaConfig.QuotaEnableEmails.value(); - QuotaEmailConfigurationVO quotaEmailConfigurationVoMock = Mockito.mock(QuotaEmailConfigurationVO.class); - Mockito.when(quotaEmailConfigurationVoMock.isEnabled()).thenReturn(expectedValue); - Mockito.doReturn(quotaEmailConfigurationVoMock).when(quotaEmailConfigurationDaoMock).findByAccountIdAndEmailTemplateType(Mockito.anyLong(), Mockito.any(QuotaConfig.QuotaEmailTemplateTypes.class)); boolean result = quotaAlertManager.isQuotaEmailTypeEnabledForAccount(accountMock, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_EMPTY); @@ -129,6 +126,8 @@ public void isQuotaEmailTypeEnabledForAccountTestConfigurationIsEnabledAndEmailI public void isQuotaEmailTypeEnabledForAccountTestConfigurationIsEnabledAndEmailIsNotConfiguredReturnDefaultValue() { boolean defaultValue = QuotaConfig.QuotaEnableEmails.value(); + Mockito.when(quotaManagerMock.findConfigurationValue(accountMock, QuotaConfig.QuotaEnableEmails)).thenReturn(true); + boolean result = quotaAlertManager.isQuotaEmailTypeEnabledForAccount(accountMock, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_EMPTY); Assert.assertEquals(defaultValue, result); From a6993efbac84825a8a914137aa1ef9ad4656e78c Mon Sep 17 00:00:00 2001 From: Julien Hervot de Mattos Vaz Date: Wed, 23 Apr 2025 10:22:23 -0300 Subject: [PATCH 2/4] Remove unused imports --- .../org/apache/cloudstack/quota/QuotaAlertManagerImplTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaAlertManagerImplTest.java b/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaAlertManagerImplTest.java index 98a67d8e62ce..4259c355de64 100644 --- a/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaAlertManagerImplTest.java +++ b/framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaAlertManagerImplTest.java @@ -33,7 +33,6 @@ import org.apache.cloudstack.quota.dao.QuotaEmailConfigurationDaoImpl; import org.apache.cloudstack.quota.dao.QuotaEmailTemplatesDao; import org.apache.cloudstack.quota.vo.QuotaAccountVO; -import org.apache.cloudstack.quota.vo.QuotaEmailConfigurationVO; import org.apache.cloudstack.quota.vo.QuotaEmailTemplatesVO; import org.junit.Assert; import org.junit.Before; From 2dc5715ba34ba0a590044b72feb09af546d675f2 Mon Sep 17 00:00:00 2001 From: julien-vaz <54545601+julien-vaz@users.noreply.github.com> Date: Wed, 4 Jun 2025 14:10:06 -0300 Subject: [PATCH 3/4] Apply suggestions from code review Co-authored-by: Fabricio Duarte --- .../java/org/apache/cloudstack/quota/QuotaManagerImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java index be9ef110bd7c..2a17900698d1 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java @@ -364,7 +364,7 @@ public boolean findConfigurationValue(AccountVO accountVO, ConfigKey ke logger.trace("Searching configuration [{}] of account [{}] in its settings.", key.key(), accountVO); AccountDetailVO accountDetail = accountDetailsDao.findDetail(accountVO.getAccountId(), key.key()); if (accountDetail != null) { - result = Boolean.TRUE.equals(Boolean.valueOf(accountDetail.getValue())); + result = Boolean.parseBoolean(accountDetail.getValue()); logger.trace("Using value [{}] found in account [{}] settings to configuration [{}].", result, accountVO, key.key()); return result; } @@ -373,7 +373,7 @@ public boolean findConfigurationValue(AccountVO accountVO, ConfigKey ke logger.trace("Searching for configuration [{}] of account [{}] in its domain [{}] settings.", key.key(), accountVO, accountVO.getDomainId()); DomainDetailVO domainDetail = domainDetailsDao.findDetail(accountVO.getDomainId(), key.key()); if (domainDetail != null) { - result = Boolean.TRUE.equals(Boolean.valueOf(domainDetail.getValue())); + result = Boolean.parseBoolean(domainDetail.getValue()); logger.trace("Using value [{}] found in domain [{}] settings to configuration [{}].", result, accountVO.getDomainId(), key.key()); return result; } From 617d2323c4eef76ea197b11c737642720fa8f0bf Mon Sep 17 00:00:00 2001 From: Julien Hervot de Mattos Vaz Date: Wed, 4 Jun 2025 14:17:10 -0300 Subject: [PATCH 4/4] Move DB access to end of method --- .../java/org/apache/cloudstack/quota/QuotaManagerImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java index 2a17900698d1..be892785a5c2 100644 --- a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java +++ b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java @@ -360,11 +360,10 @@ protected boolean shouldCalculateUsageRecord(AccountVO accountVO, UsageVO usageR @Override public boolean findConfigurationValue(AccountVO accountVO, ConfigKey key) { - boolean result = Boolean.parseBoolean(getConfigValueOrDefaultValue(key)); logger.trace("Searching configuration [{}] of account [{}] in its settings.", key.key(), accountVO); AccountDetailVO accountDetail = accountDetailsDao.findDetail(accountVO.getAccountId(), key.key()); if (accountDetail != null) { - result = Boolean.parseBoolean(accountDetail.getValue()); + boolean result = Boolean.parseBoolean(accountDetail.getValue()); logger.trace("Using value [{}] found in account [{}] settings to configuration [{}].", result, accountVO, key.key()); return result; } @@ -373,11 +372,12 @@ public boolean findConfigurationValue(AccountVO accountVO, ConfigKey ke logger.trace("Searching for configuration [{}] of account [{}] in its domain [{}] settings.", key.key(), accountVO, accountVO.getDomainId()); DomainDetailVO domainDetail = domainDetailsDao.findDetail(accountVO.getDomainId(), key.key()); if (domainDetail != null) { - result = Boolean.parseBoolean(domainDetail.getValue()); + boolean result = Boolean.parseBoolean(domainDetail.getValue()); logger.trace("Using value [{}] found in domain [{}] settings to configuration [{}].", result, accountVO.getDomainId(), key.key()); return result; } } + boolean result = Boolean.parseBoolean(getConfigValueOrDefaultValue(key)); logger.trace("Using default value [{}] to configuration [{}].", result, key.key()); return result; }