Skip to content

Commit af17bc9

Browse files
committed
Introduce Quota resource statement API
1 parent e1521f1 commit af17bc9

18 files changed

Lines changed: 771 additions & 201 deletions

File tree

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,8 @@ public class ApiConstants {
595595
public static final String SUITABLE_FOR_VM = "suitableforvirtualmachine";
596596
public static final String SUPPORTS_STORAGE_SNAPSHOT = "supportsstoragesnapshot";
597597
public static final String TARGET_IQN = "targetiqn";
598+
public static final String TARIFF_ID = "tariffid";
599+
public static final String TARIFF_NAME = "tariffname";
598600
public static final String TASKS_FILTER = "tasksfilter";
599601
public static final String TEMPLATE_FILTER = "templatefilter";
600602
public static final String TEMPLATE_ID = "templateid";
@@ -655,6 +657,7 @@ public class ApiConstants {
655657
public static final String VIRTUAL_MACHINE_STATE = "vmstate";
656658
public static final String VIRTUAL_MACHINES = "virtualmachines";
657659
public static final String USAGE_ID = "usageid";
660+
public static final String USAGE_NAME = "usagename";
658661
public static final String USAGE_TYPE = "usagetype";
659662
public static final String INCLUDE_TAGS = "includetags";
660663

@@ -871,6 +874,7 @@ public class ApiConstants {
871874
public static final String IS_SOURCE_NAT = "issourcenat";
872875
public static final String IS_STATIC_NAT = "isstaticnat";
873876
public static final String ITERATIONS = "iterations";
877+
public static final String ITEMS = "items";
874878
public static final String SORT_BY = "sortby";
875879
public static final String CHANGE_CIDR = "changecidr";
876880
public static final String PURPOSE = "purpose";

engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,9 @@ CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_tariff_usage` (
131131
-- Add the 'keep_mac_address_on_public_nic' column to the 'cloud.networks' and 'cloud.vpc' tables
132132
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.networks', 'keep_mac_address_on_public_nic', 'TINYINT(1) NOT NULL DEFAULT 1');
133133
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc', 'keep_mac_address_on_public_nic', 'TINYINT(1) NOT NULL DEFAULT 1');
134+
135+
--- Quota resource statement
136+
INSERT INTO cloud.role_permissions (uuid, role_id, rule, permission, sort_order)
137+
SELECT uuid(), role_id, 'quotaResourceStatement', permission, sort_order
138+
FROM cloud.role_permissions rp
139+
WHERE rule = 'quotaStatement' AND NOT EXISTS(SELECT 1 FROM cloud.role_permissions rp_ WHERE rp.role_id = rp_.role_id AND rp_.rule = 'quotaResourceStatement');

framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java

Lines changed: 68 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.Comparator;
2424
import java.util.Date;
2525
import java.util.HashMap;
26+
import java.util.LinkedHashMap;
2627
import java.util.LinkedHashSet;
2728
import java.util.List;
2829
import java.util.Map;
@@ -43,9 +44,11 @@
4344
import org.apache.cloudstack.quota.dao.QuotaAccountDao;
4445
import org.apache.cloudstack.quota.dao.QuotaBalanceDao;
4546
import org.apache.cloudstack.quota.dao.QuotaTariffDao;
47+
import org.apache.cloudstack.quota.dao.QuotaTariffUsageDao;
4648
import org.apache.cloudstack.quota.dao.QuotaUsageDao;
4749
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
4850
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
51+
import org.apache.cloudstack.quota.vo.QuotaTariffUsageVO;
4952
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
5053
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
5154
import org.apache.cloudstack.usage.UsageUnitTypes;
@@ -86,7 +89,8 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager {
8689
private QuotaBalanceDao _quotaBalanceDao;
8790
@Inject
8891
private ConfigurationDao _configDao;
89-
92+
@Inject
93+
private QuotaTariffUsageDao quotaTariffUsageDao;
9094
@Inject
9195
protected PresetVariableHelper presetVariableHelper;
9296

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

313-
List<Pair<UsageVO, QuotaUsageVO>> pairsUsageAndQuotaUsage = new ArrayList<>();
317+
Map<UsageVO, Pair<QuotaUsageVO, List<QuotaTariffUsageVO>>> mapUsageAndQuotaUsage = new LinkedHashMap<>();
314318

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

319323
if (!shouldCalculateUsageRecord(account, usageRecord)) {
320-
pairsUsageAndQuotaUsage.add(new Pair<>(usageRecord, null));
324+
mapUsageAndQuotaUsage.put(usageRecord, null);
321325
continue;
322326
}
323327

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

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

330338
QuotaUsageVO quotaUsage = createQuotaUsageAccordingToUsageUnit(usageRecord, aggregatedQuotaTariffsValue, accountToString);
339+
if (quotaUsage == null) {
340+
mapUsageAndQuotaUsage.put(usageRecord, null);
341+
continue;
342+
}
331343

332-
pairsUsageAndQuotaUsage.add(new Pair<>(usageRecord, quotaUsage));
344+
List<QuotaTariffUsageVO> quotaTariffUsages = new ArrayList<>();
345+
for (Map.Entry<QuotaTariffVO, BigDecimal> entry : aggregatedQuotaTariffsAndValues.entrySet()) {
346+
QuotaTariffUsageVO quotaTariffUsage = createQuotaTariffUsage(usageRecord, entry.getKey(), entry.getValue());
347+
quotaTariffUsages.add(quotaTariffUsage);
348+
}
349+
mapUsageAndQuotaUsage.put(usageRecord, new Pair<>(quotaUsage, quotaTariffUsages));
333350
}
334351
} catch (Exception e) {
335352
logger.error(String.format("Failed to calculate the quota usage for account [%s] due to [%s].", accountToString, e.getMessage()), e);
336353
return new ArrayList<>();
337354
}
338355

339-
return persistUsagesAndQuotaUsagesAndRetrievePersistedQuotaUsages(pairsUsageAndQuotaUsage);
356+
return persistUsagesAndQuotaUsagesAndRetrievePersistedQuotaUsages(mapUsageAndQuotaUsage);
340357
}
341358

342359
protected boolean shouldCalculateUsageRecord(AccountVO accountVO, UsageVO usageRecord) {
@@ -348,31 +365,41 @@ protected boolean shouldCalculateUsageRecord(AccountVO accountVO, UsageVO usageR
348365
return true;
349366
}
350367

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

354-
for (Pair<UsageVO, QuotaUsageVO> pairUsageAndQuotaUsage : pairsUsageAndQuotaUsage) {
355-
UsageVO usageVo = pairUsageAndQuotaUsage.first();
371+
for (Map.Entry<UsageVO, Pair<QuotaUsageVO, List<QuotaTariffUsageVO>>> usageAndTariffUsage : mapUsageAndQuotaTariffUsage.entrySet()) {
372+
UsageVO usageVo = usageAndTariffUsage.getKey();
356373
usageVo.setQuotaCalculated(1);
357374
_usageDao.persistUsage(usageVo);
358375

359-
QuotaUsageVO quotaUsageVo = pairUsageAndQuotaUsage.second();
360-
if (quotaUsageVo != null) {
361-
_quotaUsageDao.persistQuotaUsage(quotaUsageVo);
362-
quotaUsages.add(quotaUsageVo);
376+
Pair<QuotaUsageVO, List<QuotaTariffUsageVO>> pairUsageAndTariffUsages = usageAndTariffUsage.getValue();
377+
if (pairUsageAndTariffUsages != null) {
378+
QuotaUsageVO quotaUsage = pairUsageAndTariffUsages.first();
379+
_quotaUsageDao.persistQuotaUsage(quotaUsage);
380+
quotaUsages.add(quotaUsage);
381+
382+
persistQuotaTariffUsages(pairUsageAndTariffUsages.second(), quotaUsage.getId());
363383
}
364384
}
365385

366386
return quotaUsages;
367387
}
368388

369-
protected BigDecimal aggregateQuotaTariffsValues(UsageVO usageRecord, List<QuotaTariffVO> quotaTariffs, boolean hasAnyQuotaTariffWithActivationRule,
370-
JsInterpreter jsInterpreter, String accountToString) {
389+
protected void persistQuotaTariffUsages(List<QuotaTariffUsageVO> quotaTariffUsages, Long quotaUsageId) {
390+
for (QuotaTariffUsageVO quotaTariffUsage : quotaTariffUsages) {
391+
quotaTariffUsage.setQuotaUsageId(quotaUsageId);
392+
quotaTariffUsageDao.persistQuotaTariffUsage(quotaTariffUsage);
393+
}
394+
}
395+
396+
protected Map<QuotaTariffVO, BigDecimal> aggregateQuotaTariffsValues(UsageVO usageRecord, List<QuotaTariffVO> quotaTariffs, boolean hasAnyQuotaTariffWithActivationRule,
397+
JsInterpreter jsInterpreter, String accountToString) {
371398
String usageRecordToString = usageRecord.toString(usageAggregationTimeZone);
372399
logger.debug("Validating usage record [{}] for account [{}] against [{}] quota tariffs.", usageRecordToString, accountToString, quotaTariffs.size());
373400

374401
PresetVariables presetVariables = getPresetVariables(hasAnyQuotaTariffWithActivationRule, usageRecord);
375-
BigDecimal aggregatedQuotaTariffsValue = BigDecimal.ZERO;
402+
Map<QuotaTariffVO, BigDecimal> aggregatedQuotaTariffsAndValues = new HashMap<>();
376403

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

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

382409
for (QuotaTariffVO quotaTariff : quotaTariffs) {
383410
if (isQuotaTariffInPeriodToBeApplied(usageRecord, quotaTariff, accountToString)) {
384-
385411
BigDecimal tariffValue = getQuotaTariffValueToBeApplied(quotaTariff, jsInterpreter, presetVariables, lastTariffs);
386412

387-
aggregatedQuotaTariffsValue = aggregatedQuotaTariffsValue.add(tariffValue);
413+
aggregatedQuotaTariffsAndValues.put(quotaTariff, tariffValue);
388414

389415
Tariff tariffPresetVariable = new Tariff();
390416
tariffPresetVariable.setId(quotaTariff.getUuid());
@@ -393,10 +419,10 @@ protected BigDecimal aggregateQuotaTariffsValues(UsageVO usageRecord, List<Quota
393419
}
394420
}
395421

396-
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"
397-
+ " usage value.", aggregatedQuotaTariffsValue, usageRecordToString));
422+
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"
423+
+ " to calculate the final usage value.", aggregatedQuotaTariffsAndValues.size(), usageRecordToString);
398424

399-
return aggregatedQuotaTariffsValue;
425+
return aggregatedQuotaTariffsAndValues;
400426
}
401427

402428
protected PresetVariables getPresetVariables(boolean hasAnyQuotaTariffWithActivationRule, UsageVO usageRecord) {
@@ -407,6 +433,26 @@ protected PresetVariables getPresetVariables(boolean hasAnyQuotaTariffWithActiva
407433
return null;
408434
}
409435

436+
protected QuotaTariffUsageVO createQuotaTariffUsage(UsageVO usageRecord, QuotaTariffVO quotaTariff, BigDecimal quotaTariffValue) {
437+
BigDecimal quotaUsageValue = BigDecimal.ZERO;
438+
439+
if (!quotaTariffValue.equals(BigDecimal.ZERO)) {
440+
String quotaUnit = QuotaTypes.getQuotaType(usageRecord.getUsageType()).getQuotaUnit();
441+
logger.trace("Calculating the value of the quota tariff [{}] according to its value [{}] and its quota unit [{}].", quotaTariff, quotaTariffValue, quotaUnit);
442+
quotaUsageValue = getUsageValueAccordingToUsageUnitType(usageRecord, quotaTariffValue, quotaUnit);
443+
logger.debug("The calculation of the value of the quota tariff [{}] according to its value [{}] and its usage unit [{}] resulted in the value [{}].",
444+
quotaTariff, quotaTariffValue, quotaUnit, quotaUsageValue);
445+
} else {
446+
logger.debug("Quota tariff [{}] has no value to be calculated; therefore, it will be marked as value zero.", quotaTariff);
447+
}
448+
449+
QuotaTariffUsageVO quotaTariffUsage = new QuotaTariffUsageVO();
450+
quotaTariffUsage.setTariffId(quotaTariff.getId());
451+
quotaTariffUsage.setQuotaUsed(quotaUsageValue);
452+
453+
return quotaTariffUsage;
454+
}
455+
410456
/**
411457
* Returns the quota tariff value according to the result of the activation rule.<br/>
412458
* <ul>

0 commit comments

Comments
 (0)