Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -320,9 +320,7 @@ protected List<QuotaUsageVO> createQuotaUsagesAccordingToQuotaTariffs(AccountVO
for (UsageVO usageRecord : usageRecords) {
int usageType = usageRecord.getUsageType();

if (usageTypesToAvoidCalculation.contains(usageType)) {
s_logger.debug(String.format("Considering usage record [%s] as calculated and skipping it because the calculation of the types [%s] has not been implemented yet.",
usageRecord.toString(), usageTypesToAvoidCalculation));
if (Boolean.FALSE.equals(shouldCalculateUsageRecord(account,usageRecord))) {
pairsUsageAndQuotaUsage.add(new Pair<>(usageRecord, null));
continue;
}
Expand All @@ -345,6 +343,21 @@ protected List<QuotaUsageVO> createQuotaUsagesAccordingToQuotaTariffs(AccountVO
return persistUsagesAndQuotaUsagesAndRetrievePersistedQuotaUsages(pairsUsageAndQuotaUsage);
}

protected boolean shouldCalculateUsageRecord(AccountVO accountVO, UsageVO usageRecord) {
if (usageTypesToAvoidCalculation.contains(usageRecord.getUsageType())) {
s_logger.debug(String.format("Considering usage record [%s] as calculated and skipping it because the calculation of the types [%s] has not been implemented yet.",
usageRecord, usageTypesToAvoidCalculation));
return false;
}

if (Boolean.FALSE.equals(QuotaConfig.QuotaAccountEnabled.valueIn(accountVO.getAccountId()))) {
s_logger.debug(String.format("Considering usage record [%s] as calculated and skipping it because account [%s] has the quota plugin disabled.",
usageRecord, accountVO.reflectionToString()));
return false;
}
return true;
}

protected List<QuotaUsageVO> persistUsagesAndQuotaUsagesAndRetrievePersistedQuotaUsages(List<Pair<UsageVO, QuotaUsageVO>> pairsUsageAndQuotaUsage) {
List<QuotaUsageVO> quotaUsages = new ArrayList<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ public interface QuotaConfig {
public static final ConfigKey<Long> QuotaActivationRuleTimeout = new ConfigKey<>("Advanced", Long.class, "quota.activationrule.timeout", "2000", "The maximum runtime,"
+ " in milliseconds, to execute the quota tariff's activation rule; if it is reached, a timeout will happen.", true);

ConfigKey<Boolean> QuotaAccountEnabled = new ConfigKey<>("Advanced", Boolean.class, "quota.account.enabled", "true", "Indicates whether Quota plugin is enabled or not for " +
"the account.", true, ConfigKey.Scope.Account);

enum QuotaEmailTemplateTypes {
QUOTA_LOW, QUOTA_EMPTY, QUOTA_UNLOCK_ACCOUNT, QUOTA_STATEMENT
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
//under the License.
package org.apache.cloudstack.quota.dao;

import java.util.ArrayList;
import java.util.List;

import org.apache.cloudstack.quota.constant.QuotaConfig;
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
Expand All @@ -36,7 +38,15 @@ public class QuotaAccountDaoImpl extends GenericDaoBase<QuotaAccountVO, Long> im

@Override
public List<QuotaAccountVO> listAllQuotaAccount() {
return listAllQuotaAccount(null, null).first();
List<QuotaAccountVO> accountsWithQuotaEnabled = new ArrayList<>();
for (QuotaAccountVO account : listAllQuotaAccount(null, null).first()) {
if (Boolean.TRUE.equals(getQuotaAccountEnabled(account.getAccountId()))) {
Comment thread
BryanMLima marked this conversation as resolved.
accountsWithQuotaEnabled.add(account);
continue;
}
s_logger.trace(String.format("Account [%s] has the quota plugin disabled. Thus, it will not receive quota emails.", account));
}
return accountsWithQuotaEnabled;
}

@Override
Expand Down Expand Up @@ -80,4 +90,7 @@ public Boolean doInTransaction(final TransactionStatus status) {
});
}

public Boolean getQuotaAccountEnabled(Long accountId) {
return QuotaConfig.QuotaAccountEnabled.valueIn(accountId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package org.apache.cloudstack.quota.dao;

import com.cloud.utils.Pair;
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;

import java.util.List;

@RunWith(MockitoJUnitRunner.class)
public class QuotaAccountDaoImplTest {
@Spy
QuotaAccountDaoImpl quotaAccountDaoImplSpy;

@Test
public void listAllQuotaAccountTestShouldReturnNullWithAccountWithQuotaDisabled() {
QuotaAccountVO accountWithQuotaDisabled = new QuotaAccountVO(1L);

List<QuotaAccountVO> allQuotaAccounts = List.of(accountWithQuotaDisabled);
Pair<List<QuotaAccountVO>,Integer> pair = new Pair<>(allQuotaAccounts, 1);

Mockito.doReturn(pair).when(quotaAccountDaoImplSpy).listAllQuotaAccount(null, null);
Mockito.doReturn(false).when(quotaAccountDaoImplSpy).getQuotaAccountEnabled(accountWithQuotaDisabled.getAccountId());

int expected = quotaAccountDaoImplSpy.listAllQuotaAccount().size();
Assert.assertEquals(0, expected);
}

@Test
public void listAllQuotaAccountTestShouldReturnSizeOneWithAccountWithQuotaEnabled() {
QuotaAccountVO accountWithQuotaEnabled = new QuotaAccountVO(2L);

List<QuotaAccountVO> allQuotaAccounts = List.of(accountWithQuotaEnabled);
Pair<List<QuotaAccountVO>,Integer> pair = new Pair<>(allQuotaAccounts, 1);

Mockito.doReturn(pair).when(quotaAccountDaoImplSpy).listAllQuotaAccount(null, null);
Mockito.doReturn(true).when(quotaAccountDaoImplSpy).getQuotaAccountEnabled(accountWithQuotaEnabled.getAccountId());

int expected = quotaAccountDaoImplSpy.listAllQuotaAccount().size();
Assert.assertEquals(1, expected);
}

@Test
public void listAllQuotaAccountTestShouldReturnOnlyAccountsWithQuotaEnabled() {
QuotaAccountVO accountWithQuotaEnabled = new QuotaAccountVO(1L);
QuotaAccountVO accountWithQuotaDisabled = new QuotaAccountVO(2L);

List<QuotaAccountVO> allQuotaAccounts = List.of(accountWithQuotaEnabled, accountWithQuotaDisabled);
Pair<List<QuotaAccountVO>,Integer> pair = new Pair<>(allQuotaAccounts, 1);

Mockito.doReturn(pair).when(quotaAccountDaoImplSpy).listAllQuotaAccount(null, null);
Mockito.doReturn(true).when(quotaAccountDaoImplSpy).getQuotaAccountEnabled(accountWithQuotaEnabled.getAccountId());
Mockito.doReturn(false).when(quotaAccountDaoImplSpy).getQuotaAccountEnabled(accountWithQuotaDisabled.getAccountId());

int expected = quotaAccountDaoImplSpy.listAllQuotaAccount().size();
Assert.assertEquals(1, expected);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ public class QuotaSummaryResponse extends BaseResponse {
@Param(description = "currency")
private String currency;

@SerializedName("quotaenabled")
@Param(description = "if the account has the quota config enabled")
private boolean quotaEnabled;

public QuotaSummaryResponse() {
super();
}
Expand Down Expand Up @@ -152,4 +156,12 @@ public String getCurrency() {
public void setCurrency(String currency) {
this.currency = currency;
}

public boolean getQuotaEnabled() {
return quotaEnabled;
}

public void setQuotaEnabled(boolean quotaEnabled) {
this.quotaEnabled = quotaEnabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public String getConfigComponentName() {
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {QuotaPluginEnabled, QuotaEnableEnforcement, QuotaCurrencySymbol, QuotaStatementPeriod, QuotaSmtpHost, QuotaSmtpPort, QuotaSmtpTimeout,
QuotaSmtpUser, QuotaSmtpPassword, QuotaSmtpAuthType, QuotaSmtpSender, QuotaSmtpEnabledSecurityProtocols, QuotaSmtpUseStartTLS, QuotaActivationRuleTimeout};
QuotaSmtpUser, QuotaSmtpPassword, QuotaSmtpAuthType, QuotaSmtpSender, QuotaSmtpEnabledSecurityProtocols, QuotaSmtpUseStartTLS, QuotaActivationRuleTimeout, QuotaAccountEnabled};
}

@Override
Expand Down
2 changes: 2 additions & 0 deletions ui/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"label.account.name": "Account name",
"label.account.specific": "Account-specific",
"label.accounts": "Accounts",
"label.accountstate": "Account state",
"label.accounttype": "Account type",
"label.acl.export": "Export ACLs",
"label.acl.id": "ACL ID",
Expand Down Expand Up @@ -1361,6 +1362,7 @@
"label.quota.type.unit": "Usage unit",
"label.quota.usage": "Quota consumption",
"label.quota.value": "Quota value",
"label.quotastate": "Quota state",
"label.quota_enforce": "Enforce Quota",
"label.rados.monitor": "RADOS monitor",
"label.rados.monitor.description": "The RADOS monitor(s). If there are multiple monitors, they are separated by comma. For example, \"192.168.0.1,192.168.0.2,192.168.0.3\", \"mon1, mon2, mon3\". IPv6 addresses must include square brackets, for example, \"[fc00:1234::1],[fc00:1234::2],[fc00:1234::3]\".",
Expand Down
2 changes: 2 additions & 0 deletions ui/public/locales/pt_BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"label.account.name": "Nome da conta",
"label.account.specific": "Espec\u00edfico da conta",
"label.accounts": "Contas",
"label.accountstate": "Estado da conta",
"label.accounttype": "Tipo de conta",
"label.acl.export": "Exportar ACLs",
"label.acl.id": "ACL ID",
Expand Down Expand Up @@ -1267,6 +1268,7 @@
"label.quota.statement.quota": "Utiliza\u00e7\u00e3o",
"label.quota.statement.tariff": "Tarifa",
"label.quota.summary": "Relat\u00f3rios",
"label.quotastate": "Estado da cota",
"label.summary": "Sum\u00e1rio",
"label.quota.tariff": "Tarifa",
"label.quota.tariff.effectivedate": "Data efetiva",
Expand Down
3 changes: 3 additions & 0 deletions ui/src/components/view/ListView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@
<template #agentstate="{ text }">
<status :text="text ? text : ''" displayText />
</template>
<template #quotastate="{ text }">
<status :text="text ? text : ''" displayText />
</template>
<template #vlan="{ text, record }">
<a href="javascript:;">
<router-link v-if="$route.path === '/guestvlans'" :to="{ path: '/guestvlans/' + record.id }">{{ text }}</router-link>
Expand Down
10 changes: 9 additions & 1 deletion ui/src/config/section/plugin/quota.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,15 @@ export default {
title: 'label.quota.summary',
icon: 'bars-outlined',
permission: ['quotaSummary'],
columns: ['account', 'domain', 'state', 'currency', 'balance', 'quota'],
columns: ['account',
{
state: (record) => record.state.toLowerCase()
},
{
quotastate: (record) => record.quotaenabled ? 'Enabled' : 'Disabled'
}, 'domain', 'currency', 'balance'
],
columnNames: ['account', 'accountstate', 'quotastate', 'domain', 'currency', 'currentbalance'],
details: ['account', 'domain', 'state', 'currency', 'balance', 'quota', 'startdate', 'enddate'],
component: shallowRef(() => import('@/views/plugins/quota/QuotaSummary.vue')),
tabs: [
Expand Down