Skip to content
Open
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
4 changes: 4 additions & 0 deletions api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,8 @@ public class ApiConstants {
public static final String SUITABLE_FOR_VM = "suitableforvirtualmachine";
public static final String SUPPORTS_STORAGE_SNAPSHOT = "supportsstoragesnapshot";
public static final String TARGET_IQN = "targetiqn";
public static final String TARIFF_ID = "tariffid";
public static final String TARIFF_NAME = "tariffname";
public static final String TASKS_FILTER = "tasksfilter";
public static final String TEMPLATE_FILTER = "templatefilter";
public static final String TEMPLATE_ID = "templateid";
Expand Down Expand Up @@ -655,6 +657,7 @@ public class ApiConstants {
public static final String VIRTUAL_MACHINE_STATE = "vmstate";
public static final String VIRTUAL_MACHINES = "virtualmachines";
public static final String USAGE_ID = "usageid";
public static final String USAGE_NAME = "usagename";
public static final String USAGE_TYPE = "usagetype";
public static final String INCLUDE_TAGS = "includetags";

Expand Down Expand Up @@ -871,6 +874,7 @@ public class ApiConstants {
public static final String IS_SOURCE_NAT = "issourcenat";
public static final String IS_STATIC_NAT = "isstaticnat";
public static final String ITERATIONS = "iterations";
public static final String ITEMS = "items";
public static final String SORT_BY = "sortby";
public static final String CHANGE_CIDR = "changecidr";
public static final String PURPOSE = "purpose";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,9 @@ SELECT 'Advanced', 'DEFAULT', 'CapacityManager', 'kvm.cpu.dynamic.scaling.capaci
FROM `cloud`.`configuration` `cfg`
WHERE NOT EXISTS (SELECT 1 FROM `cloud`.`configuration` WHERE `name` = 'kvm.cpu.dynamic.scaling.capacity')
AND `cfg`.`name` = 'vm.serviceoffering.cpu.cores.max';

--- Quota resource statement
INSERT INTO cloud.role_permissions (uuid, role_id, rule, permission, sort_order)
SELECT uuid(), role_id, 'quotaResourceStatement', permission, sort_order
FROM cloud.role_permissions rp
WHERE rule = 'quotaStatement' AND NOT EXISTS(SELECT 1 FROM cloud.role_permissions rp_ WHERE rp.role_id = rp_.role_id AND rp_.rule = 'quotaResourceStatement');
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
Expand All @@ -43,9 +44,11 @@
import org.apache.cloudstack.quota.dao.QuotaAccountDao;
import org.apache.cloudstack.quota.dao.QuotaBalanceDao;
import org.apache.cloudstack.quota.dao.QuotaTariffDao;
import org.apache.cloudstack.quota.dao.QuotaTariffUsageDao;
import org.apache.cloudstack.quota.dao.QuotaUsageDao;
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
import org.apache.cloudstack.quota.vo.QuotaTariffUsageVO;
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
import org.apache.cloudstack.usage.UsageUnitTypes;
Expand Down Expand Up @@ -86,7 +89,8 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager {
private QuotaBalanceDao _quotaBalanceDao;
@Inject
private ConfigurationDao _configDao;

@Inject
private QuotaTariffUsageDao quotaTariffUsageDao;
@Inject
protected PresetVariableHelper presetVariableHelper;

Expand Down Expand Up @@ -310,33 +314,46 @@ protected List<QuotaUsageVO> createQuotaUsagesAccordingToQuotaTariffs(AccountVO
String accountToString = account.reflectionToString();
logger.info("Calculating quota usage of [{}] usage records for account [{}].", usageRecords.size(), accountToString);

List<Pair<UsageVO, QuotaUsageVO>> pairsUsageAndQuotaUsage = new ArrayList<>();
Map<UsageVO, Pair<QuotaUsageVO, List<QuotaTariffUsageVO>>> mapUsageAndQuotaUsage = new LinkedHashMap<>();

try (JsInterpreter jsInterpreter = new JsInterpreter(QuotaConfig.QuotaActivationRuleTimeout.value())) {
for (UsageVO usageRecord : usageRecords) {
int usageType = usageRecord.getUsageType();

if (!shouldCalculateUsageRecord(account, usageRecord)) {
pairsUsageAndQuotaUsage.add(new Pair<>(usageRecord, null));
mapUsageAndQuotaUsage.put(usageRecord, null);
continue;
}

Pair<List<QuotaTariffVO>, Boolean> pairQuotaTariffsPerUsageTypeAndHasActivationRule = mapQuotaTariffsPerUsageType.get(usageType);
List<QuotaTariffVO> quotaTariffs = pairQuotaTariffsPerUsageTypeAndHasActivationRule.first();
boolean hasAnyQuotaTariffWithActivationRule = pairQuotaTariffsPerUsageTypeAndHasActivationRule.second();

BigDecimal aggregatedQuotaTariffsValue = aggregateQuotaTariffsValues(usageRecord, quotaTariffs, hasAnyQuotaTariffWithActivationRule, jsInterpreter, accountToString);
Map<QuotaTariffVO, BigDecimal> aggregatedQuotaTariffsAndValues = aggregateQuotaTariffsValues(usageRecord,
quotaTariffs, hasAnyQuotaTariffWithActivationRule, jsInterpreter, accountToString);
BigDecimal aggregatedQuotaTariffsValue = aggregatedQuotaTariffsAndValues.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
logger.debug("The aggregation of the quota tariffs of account [{}] resulted in [{}] for the usage record [{}].",
account, aggregatedQuotaTariffsValue, usageRecord);

QuotaUsageVO quotaUsage = createQuotaUsageAccordingToUsageUnit(usageRecord, aggregatedQuotaTariffsValue, accountToString);
if (quotaUsage == null) {
mapUsageAndQuotaUsage.put(usageRecord, null);
continue;
}

pairsUsageAndQuotaUsage.add(new Pair<>(usageRecord, quotaUsage));
List<QuotaTariffUsageVO> quotaTariffUsages = new ArrayList<>();
for (Map.Entry<QuotaTariffVO, BigDecimal> entry : aggregatedQuotaTariffsAndValues.entrySet()) {
QuotaTariffUsageVO quotaTariffUsage = createQuotaTariffUsage(usageRecord, entry.getKey(), entry.getValue());
quotaTariffUsages.add(quotaTariffUsage);
}
mapUsageAndQuotaUsage.put(usageRecord, new Pair<>(quotaUsage, quotaTariffUsages));
}
} catch (Exception e) {
logger.error(String.format("Failed to calculate the quota usage for account [%s] due to [%s].", accountToString, e.getMessage()), e);
return new ArrayList<>();
}

return persistUsagesAndQuotaUsagesAndRetrievePersistedQuotaUsages(pairsUsageAndQuotaUsage);
return persistUsagesAndQuotaUsagesAndRetrievePersistedQuotaUsages(mapUsageAndQuotaUsage);
}

protected boolean shouldCalculateUsageRecord(AccountVO accountVO, UsageVO usageRecord) {
Expand All @@ -348,31 +365,41 @@ protected boolean shouldCalculateUsageRecord(AccountVO accountVO, UsageVO usageR
return true;
}

protected List<QuotaUsageVO> persistUsagesAndQuotaUsagesAndRetrievePersistedQuotaUsages(List<Pair<UsageVO, QuotaUsageVO>> pairsUsageAndQuotaUsage) {
List<QuotaUsageVO> quotaUsages = new ArrayList<>();
protected List<QuotaUsageVO> persistUsagesAndQuotaUsagesAndRetrievePersistedQuotaUsages(Map<UsageVO, Pair<QuotaUsageVO, List<QuotaTariffUsageVO>>> mapUsageAndQuotaTariffUsage) {
List<QuotaUsageVO> quotaUsages = new ArrayList<>(); // TODO: isso tem que ser em uma transação

for (Pair<UsageVO, QuotaUsageVO> pairUsageAndQuotaUsage : pairsUsageAndQuotaUsage) {
UsageVO usageVo = pairUsageAndQuotaUsage.first();
for (Map.Entry<UsageVO, Pair<QuotaUsageVO, List<QuotaTariffUsageVO>>> usageAndTariffUsage : mapUsageAndQuotaTariffUsage.entrySet()) {
UsageVO usageVo = usageAndTariffUsage.getKey();
usageVo.setQuotaCalculated(1);
_usageDao.persistUsage(usageVo);

QuotaUsageVO quotaUsageVo = pairUsageAndQuotaUsage.second();
if (quotaUsageVo != null) {
_quotaUsageDao.persistQuotaUsage(quotaUsageVo);
quotaUsages.add(quotaUsageVo);
Pair<QuotaUsageVO, List<QuotaTariffUsageVO>> pairUsageAndTariffUsages = usageAndTariffUsage.getValue();
if (pairUsageAndTariffUsages != null) {
QuotaUsageVO quotaUsage = pairUsageAndTariffUsages.first();
_quotaUsageDao.persistQuotaUsage(quotaUsage);
quotaUsages.add(quotaUsage);

persistQuotaTariffUsages(pairUsageAndTariffUsages.second(), quotaUsage.getId());
}
}

return quotaUsages;
}

protected BigDecimal aggregateQuotaTariffsValues(UsageVO usageRecord, List<QuotaTariffVO> quotaTariffs, boolean hasAnyQuotaTariffWithActivationRule,
JsInterpreter jsInterpreter, String accountToString) {
protected void persistQuotaTariffUsages(List<QuotaTariffUsageVO> quotaTariffUsages, Long quotaUsageId) {
for (QuotaTariffUsageVO quotaTariffUsage : quotaTariffUsages) {
quotaTariffUsage.setQuotaUsageId(quotaUsageId);
quotaTariffUsageDao.persistQuotaTariffUsage(quotaTariffUsage);
}
}

protected Map<QuotaTariffVO, BigDecimal> aggregateQuotaTariffsValues(UsageVO usageRecord, List<QuotaTariffVO> quotaTariffs, boolean hasAnyQuotaTariffWithActivationRule,
JsInterpreter jsInterpreter, String accountToString) {
String usageRecordToString = usageRecord.toString(usageAggregationTimeZone);
logger.debug("Validating usage record [{}] for account [{}] against [{}] quota tariffs.", usageRecordToString, accountToString, quotaTariffs.size());

PresetVariables presetVariables = getPresetVariables(hasAnyQuotaTariffWithActivationRule, usageRecord);
BigDecimal aggregatedQuotaTariffsValue = BigDecimal.ZERO;
Map<QuotaTariffVO, BigDecimal> aggregatedQuotaTariffsAndValues = new HashMap<>();

quotaTariffs.sort(Comparator.comparing(QuotaTariffVO::getPosition));

Expand All @@ -381,10 +408,9 @@ protected BigDecimal aggregateQuotaTariffsValues(UsageVO usageRecord, List<Quota

for (QuotaTariffVO quotaTariff : quotaTariffs) {
if (isQuotaTariffInPeriodToBeApplied(usageRecord, quotaTariff, accountToString)) {

BigDecimal tariffValue = getQuotaTariffValueToBeApplied(quotaTariff, jsInterpreter, presetVariables, lastTariffs);

aggregatedQuotaTariffsValue = aggregatedQuotaTariffsValue.add(tariffValue);
aggregatedQuotaTariffsAndValues.put(quotaTariff, tariffValue);

Tariff tariffPresetVariable = new Tariff();
tariffPresetVariable.setId(quotaTariff.getUuid());
Expand All @@ -393,10 +419,10 @@ protected BigDecimal aggregateQuotaTariffsValues(UsageVO usageRecord, List<Quota
}
}

logger.debug(String.format("The aggregation of the quota tariffs resulted in the value [%s] for the usage record [%s]. We will use this value to calculate the final"
+ " usage value.", aggregatedQuotaTariffsValue, usageRecordToString));
logger.debug("The aggregation of the quota tariffs resulted in [{}] quota tariffs for the usage record [{}]. The values of the quota tariffs will be used"
+ " to calculate the final usage value.", aggregatedQuotaTariffsAndValues.size(), usageRecordToString);

return aggregatedQuotaTariffsValue;
return aggregatedQuotaTariffsAndValues;
}

protected PresetVariables getPresetVariables(boolean hasAnyQuotaTariffWithActivationRule, UsageVO usageRecord) {
Expand All @@ -407,6 +433,26 @@ protected PresetVariables getPresetVariables(boolean hasAnyQuotaTariffWithActiva
return null;
}

protected QuotaTariffUsageVO createQuotaTariffUsage(UsageVO usageRecord, QuotaTariffVO quotaTariff, BigDecimal quotaTariffValue) {
BigDecimal quotaUsageValue = BigDecimal.ZERO;

if (!quotaTariffValue.equals(BigDecimal.ZERO)) {
String quotaUnit = QuotaTypes.getQuotaType(usageRecord.getUsageType()).getQuotaUnit();
logger.trace("Calculating the value of the quota tariff [{}] according to its value [{}] and its quota unit [{}].", quotaTariff, quotaTariffValue, quotaUnit);
quotaUsageValue = getUsageValueAccordingToUsageUnitType(usageRecord, quotaTariffValue, quotaUnit);
logger.debug("The calculation of the value of the quota tariff [{}] according to its value [{}] and its usage unit [{}] resulted in the value [{}].",
quotaTariff, quotaTariffValue, quotaUnit, quotaUsageValue);
} else {
logger.debug("Quota tariff [{}] has no value to be calculated; therefore, it will be marked as value zero.", quotaTariff);
}

QuotaTariffUsageVO quotaTariffUsage = new QuotaTariffUsageVO();
quotaTariffUsage.setTariffId(quotaTariff.getId());
quotaTariffUsage.setQuotaUsed(quotaUsageValue);

return quotaTariffUsage;
}

/**
* Returns the quota tariff value according to the result of the activation rule.<br/>
* <ul>
Expand Down
Loading
Loading