CLOUDSTACK-8592: Implement Quota service

Quota service while allowing for scalability will make sure that the cloud is
not exploited by attacks, careless use and program errors. To address this
problem, we propose to employ a quota-enforcement service that allows resource
usage within certain bounds as defined by policies and available quotas for
various entities.  Quota service extends the functionality of usage server to
provide a measurement for the resources used by the accounts and domains using a
common unit referred to as cloud currency in this document. It can be configured
to ensure that your usage won’t exceed the budget allocated to accounts/domain
in cloud currency.  It will let user know how much of the cloud resources he is
using. It will help the cloud admins, if they want, to ensure that a user does
not go beyond his allocated quota. Per usage cycle if a account is found to be
exceeding its quota then it is locked. Locking an account means that it will not
be able to initiat e a new resource allocation request, whether it is more
storage or an additional ip. Needless to say quota service as well as any action
on the account is configurable.

Changes from Github code review:

- Added marvin test for quota plugin API
- removed unused commented code
- debug messages in debug enabled check
- checks for nulls, fixed access to member variables and feature
- changes based on PR comments
- unit tests for UsageTypes
- unit tests for all Cmd classes
- unit tests for all service and manager impls
- try-catch-finally or try-with-resource in dao impls for failsafe db switching
- remove dead code
- add missing quota calculation case (regression fixed)
- replace tabs with spaces in pom.xmls
- quota: though default value for quota_calculated is 0, the usage server
  makes it null while entering usage entries. Flipping the condition so
  as to acocunt for that.
- quotatypes: fix NPE in quota type
- quota framework test fixes
- made statement period configurable
- changed default email templates to reflect the fact that exhausted quota may not result in a locked account
- added quotaUpdateCmd that refreshes quota balances and sends alerts and statements
- report quotaSummary command returns quota balance, quota usage and state for all account
- made UI framework changes to allow for text area input in edit views
- process usage entries that have greater than 0 usage
- orocess quota entries only if tariff is non zero
- if there are credit entries but no balance entry create a dummy balance entry
- remove any credit entries that are before the last balance entry
  when displaying balance statement
- on a rerun the last balance is now getting added

FS: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Quota+Service+-+FS
PR: https://github.com/apache/cloudstack/pull/768

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Abhinandan Prateek 2015-08-13 11:42:30 +05:30 committed by Rohit Yadav
parent f30fbe9a5c
commit 987fcbd441
110 changed files with 10350 additions and 81 deletions

View File

@ -273,6 +273,7 @@ public class ApiConstants {
public static final String VIRTUAL_MACHINE_ID_IP = "vmidipmap";
public static final String VIRTUAL_MACHINE_COUNT = "virtualmachinecount";
public static final String USAGE_ID = "usageid";
public static final String USAGE_TYPE = "usagetype";
public static final String VLAN = "vlan";
public static final String VLAN_RANGE = "vlanrange";

View File

@ -95,7 +95,7 @@ public abstract class BaseCmd {
GET, POST, PUT, DELETE
}
public static enum CommandType {
BOOLEAN, DATE, FLOAT, INTEGER, SHORT, LIST, LONG, OBJECT, MAP, STRING, TZDATE, UUID
BOOLEAN, DATE, FLOAT, DOUBLE, INTEGER, SHORT, LIST, LONG, OBJECT, MAP, STRING, TZDATE, UUID
}
private Object _responseObject;

View File

@ -111,6 +111,30 @@ public class GetUsageRecordsCmd extends BaseListCmd {
public String getUsageId() {
return usageId;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public void setEndDate(Date endDate) {
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public void setStartDate(Date startDate) {
this.startDate = startDate == null ? null : new Date(startDate.getTime());
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public void setUsageId(String usageId) {
this.usageId = usageId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////

View File

@ -22,6 +22,7 @@ import java.util.List;
import org.apache.cloudstack.api.response.UsageTypeResponse;
public class UsageTypes {
/* Any changes here should also reflect in cloud_usage.quota_mapping table */
public static final int RUNNING_VM = 1;
public static final int ALLOCATED_VM = 2; // used for tracking how long storage has been allocated for a VM
public static final int IP_ADDRESS = 3;

View File

@ -17,6 +17,7 @@
package org.apache.cloudstack.api.command.test;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import junit.framework.TestCase;
@ -70,4 +71,22 @@ public class UsageCmdTest extends TestCase {
}
@Test
public void testCrud() {
getUsageRecordsCmd.setDomainId(1L);
assertTrue(getUsageRecordsCmd.getDomainId().equals(1L));
getUsageRecordsCmd.setAccountName("someAccount");
assertTrue(getUsageRecordsCmd.getAccountName().equals("someAccount"));
Date d = new Date();
getUsageRecordsCmd.setStartDate(d);
getUsageRecordsCmd.setEndDate(d);
assertTrue(getUsageRecordsCmd.getStartDate().equals(d));
assertTrue(getUsageRecordsCmd.getEndDate().equals(d));
getUsageRecordsCmd.setUsageId("someId");
assertTrue(getUsageRecordsCmd.getUsageId().equals("someId"));
}
}

View File

@ -1423,6 +1423,47 @@ label.show.advanced.settings=Show advanced settings
label.delete.OpenDaylight.device=Delete OpenDaylight Controller
label.polling.interval.sec=Polling Interval (in sec)
label.quiet.time.sec=Quiet Time (in sec)
label.usage.type=Usage Type
label.usage.unit=Unit
label.quota.value=Quota Value
label.quota.description=Quota Description
label.quota.configuration=Quota Configuration
label.quota.configure=Configure Quota
label.quota.remove=Remove Quota
label.quota.totalusage=Total Usage
label.quota.balance=Balance
label.quota.minbalance=Min Balance
label.quota.enforcequota=Enforce Quota
label.quota.summary=Summary
label.quota.fullsummary=All Accounts
label.quota.tariff=Tariff
label.quota.state=State
label.quota.startdate=Start Date
label.quota.enddate=End Date
label.quota.total=Total
label.quota.startquota=Start Quota
label.quota.endquota=End Quota
label.quota.type.name=Usage Type
label.quota.type.unit=Usage Unit
label.quota.usage=Quota Consumption
label.quota.add.credits=Add Credits
label.quota.email.template=Email Template
label.quota.statement=Statement
label.quota.statement.balance=Quota Balance
label.quota.statement.quota=Quota Usage
label.quota.statement.tariff=Quota Tariff
label.quota.tariff.value=Tariff Value
label.quota.tariff.edit=Edit Tariff
label.quota.tariff.effectivedate=Effective Date
label.quota.date=Date
label.quota.dates=Update Dates
label.quota.credit=Credit
label.quota.credits=Credits
label.quota.value=Quota Value
label.quota.statement.bydates=Statement
label.quota.email.subject=Subject
label.quota.email.body=Body
label.quota.email.lastupdated=Last Update
label.destroy.vm.graceperiod=Destroy VM Grace Period
label.SNMP.community=SNMP Community
label.SNMP.port=SNMP Port

View File

@ -256,6 +256,11 @@
<artifactId>cloud-framework-ipc</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-framework-quota</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-framework-rest</artifactId>
@ -366,6 +371,11 @@
<artifactId>cloud-plugin-network-globodns</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-database-quota</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -787,3 +787,14 @@ addGloboDnsHost=1
### volume/template post upload
getUploadParamsForVolume=15
getUploadParamsForTemplate=15
### Quota Service
quotaStatement=15
quotaBalance=15
quotaSummary=15
quotaUpdate=1
quotaTariffList=15
quotaTariffUpdate=1
quotaCredits=1
quotaEmailTemplateList=1
quotaEmailTemplateUpdate=1

View File

@ -340,4 +340,4 @@ public class Upgrade452to460 implements DbUpgrade {
}
s_logger.debug("Updating System Vm Template IDs Complete");
}
}
}

View File

@ -23,6 +23,8 @@ import org.apache.log4j.Logger;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Upgrade461to470 implements DbUpgrade {
final static Logger s_logger = Logger.getLogger(Upgrade461to470.class);
@ -51,8 +53,23 @@ public class Upgrade461to470 implements DbUpgrade {
return new File[] {new File(script)};
}
public void alterAddColumnToCloudUsage(final Connection conn) {
final String alterTableSql = "ALTER TABLE `cloud_usage`.`cloud_usage` ADD COLUMN `quota_calculated` tinyint(1) DEFAULT 0 NOT NULL COMMENT 'quota calculation status'";
try (PreparedStatement pstmt = conn.prepareStatement(alterTableSql)) {
pstmt.executeUpdate();
s_logger.info("Altered cloud_usage.cloud_usage table and added column quota_calculated");
} catch (SQLException e) {
if (e.getMessage().contains("quota_calculated")) {
s_logger.warn("cloud_usage.cloud_usage table already has a column called quota_calculated");
} else {
throw new CloudRuntimeException("Unable to create column quota_calculated in table cloud_usage.cloud_usage", e);
}
}
}
@Override
public void performDataMigration(Connection conn) {
alterAddColumnToCloudUsage(conn);
}
@Override

View File

@ -103,6 +103,17 @@ public class UsageVO implements Usage, InternalIdentity {
@Temporal(value = TemporalType.TIMESTAMP)
private Date endDate = null;
@Column(name = "quota_calculated")
private Integer quotaCalculated = 0;
public Integer getQuotaCalculated() {
return quotaCalculated;
}
public void setQuotaCalculated(Integer quotaCalculated) {
this.quotaCalculated = quotaCalculated;
}
public UsageVO() {
}
@ -121,8 +132,8 @@ public class UsageVO implements Usage, InternalIdentity {
this.templateId = templateId;
this.usageId = usageId;
this.size = size;
this.startDate = startDate;
this.endDate = endDate;
this.startDate = startDate == null ? null : new Date(startDate.getTime());
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public UsageVO(Long zoneId, Long accountId, Long domainId, String description, String usageDisplay, int usageType, Double rawUsage, Long vmId, String vmName,
@ -141,8 +152,8 @@ public class UsageVO implements Usage, InternalIdentity {
this.usageId = usageId;
this.size = size;
this.virtualSize = virtualSize;
this.startDate = startDate;
this.endDate = endDate;
this.startDate = startDate == null ? null : new Date(startDate.getTime());
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public UsageVO(Long zoneId, Long accountId, Long domainId, String description, String usageDisplay, int usageType, Double rawUsage, Long usageId, String type,
@ -157,8 +168,8 @@ public class UsageVO implements Usage, InternalIdentity {
this.usageId = usageId;
this.type = type;
this.networkId = networkId;
this.startDate = startDate;
this.endDate = endDate;
this.startDate = startDate == null ? null : new Date(startDate.getTime());
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public UsageVO(Long zoneId, Long accountId, Long domainId, String description, String usageDisplay, int usageType, Double rawUsage, Long vmId, String vmName,
@ -176,8 +187,8 @@ public class UsageVO implements Usage, InternalIdentity {
this.templateId = templateId;
this.usageId = usageId;
this.type = type;
this.startDate = startDate;
this.endDate = endDate;
this.startDate = startDate == null ? null : new Date(startDate.getTime());
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public UsageVO(Long zoneId, Long accountId, Long domainId, String description, String usageDisplay, int usageType, Double rawUsage, Long vmId, String vmName,
@ -198,8 +209,8 @@ public class UsageVO implements Usage, InternalIdentity {
this.templateId = templateId;
this.usageId = usageId;
this.type = type;
this.startDate = startDate;
this.endDate = endDate;
this.startDate = startDate == null ? null : new Date(startDate.getTime());
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
//IPAddress Usage
@ -215,8 +226,8 @@ public class UsageVO implements Usage, InternalIdentity {
this.usageId = usageId;
this.size = size;
this.type = type;
this.startDate = startDate;
this.endDate = endDate;
this.startDate = startDate == null ? null : new Date(startDate.getTime());
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
@Override
@ -321,11 +332,55 @@ public class UsageVO implements Usage, InternalIdentity {
@Override
public Date getStartDate() {
return startDate;
return startDate == null ? null : new Date(startDate.getTime());
}
@Override
public Date getEndDate() {
return endDate;
return endDate == null ? null : new Date(endDate.getTime());
}
public void setId(Long id) {
this.id = id;
}
public void setType(String type) {
this.type = type;
}
public void setStartDate(Date startDate) {
this.startDate = startDate == null ? null : new Date(startDate.getTime());
}
public void setEndDate(Date endDate) {
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public void setZoneId(Long zoneId) {
this.zoneId = zoneId;
}
public void setUsageType(int usageType) {
this.usageType = usageType;
}
public void setRawUsage(Double rawUsage) {
this.rawUsage = rawUsage;
}
public void setSize(Long size) {
this.size = size;
}
public void setVirtualSize(Long virtualSize) {
this.virtualSize = virtualSize;
}
}

View File

@ -55,4 +55,8 @@ public interface UsageDao extends GenericDao<UsageVO, Long> {
void saveUsageRecords(List<UsageVO> usageRecords);
void removeOldUsageRecords(int days);
UsageVO persistUsage(final UsageVO usage);
Pair<List<? extends UsageVO>, Integer> getUsageRecordsPendingQuotaAggregation(long accountId, long domainId);
}

View File

@ -24,9 +24,14 @@ import com.cloud.utils.DateUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.TransactionStatus;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@ -45,29 +50,24 @@ public class UsageDaoImpl extends GenericDaoBase<UsageVO, Long> implements Usage
private static final String DELETE_ALL_BY_ACCOUNTID = "DELETE FROM cloud_usage WHERE account_id = ?";
private static final String DELETE_ALL_BY_INTERVAL = "DELETE FROM cloud_usage WHERE end_date < DATE_SUB(CURRENT_DATE(), INTERVAL ? DAY)";
private static final String INSERT_ACCOUNT = "INSERT INTO cloud_usage.account (id, account_name, type, domain_id, removed, cleanup_needed) VALUES (?,?,?,?,?,?)";
private static final String INSERT_USER_STATS =
"INSERT INTO cloud_usage.user_statistics (id, data_center_id, account_id, public_ip_address, device_id, device_type, network_id, net_bytes_received,"
+ " net_bytes_sent, current_bytes_received, current_bytes_sent, agg_bytes_received, agg_bytes_sent) VALUES (?,?,?,?,?,?,?,?,?,?, ?, ?, ?)";
private static final String INSERT_USER_STATS = "INSERT INTO cloud_usage.user_statistics (id, data_center_id, account_id, public_ip_address, device_id, device_type, network_id, net_bytes_received,"
+ " net_bytes_sent, current_bytes_received, current_bytes_sent, agg_bytes_received, agg_bytes_sent) VALUES (?,?,?,?,?,?,?,?,?,?, ?, ?, ?)";
private static final String UPDATE_ACCOUNT = "UPDATE cloud_usage.account SET account_name=?, removed=? WHERE id=?";
private static final String UPDATE_USER_STATS =
"UPDATE cloud_usage.user_statistics SET net_bytes_received=?, net_bytes_sent=?, current_bytes_received=?, current_bytes_sent=?, agg_bytes_received=?, agg_bytes_sent=? WHERE id=?";
private static final String UPDATE_USER_STATS = "UPDATE cloud_usage.user_statistics SET net_bytes_received=?, net_bytes_sent=?, current_bytes_received=?, current_bytes_sent=?, agg_bytes_received=?, agg_bytes_sent=? WHERE id=?";
private static final String GET_LAST_ACCOUNT = "SELECT id FROM cloud_usage.account ORDER BY id DESC LIMIT 1";
private static final String GET_LAST_USER_STATS = "SELECT id FROM cloud_usage.user_statistics ORDER BY id DESC LIMIT 1";
private static final String GET_PUBLIC_TEMPLATES_BY_ACCOUNTID = "SELECT id FROM cloud.vm_template WHERE account_id = ? AND public = '1' AND removed IS NULL";
private static final String GET_LAST_VM_DISK_STATS = "SELECT id FROM cloud_usage.vm_disk_statistics ORDER BY id DESC LIMIT 1";
private static final String INSERT_VM_DISK_STATS =
"INSERT INTO cloud_usage.vm_disk_statistics (id, data_center_id, account_id, vm_id, volume_id, net_io_read, net_io_write, current_io_read, "
+ "current_io_write, agg_io_read, agg_io_write, net_bytes_read, net_bytes_write, current_bytes_read, current_bytes_write, agg_bytes_read, agg_bytes_write) "
+ " VALUES (?,?,?,?,?,?,?,?,?,?, ?, ?, ?, ?,?, ?, ?)";
private static final String UPDATE_VM_DISK_STATS =
"UPDATE cloud_usage.vm_disk_statistics SET net_io_read=?, net_io_write=?, current_io_read=?, current_io_write=?, agg_io_read=?, agg_io_write=?, "
+ "net_bytes_read=?, net_bytes_write=?, current_bytes_read=?, current_bytes_write=?, agg_bytes_read=?, agg_bytes_write=? WHERE id=?";
private static final String INSERT_VM_DISK_STATS = "INSERT INTO cloud_usage.vm_disk_statistics (id, data_center_id, account_id, vm_id, volume_id, net_io_read, net_io_write, current_io_read, "
+ "current_io_write, agg_io_read, agg_io_write, net_bytes_read, net_bytes_write, current_bytes_read, current_bytes_write, agg_bytes_read, agg_bytes_write) "
+ " VALUES (?,?,?,?,?,?,?,?,?,?, ?, ?, ?, ?,?, ?, ?)";
private static final String UPDATE_VM_DISK_STATS = "UPDATE cloud_usage.vm_disk_statistics SET net_io_read=?, net_io_write=?, current_io_read=?, current_io_write=?, agg_io_read=?, agg_io_write=?, "
+ "net_bytes_read=?, net_bytes_write=?, current_bytes_read=?, current_bytes_write=?, agg_bytes_read=?, agg_bytes_write=? WHERE id=?";
private static final String INSERT_USAGE_RECORDS = "INSERT INTO cloud_usage.cloud_usage (zone_id, account_id, domain_id, description, usage_display, "
+
"usage_type, raw_usage, vm_instance_id, vm_name, offering_id, template_id, "
+ "usage_type, raw_usage, vm_instance_id, vm_name, offering_id, template_id, "
+ "usage_id, type, size, network_id, start_date, end_date, virtual_size) VALUES (?,?,?,?,?,?,?,?,?, ?, ?, ?,?,?,?,?,?,?)";
protected final static TimeZone s_gmtTimeZone = TimeZone.getTimeZone("GMT");
@ -213,7 +213,7 @@ public class UsageDaoImpl extends GenericDaoBase<UsageVO, Long> implements Usage
txn.start();
String sql = UPDATE_USER_STATS;
PreparedStatement pstmt = null;
pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
for (UserStatisticsVO userStat : userStats) {
pstmt.setLong(1, userStat.getNetBytesReceived());
pstmt.setLong(2, userStat.getNetBytesSent());
@ -310,7 +310,7 @@ public class UsageDaoImpl extends GenericDaoBase<UsageVO, Long> implements Usage
txn.start();
String sql = UPDATE_VM_DISK_STATS;
PreparedStatement pstmt = null;
pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
for (VmDiskStatisticsVO vmDiskStat : vmDiskStats) {
pstmt.setLong(1, vmDiskStat.getNetIORead());
pstmt.setLong(2, vmDiskStat.getNetIOWrite());
@ -467,4 +467,40 @@ public class UsageDaoImpl extends GenericDaoBase<UsageVO, Long> implements Usage
txn.close();
}
}
public UsageVO persistUsage(final UsageVO usage) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<UsageVO>() {
@Override
public UsageVO doInTransaction(final TransactionStatus status) {
return persist(usage);
}
});
}
public Pair<List<? extends UsageVO>, Integer> getUsageRecordsPendingQuotaAggregation(final long accountId, final long domainId) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Getting usage records for account: " + accountId + ", domainId: " + domainId);
}
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<Pair<List<? extends UsageVO>, Integer>>() {
@Override
public Pair<List<? extends UsageVO>, Integer> doInTransaction(final TransactionStatus status) {
Pair<List<UsageVO>, Integer> usageRecords = new Pair<List<UsageVO>, Integer>(new ArrayList<UsageVO>(), 0);
Filter usageFilter = new Filter(UsageVO.class, "startDate", true, 0L, Long.MAX_VALUE);
QueryBuilder<UsageVO> qb = QueryBuilder.create(UsageVO.class);
if (accountId != -1) {
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
}
if (domainId != -1) {
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
}
qb.and(qb.entity().getQuotaCalculated(), SearchCriteria.Op.NEQ, 1);
qb.and(qb.entity().getRawUsage(), SearchCriteria.Op.GT, 0);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Getting usage records" + usageFilter.getOrderBy());
}
usageRecords = searchAndCountAllRecords(qb.create(), usageFilter);
return new Pair<List<? extends UsageVO>, Integer>(usageRecords.first(), usageRecords.second());
}
});
}
}

View File

@ -35,18 +35,11 @@ public class Transaction {
if (currentTxn != null) {
databaseId = currentTxn.getDatabaseId();
}
TransactionLegacy txn = TransactionLegacy.open(name, databaseId, false);
try {
// if (txn.dbTxnStarted()){
// String warnMsg = "Potential Wrong Usage: TRANSACTION.EXECUTE IS WRAPPED INSIDE ANOTHER DB TRANSACTION!";
// s_logger.warn(warnMsg, new CloudRuntimeException(warnMsg));
// }
try (final TransactionLegacy txn = TransactionLegacy.open(name, databaseId, false)) {
txn.start();
T result = callback.doInTransaction(STATUS);
txn.commit();
return result;
} finally {
txn.close();
}
}
@ -59,4 +52,28 @@ public class Transaction {
});
}
@SuppressWarnings("deprecation")
public static <T, E extends Throwable> T execute(final short databaseId, TransactionCallbackWithException<T, E> callback) throws E {
String name = "tx-" + counter.incrementAndGet();
TransactionLegacy currentTxn = TransactionLegacy.currentTxn(false);
short outer_txn_databaseId = (currentTxn != null ? currentTxn.getDatabaseId() : databaseId);
try (final TransactionLegacy txn = TransactionLegacy.open(name, databaseId, true)) {
txn.start();
T result = callback.doInTransaction(STATUS);
txn.commit();
return result;
} finally {
TransactionLegacy.open(outer_txn_databaseId).close();
}
}
public static <T> T execute(final short databaseId, final TransactionCallback<T> callback) {
return execute(databaseId, new TransactionCallbackWithException<T, RuntimeException>() {
@Override
public T doInTransaction(TransactionStatus status) throws RuntimeException {
return callback.doInTransaction(status);
}
});
}
}

View File

@ -47,6 +47,7 @@
<module>rest</module>
<module>events</module>
<module>jobs</module>
<module>quota</module>
<module>cluster</module>
<module>db</module>
<module>config</module>

73
framework/quota/pom.xml Normal file
View File

@ -0,0 +1,73 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-framework-quota</artifactId>
<name>Apache CloudStack Framework - Quota</name>
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-framework</artifactId>
<version>4.7.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-utils</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-schema</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${cs.junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>${cs.mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${cs.powermock.version}</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${cs.powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${cs.commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,34 @@
<!-- 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. -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="QuotaTariffDao" class="org.apache.cloudstack.quota.dao.QuotaTariffDaoImpl" />
<bean id="QuotaAccountDao" class="org.apache.cloudstack.quota.dao.QuotaAccountDaoImpl" />
<bean id="QuotaBalanceDao" class="org.apache.cloudstack.quota.dao.QuotaBalanceDaoImpl" />
<bean id="QuotaCreditsDao" class="org.apache.cloudstack.quota.dao.QuotaCreditsDaoImpl" />
<bean id="QuotaEmailTemplatesDao"
class="org.apache.cloudstack.quota.dao.QuotaEmailTemplatesDaoImpl" />
<bean id="QuotaUsageDao" class="org.apache.cloudstack.quota.dao.QuotaUsageDaoImpl" />
<bean id="ServiceOfferingDao" class="org.apache.cloudstack.quota.dao.ServiceOfferingDaoImpl" />
<bean id="UserVmDetailsDao" class="org.apache.cloudstack.quota.dao.UserVmDetailsDaoImpl" />
<bean id="QuotaManager" class="org.apache.cloudstack.quota.QuotaManagerImpl" />
<bean id="QuotaAlertManager" class="org.apache.cloudstack.quota.QuotaAlertManagerImpl" />
<bean id="QuotaStatement" class="org.apache.cloudstack.quota.QuotaStatementImpl" />
</beans>

View File

@ -0,0 +1,26 @@
//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
//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;
import com.cloud.utils.component.Manager;
import org.apache.cloudstack.quota.QuotaAlertManagerImpl.DeferredQuotaEmail;
public interface QuotaAlertManager extends Manager {
void checkAndSendQuotaAlertEmails();
void sendQuotaAlert(DeferredQuotaEmail emailToBeSent);
}

View File

@ -0,0 +1,418 @@
//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;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.user.Account;
import com.cloud.user.Account.State;
import com.cloud.user.AccountVO;
import com.cloud.user.UserVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.exception.CloudRuntimeException;
import com.google.common.base.Strings;
import com.sun.mail.smtp.SMTPMessage;
import com.sun.mail.smtp.SMTPSSLTransport;
import com.sun.mail.smtp.SMTPTransport;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.quota.constant.QuotaConfig;
import org.apache.cloudstack.quota.constant.QuotaConfig.QuotaEmailTemplateTypes;
import org.apache.cloudstack.quota.dao.QuotaAccountDao;
import org.apache.cloudstack.quota.dao.QuotaEmailTemplatesDao;
import org.apache.cloudstack.quota.dao.QuotaUsageDao;
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;
import org.springframework.stereotype.Component;
import javax.ejb.Local;
import javax.inject.Inject;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.URLName;
import javax.mail.internet.InternetAddress;
import javax.naming.ConfigurationException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
@Component
@Local(value = QuotaAlertManager.class)
public class QuotaAlertManagerImpl extends ManagerBase implements QuotaAlertManager {
private static final Logger s_logger = Logger.getLogger(QuotaAlertManagerImpl.class);
@Inject
private AccountDao _accountDao;
@Inject
private QuotaAccountDao _quotaAcc;
@Inject
private UserDao _userDao;
@Inject
private DomainDao _domainDao;
@Inject
private QuotaEmailTemplatesDao _quotaEmailTemplateDao;
@Inject
private ConfigurationDao _configDao;
@Inject
private QuotaUsageDao _quotaUsage;
private EmailQuotaAlert _emailQuotaAlert;
private boolean _lockAccountEnforcement = false;
boolean _smtpDebug = false;
public QuotaAlertManagerImpl() {
super();
}
private void mergeConfigs(Map<String, String> dbParams, Map<String, Object> xmlParams) {
for (Map.Entry<String, Object> param : xmlParams.entrySet()) {
dbParams.put(param.getKey(), (String)param.getValue());
}
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params);
Map<String, String> configs = _configDao.getConfiguration(params);
if (params != null) {
mergeConfigs(configs, params);
}
final String smtpHost = configs.get(QuotaConfig.QuotaSmtpHost.key());
int smtpPort = NumbersUtil.parseInt(configs.get(QuotaConfig.QuotaSmtpPort.key()), 25);
String useAuthStr = configs.get(QuotaConfig.QuotaSmtpAuthType.key());
boolean useAuth = ((useAuthStr != null) && Boolean.parseBoolean(useAuthStr));
String smtpUsername = configs.get(QuotaConfig.QuotaSmtpUser.key());
String smtpPassword = configs.get(QuotaConfig.QuotaSmtpPassword.key());
String emailSender = configs.get(QuotaConfig.QuotaSmtpSender.key());
_lockAccountEnforcement = "true".equalsIgnoreCase(configs.get(QuotaConfig.QuotaEnableEnforcement.key()));
_emailQuotaAlert = new EmailQuotaAlert(smtpHost, smtpPort, useAuth, smtpUsername, smtpPassword, emailSender, _smtpDebug);
return true;
}
@Override
public boolean start() {
if (s_logger.isInfoEnabled()) {
s_logger.info("Starting Alert Manager");
}
return true;
}
@Override
public boolean stop() {
if (s_logger.isInfoEnabled()) {
s_logger.info("Stopping Alert Manager");
}
return true;
}
@Override
public void checkAndSendQuotaAlertEmails() {
List<DeferredQuotaEmail> deferredQuotaEmailList = new ArrayList<DeferredQuotaEmail>();
final BigDecimal zeroBalance = new BigDecimal(0);
for (final QuotaAccountVO quotaAccount : _quotaAcc.listAllQuotaAccount()) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("checkAndSendQuotaAlertEmails accId=" + quotaAccount.getId());
}
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());
if (s_logger.isDebugEnabled()) {
s_logger.debug("checkAndSendQuotaAlertEmails: Check id=" + account.getId() + " bal=" + accountBalance + ", alertDate=" + alertDate + ", lockable=" + lockable);
}
if (accountBalance.compareTo(zeroBalance) < 0) {
if (_lockAccountEnforcement && (lockable == 1)) {
if (account.getType() == Account.ACCOUNT_TYPE_NORMAL) {
s_logger.info("Locking account " + account.getAccountName() + " due to quota < 0.");
lockAccount(account.getId());
}
}
if (alertDate == null || (balanceDate.after(alertDate) && getDifferenceDays(alertDate, new Date()) > 1)) {
s_logger.info("Sending alert " + account.getAccountName() + " due to quota < 0.");
deferredQuotaEmailList.add(new DeferredQuotaEmail(account, quotaAccount, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_EMPTY));
}
} else if (accountBalance.compareTo(thresholdBalance) < 0) {
if (alertDate == null || (balanceDate.after(alertDate) && getDifferenceDays(alertDate, new Date()) > 1)) {
s_logger.info("Sending alert " + account.getAccountName() + " due to quota below threshold.");
deferredQuotaEmailList.add(new DeferredQuotaEmail(account, quotaAccount, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_LOW));
}
}
}
}
for (DeferredQuotaEmail emailToBeSent : deferredQuotaEmailList) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("checkAndSendQuotaAlertEmails: Attempting to send quota alert email to users of account: " + emailToBeSent.getAccount().getAccountName());
}
sendQuotaAlert(emailToBeSent);
}
}
public void sendQuotaAlert(DeferredQuotaEmail emailToBeSent) {
final AccountVO account = emailToBeSent.getAccount();
final BigDecimal balance = emailToBeSent.getQuotaBalance();
final BigDecimal usage = emailToBeSent.getQuotaUsage();
final QuotaConfig.QuotaEmailTemplateTypes emailType = emailToBeSent.getEmailTemplateType();
final List<QuotaEmailTemplatesVO> emailTemplates = _quotaEmailTemplateDao.listAllQuotaEmailTemplates(emailType.toString());
if (emailTemplates != null && emailTemplates.get(0) != null) {
final QuotaEmailTemplatesVO emailTemplate = emailTemplates.get(0);
final DomainVO accountDomain = _domainDao.findByIdIncludingRemoved(account.getDomainId());
final List<UserVO> usersInAccount = _userDao.listByAccount(account.getId());
String userNames = "";
final List<String> emailRecipients = new ArrayList<String>();
for (UserVO user : usersInAccount) {
userNames += String.format("%s <%s>,", user.getUsername(), user.getEmail());
emailRecipients.add(user.getEmail());
}
if (userNames.endsWith(",")) {
userNames = userNames.substring(0, userNames.length() - 1);
}
final Map<String, String> optionMap = new HashMap<String, String>();
optionMap.put("accountName", account.getAccountName());
optionMap.put("accountID", account.getUuid());
optionMap.put("accountUsers", userNames);
optionMap.put("domainName", accountDomain.getName());
optionMap.put("domainID", accountDomain.getUuid());
optionMap.put("quotaBalance", QuotaConfig.QuotaCurrencySymbol.value() + " " + balance.toString());
if (emailType == QuotaEmailTemplateTypes.QUOTA_STATEMENT) {
optionMap.put("quotaUsage", QuotaConfig.QuotaCurrencySymbol.value() + " " + usage.toString());
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("accountName" + account.getAccountName() + "accountID" + account.getUuid() + "accountUsers" + userNames + "domainName" + accountDomain.getName()
+ "domainID" + accountDomain.getUuid());
}
final StrSubstitutor templateEngine = new StrSubstitutor(optionMap);
final String subject = templateEngine.replace(emailTemplate.getTemplateSubject());
final String body = templateEngine.replace(emailTemplate.getTemplateBody());
try {
_emailQuotaAlert.sendQuotaAlert(emailRecipients, subject, body);
emailToBeSent.sentSuccessfully(_quotaAcc);
} 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));
if (s_logger.isDebugEnabled()) {
s_logger.debug("Exception", e);
}
}
} else {
s_logger.error(String.format("No quota email template found for type %s, cannot send quota alert email to account %s(%s)", emailType, account.getAccountName(),
account.getUuid()));
}
}
public static long getDifferenceDays(Date d1, Date d2) {
long diff = d2.getTime() - d1.getTime();
return TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
}
protected boolean lockAccount(long accountId) {
final short opendb = TransactionLegacy.currentTxn().getDatabaseId();
boolean success = false;
try (TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB)) {
Account account = _accountDao.findById(accountId);
if (account != null) {
if (account.getState() == State.locked) {
return true; // already locked, no-op
} else if (account.getState() == State.enabled) {
AccountVO acctForUpdate = _accountDao.createForUpdate();
acctForUpdate.setState(State.locked);
success = _accountDao.update(Long.valueOf(accountId), acctForUpdate);
} else {
if (s_logger.isInfoEnabled()) {
s_logger.info("Attempting to lock a non-enabled account, current state is " + account.getState() + " (accountId: " + accountId + "), locking failed.");
}
}
} else {
s_logger.warn("Failed to lock account " + accountId + ", account not found.");
}
} catch (Exception e) {
s_logger.error("Exception occured while locking account by Quota Alert Manager", e);
throw e;
} finally {
TransactionLegacy.open(opendb).close();
}
return success;
}
public static class DeferredQuotaEmail {
private AccountVO account;
private QuotaAccountVO quotaAccount;
private QuotaConfig.QuotaEmailTemplateTypes emailTemplateType;
private BigDecimal quotaUsage;
public DeferredQuotaEmail(AccountVO account, QuotaAccountVO quotaAccount, BigDecimal quotaUsage, QuotaConfig.QuotaEmailTemplateTypes emailTemplateType) {
this.account = account;
this.quotaAccount = quotaAccount;
this.emailTemplateType = emailTemplateType;
this.quotaUsage = quotaUsage;
}
public DeferredQuotaEmail(AccountVO account, QuotaAccountVO quotaAccount, QuotaConfig.QuotaEmailTemplateTypes emailTemplateType) {
this.account = account;
this.quotaAccount = quotaAccount;
this.emailTemplateType = emailTemplateType;
this.quotaUsage = new BigDecimal(-1);
}
public AccountVO getAccount() {
return account;
}
public BigDecimal getQuotaBalance() {
return quotaAccount.getQuotaBalance();
}
public BigDecimal getQuotaUsage() {
return quotaUsage;
}
public Date getSendDate() {
if (emailTemplateType == QuotaEmailTemplateTypes.QUOTA_STATEMENT) {
return quotaAccount.getLastStatementDate();
} else {
return quotaAccount.getQuotaAlertDate();
}
}
public QuotaConfig.QuotaEmailTemplateTypes getEmailTemplateType() {
return emailTemplateType;
}
public void sentSuccessfully(final QuotaAccountDao quotaAccountDao) {
if (emailTemplateType == QuotaEmailTemplateTypes.QUOTA_STATEMENT) {
quotaAccount.setLastStatementDate(new Date());
} else {
quotaAccount.setQuotaAlertDate(new Date());
quotaAccount.setQuotaAlertType(emailTemplateType.ordinal());
}
quotaAccountDao.updateQuotaAccount(quotaAccount.getAccountId(), quotaAccount);
}
};
static class EmailQuotaAlert {
private final Session _smtpSession;
private final String _smtpHost;
private final int _smtpPort;
private final boolean _smtpUseAuth;
private final String _smtpUsername;
private final String _smtpPassword;
private final String _emailSender;
public EmailQuotaAlert(String smtpHost, int smtpPort, boolean smtpUseAuth, final String smtpUsername, final String smtpPassword, String emailSender, boolean smtpDebug) {
_smtpHost = smtpHost;
_smtpPort = smtpPort;
_smtpUseAuth = smtpUseAuth;
_smtpUsername = smtpUsername;
_smtpPassword = smtpPassword;
_emailSender = emailSender;
if (!Strings.isNullOrEmpty(_smtpHost)) {
Properties smtpProps = new Properties();
smtpProps.put("mail.smtp.host", smtpHost);
smtpProps.put("mail.smtp.port", smtpPort);
smtpProps.put("mail.smtp.auth", "" + smtpUseAuth);
if (smtpUsername != null) {
smtpProps.put("mail.smtp.user", smtpUsername);
}
smtpProps.put("mail.smtps.host", smtpHost);
smtpProps.put("mail.smtps.port", smtpPort);
smtpProps.put("mail.smtps.auth", "" + smtpUseAuth);
if (!Strings.isNullOrEmpty(smtpUsername)) {
smtpProps.put("mail.smtps.user", smtpUsername);
}
if (!Strings.isNullOrEmpty(smtpUsername) && !Strings.isNullOrEmpty(smtpPassword)) {
_smtpSession = Session.getInstance(smtpProps, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(smtpUsername, smtpPassword);
}
});
} else {
_smtpSession = Session.getInstance(smtpProps);
}
_smtpSession.setDebug(smtpDebug);
} else {
_smtpSession = null;
}
}
public void sendQuotaAlert(List<String> emails, String subject, String body) throws MessagingException, UnsupportedEncodingException {
if (_smtpSession == null) {
throw new CloudRuntimeException("Unable to create smtp session.");
}
SMTPMessage msg = new SMTPMessage(_smtpSession);
msg.setSender(new InternetAddress(_emailSender, _emailSender));
msg.setFrom(new InternetAddress(_emailSender, _emailSender));
for (String email : emails) {
if (email != null && !email.isEmpty()) {
try {
InternetAddress address = new InternetAddress(email, email);
msg.addRecipient(Message.RecipientType.TO, address);
} catch (Exception pokemon) {
s_logger.error("Exception in creating address for:" + email, pokemon);
}
}
}
msg.setSubject(subject);
msg.setSentDate(new Date());
msg.setContent(body, "text/html; charset=utf-8");
msg.saveChanges();
SMTPTransport smtpTrans = null;
if (_smtpUseAuth) {
smtpTrans = new SMTPSSLTransport(_smtpSession, new URLName("smtp", _smtpHost, _smtpPort, null, _smtpUsername, _smtpPassword));
} else {
smtpTrans = new SMTPTransport(_smtpSession, new URLName("smtp", _smtpHost, _smtpPort, null, _smtpUsername, _smtpPassword));
}
smtpTrans.connect();
smtpTrans.sendMessage(msg, msg.getAllRecipients());
smtpTrans.close();
}
}
}

View File

@ -0,0 +1,25 @@
//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
//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;
import com.cloud.utils.component.Manager;
public interface QuotaManager extends Manager {
boolean calculateQuotaUsage();
}

View File

@ -0,0 +1,464 @@
//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;
import com.cloud.usage.UsageVO;
import com.cloud.usage.dao.UsageDao;
import com.cloud.user.AccountVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.Pair;
import com.cloud.utils.component.ManagerBase;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.quota.constant.QuotaTypes;
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.QuotaUsageDao;
import org.apache.cloudstack.quota.dao.ServiceOfferingDao;
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
import org.apache.cloudstack.quota.vo.ServiceOfferingVO;
import org.apache.cloudstack.utils.usage.UsageUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.ejb.Local;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
@Component
@Local(value = QuotaManager.class)
public class QuotaManagerImpl extends ManagerBase implements QuotaManager {
private static final Logger s_logger = Logger.getLogger(QuotaManagerImpl.class.getName());
@Inject
private AccountDao _accountDao;
@Inject
private QuotaAccountDao _quotaAcc;
@Inject
private UsageDao _usageDao;
@Inject
private QuotaTariffDao _quotaTariffDao;
@Inject
private QuotaUsageDao _quotaUsageDao;
@Inject
private ServiceOfferingDao _serviceOfferingDao;
@Inject
private QuotaBalanceDao _quotaBalanceDao;
@Inject
private ConfigurationDao _configDao;
private TimeZone _usageTimezone;
private int _aggregationDuration = 0;
final static BigDecimal s_hoursInMonth = new BigDecimal(30 * 24);
final static BigDecimal s_minutesInMonth = new BigDecimal(30 * 24 * 60);
final static BigDecimal s_gb = new BigDecimal(1024 * 1024 * 1024);
public QuotaManagerImpl() {
super();
}
private void mergeConfigs(Map<String, String> dbParams, Map<String, Object> xmlParams) {
for (Map.Entry<String, Object> param : xmlParams.entrySet()) {
dbParams.put(param.getKey(), (String)param.getValue());
}
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params);
Map<String, String> configs = _configDao.getConfiguration(params);
if (params != null) {
mergeConfigs(configs, params);
}
String aggregationRange = configs.get("usage.stats.job.aggregation.range");
String timeZoneStr = configs.get("usage.aggregation.timezone");
if (timeZoneStr == null) {
timeZoneStr = "GMT";
}
_usageTimezone = TimeZone.getTimeZone(timeZoneStr);
_aggregationDuration = Integer.parseInt(aggregationRange);
if (_aggregationDuration < UsageUtils.USAGE_AGGREGATION_RANGE_MIN) {
s_logger.warn("Usage stats job aggregation range is to small, using the minimum value of " + UsageUtils.USAGE_AGGREGATION_RANGE_MIN);
_aggregationDuration = UsageUtils.USAGE_AGGREGATION_RANGE_MIN;
}
s_logger.info("Usage timezone = " + _usageTimezone + " AggregationDuration=" + _aggregationDuration);
return true;
}
@Override
public boolean start() {
if (s_logger.isInfoEnabled()) {
s_logger.info("Starting Quota Manager");
}
return true;
}
@Override
public boolean stop() {
if (s_logger.isInfoEnabled()) {
s_logger.info("Stopping Quota Manager");
}
return true;
}
public List<QuotaUsageVO> aggregatePendingQuotaRecordsForAccount(final AccountVO account, final Pair<List<? extends UsageVO>, Integer> usageRecords) {
List<QuotaUsageVO> quotaListForAccount = new ArrayList<>();
if (usageRecords == null || usageRecords.first() == null || usageRecords.first().isEmpty()) {
return quotaListForAccount;
}
s_logger.info("Getting pending quota records for account=" + account.getAccountName());
for (UsageVO usageRecord : usageRecords.first()) {
BigDecimal aggregationRatio = new BigDecimal(_aggregationDuration).divide(s_minutesInMonth, 8, RoundingMode.HALF_EVEN);
switch (usageRecord.getUsageType()) {
case QuotaTypes.RUNNING_VM:
List<QuotaUsageVO> lq = updateQuotaRunningVMUsage(usageRecord, aggregationRatio);
if (!lq.isEmpty()) {
quotaListForAccount.addAll(lq);
}
break;
case QuotaTypes.ALLOCATED_VM:
QuotaUsageVO qu = updateQuotaAllocatedVMUsage(usageRecord, aggregationRatio);
if (qu != null) {
quotaListForAccount.add(qu);
}
break;
case QuotaTypes.SNAPSHOT:
case QuotaTypes.TEMPLATE:
case QuotaTypes.ISO:
case QuotaTypes.VOLUME:
case QuotaTypes.VM_SNAPSHOT:
qu = updateQuotaDiskUsage(usageRecord, aggregationRatio, usageRecord.getUsageType());
if (qu != null) {
quotaListForAccount.add(qu);
}
break;
case QuotaTypes.LOAD_BALANCER_POLICY:
case QuotaTypes.PORT_FORWARDING_RULE:
case QuotaTypes.IP_ADDRESS:
case QuotaTypes.NETWORK_OFFERING:
case QuotaTypes.SECURITY_GROUP:
case QuotaTypes.VPN_USERS:
qu = updateQuotaRaw(usageRecord, aggregationRatio, usageRecord.getUsageType());
if (qu != null) {
quotaListForAccount.add(qu);
}
break;
case QuotaTypes.NETWORK_BYTES_RECEIVED:
case QuotaTypes.NETWORK_BYTES_SENT:
qu = updateQuotaNetwork(usageRecord, usageRecord.getUsageType());
if (qu != null) {
quotaListForAccount.add(qu);
}
break;
case QuotaTypes.VM_DISK_IO_READ:
case QuotaTypes.VM_DISK_IO_WRITE:
case QuotaTypes.VM_DISK_BYTES_READ:
case QuotaTypes.VM_DISK_BYTES_WRITE:
default:
break;
}
}
return quotaListForAccount;
}
public void processQuotaBalanceForAccount(final AccountVO account, final List<QuotaUsageVO> quotaListForAccount) {
if (quotaListForAccount == null || quotaListForAccount.isEmpty()) {
return;
}
if (s_logger.isDebugEnabled()) {
s_logger.debug(quotaListForAccount.get(0));
}
Date startDate = quotaListForAccount.get(0).getStartDate();
Date endDate = quotaListForAccount.get(0).getEndDate();
if (s_logger.isDebugEnabled()) {
s_logger.debug("processQuotaBalanceForAccount startDate " + startDate + " endDate=" + endDate);
s_logger.debug("processQuotaBalanceForAccount last items startDate " + quotaListForAccount.get(quotaListForAccount.size() - 1).getStartDate() + " items endDate="
+ quotaListForAccount.get(quotaListForAccount.size() - 1).getEndDate());
}
quotaListForAccount.add(new QuotaUsageVO());
BigDecimal aggrUsage = new BigDecimal(0);
List<QuotaBalanceVO> creditsReceived = null;
//bootstrapping
QuotaUsageVO lastQuotaUsage = _quotaUsageDao.findLastQuotaUsageEntry(account.getAccountId(), account.getDomainId(), startDate);
if (lastQuotaUsage == null) {
creditsReceived = _quotaBalanceDao.findCreditBalance(account.getAccountId(), account.getDomainId(), new Date(0), startDate);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Credit entries count " + creditsReceived.size() + " on Before Date=" + startDate);
}
if (creditsReceived != null) {
for (QuotaBalanceVO credit : creditsReceived) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Credit entry found " + credit);
s_logger.debug("Total = " + aggrUsage);
}
aggrUsage = aggrUsage.add(credit.getCreditBalance());
}
}
// create a balance entry for these accumulated credits
QuotaBalanceVO firstBalance = new QuotaBalanceVO(account.getAccountId(), account.getDomainId(), aggrUsage, startDate);
_quotaBalanceDao.saveQuotaBalance(firstBalance);
}
else {
QuotaBalanceVO lastRealBalanceEntry = _quotaBalanceDao.findLastBalanceEntry(account.getAccountId(), account.getDomainId(), endDate);
aggrUsage = aggrUsage.add(lastRealBalanceEntry.getCreditBalance());
if (s_logger.isDebugEnabled()) {
s_logger.debug("Last balance entry " + lastRealBalanceEntry + " AggrUsage=" + aggrUsage);
}
}
for (QuotaUsageVO entry : quotaListForAccount) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Usage entry found " + entry);
}
if (entry.getQuotaUsed().compareTo(BigDecimal.ZERO) == 0) {
// check if there were credits
creditsReceived = _quotaBalanceDao.findCreditBalance(account.getAccountId(), account.getDomainId(), entry.getStartDate(), entry.getEndDate());
if (creditsReceived != null) {
for (QuotaBalanceVO credit : creditsReceived) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Credit entry found " + credit);
s_logger.debug("Total = " + aggrUsage);
}
aggrUsage = aggrUsage.add(credit.getCreditBalance());
}
}
continue;
}
if (startDate.compareTo(entry.getStartDate()) != 0) {
QuotaBalanceVO newBalance = new QuotaBalanceVO(account.getAccountId(), account.getDomainId(), aggrUsage, endDate);
_quotaBalanceDao.saveQuotaBalance(newBalance);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Saving Balance" + newBalance);
}
//New balance entry
aggrUsage = new BigDecimal(0);
startDate = entry.getStartDate();
endDate = entry.getEndDate();
QuotaBalanceVO lastRealBalanceEntry = _quotaBalanceDao.findLastBalanceEntry(account.getAccountId(), account.getDomainId(), endDate);
Date lastBalanceDate = new Date(0);
if (lastRealBalanceEntry != null) {
lastBalanceDate = lastRealBalanceEntry.getUpdatedOn();
aggrUsage = aggrUsage.add(lastRealBalanceEntry.getCreditBalance());
}
creditsReceived = _quotaBalanceDao.findCreditBalance(account.getAccountId(), account.getDomainId(), lastBalanceDate, endDate);
if (creditsReceived != null) {
for (QuotaBalanceVO credit : creditsReceived) {
aggrUsage = aggrUsage.add(credit.getCreditBalance());
}
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Getting Balance" + account.getAccountName() + ",Balance entry=" + aggrUsage + " on Date=" + endDate);
}
}
aggrUsage = aggrUsage.subtract(entry.getQuotaUsed());
}
QuotaBalanceVO newBalance = new QuotaBalanceVO(account.getAccountId(), account.getDomainId(), aggrUsage, endDate);
_quotaBalanceDao.saveQuotaBalance(newBalance);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Saving Balance" + newBalance);
}
// update quota_accounts
QuotaAccountVO quota_account = _quotaAcc.findByIdQuotaAccount(account.getAccountId());
if (quota_account == null) {
quota_account = new QuotaAccountVO(account.getAccountId());
quota_account.setQuotaBalance(aggrUsage);
quota_account.setQuotaBalanceDate(endDate);
if (s_logger.isDebugEnabled()) {
s_logger.debug(quota_account);
}
_quotaAcc.persistQuotaAccount(quota_account);
} else {
quota_account.setQuotaBalance(aggrUsage);
quota_account.setQuotaBalanceDate(endDate);
if (s_logger.isDebugEnabled()) {
s_logger.debug(quota_account);
}
_quotaAcc.updateQuotaAccount(account.getAccountId(), quota_account);
}
}
@Override
public boolean calculateQuotaUsage() {
List<AccountVO> accounts = _accountDao.listAll();
for (AccountVO account : accounts) {
Pair<List<? extends UsageVO>, Integer> usageRecords = _usageDao.getUsageRecordsPendingQuotaAggregation(account.getAccountId(), account.getDomainId());
if (s_logger.isDebugEnabled()) {
s_logger.debug("Usage entries size = " + usageRecords.second().intValue() + ", accId" + account.getAccountId() + ", domId" + account.getDomainId());
}
List<QuotaUsageVO> quotaListForAccount = aggregatePendingQuotaRecordsForAccount(account, usageRecords);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Quota entries size = " + quotaListForAccount.size() + ", accId" + account.getAccountId() + ", domId" + account.getDomainId());
}
processQuotaBalanceForAccount(account, quotaListForAccount);
}
return true;
}
public QuotaUsageVO updateQuotaDiskUsage(UsageVO usageRecord, final BigDecimal aggregationRatio, final int quotaType) {
QuotaUsageVO quota_usage = null;
QuotaTariffVO tariff = _quotaTariffDao.findTariffPlanByUsageType(quotaType, usageRecord.getEndDate());
if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) {
BigDecimal quotaUsgage;
BigDecimal onehourcostpergb;
BigDecimal noofgbinuse;
onehourcostpergb = tariff.getCurrencyValue().multiply(aggregationRatio);
noofgbinuse = new BigDecimal(usageRecord.getSize()).divide(s_gb, 8, RoundingMode.HALF_EVEN);
quotaUsgage = new BigDecimal(usageRecord.getRawUsage()).multiply(onehourcostpergb).multiply(noofgbinuse);
quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), usageRecord.getUsageType(),
quotaUsgage, usageRecord.getStartDate(), usageRecord.getEndDate());
_quotaUsageDao.persistQuotaUsage(quota_usage);
}
usageRecord.setQuotaCalculated(1);
_usageDao.persistUsage(usageRecord);
return quota_usage;
}
public List<QuotaUsageVO> updateQuotaRunningVMUsage(UsageVO usageRecord, final BigDecimal aggregationRatio) {
List<QuotaUsageVO> quotalist = new ArrayList<QuotaUsageVO>();
QuotaUsageVO quota_usage;
BigDecimal cpuquotausgage, speedquotausage, memoryquotausage, vmusage;
BigDecimal onehourcostpercpu, onehourcostper100mhz, onehourcostper1mb, onehourcostforvmusage;
BigDecimal rawusage;
// get service offering details
ServiceOfferingVO serviceoffering = _serviceOfferingDao.findServiceOffering(usageRecord.getVmInstanceId(), usageRecord.getOfferingId());
rawusage = new BigDecimal(usageRecord.getRawUsage());
QuotaTariffVO tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.CPU_NUMBER, usageRecord.getEndDate());
if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) {
BigDecimal cpu = new BigDecimal(serviceoffering.getCpu());
onehourcostpercpu = tariff.getCurrencyValue().multiply(aggregationRatio);
cpuquotausgage = rawusage.multiply(onehourcostpercpu).multiply(cpu);
quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.CPU_NUMBER,
cpuquotausgage, usageRecord.getStartDate(), usageRecord.getEndDate());
_quotaUsageDao.persistQuotaUsage(quota_usage);
quotalist.add(quota_usage);
}
tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.CPU_CLOCK_RATE, usageRecord.getEndDate());
if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) {
BigDecimal speed = new BigDecimal(serviceoffering.getSpeed() / 100.00);
onehourcostper100mhz = tariff.getCurrencyValue().multiply(aggregationRatio);
speedquotausage = rawusage.multiply(onehourcostper100mhz).multiply(speed);
quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.CPU_CLOCK_RATE,
speedquotausage, usageRecord.getStartDate(), usageRecord.getEndDate());
_quotaUsageDao.persistQuotaUsage(quota_usage);
quotalist.add(quota_usage);
}
tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.MEMORY, usageRecord.getEndDate());
if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) {
BigDecimal memory = new BigDecimal(serviceoffering.getRamSize());
onehourcostper1mb = tariff.getCurrencyValue().multiply(aggregationRatio);
memoryquotausage = rawusage.multiply(onehourcostper1mb).multiply(memory);
quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.MEMORY, memoryquotausage,
usageRecord.getStartDate(), usageRecord.getEndDate());
_quotaUsageDao.persistQuotaUsage(quota_usage);
quotalist.add(quota_usage);
}
tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.RUNNING_VM, usageRecord.getEndDate());
if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) {
onehourcostforvmusage = tariff.getCurrencyValue().multiply(aggregationRatio);
vmusage = rawusage.multiply(onehourcostforvmusage);
quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.RUNNING_VM, vmusage,
usageRecord.getStartDate(), usageRecord.getEndDate());
_quotaUsageDao.persistQuotaUsage(quota_usage);
quotalist.add(quota_usage);
}
usageRecord.setQuotaCalculated(1);
_usageDao.persistUsage(usageRecord);
return quotalist;
}
public QuotaUsageVO updateQuotaAllocatedVMUsage(UsageVO usageRecord, final BigDecimal aggregationRatio) {
QuotaUsageVO quota_usage = null;
QuotaTariffVO tariff = _quotaTariffDao.findTariffPlanByUsageType(QuotaTypes.ALLOCATED_VM, usageRecord.getEndDate());
if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) {
BigDecimal vmusage;
BigDecimal onehourcostforvmusage;
onehourcostforvmusage = tariff.getCurrencyValue().multiply(aggregationRatio);
vmusage = new BigDecimal(usageRecord.getRawUsage()).multiply(onehourcostforvmusage);
quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), QuotaTypes.ALLOCATED_VM, vmusage,
usageRecord.getStartDate(), usageRecord.getEndDate());
_quotaUsageDao.persistQuotaUsage(quota_usage);
}
usageRecord.setQuotaCalculated(1);
_usageDao.persistUsage(usageRecord);
return quota_usage;
}
public QuotaUsageVO updateQuotaRaw(UsageVO usageRecord, final BigDecimal aggregationRatio, final int ruleType) {
QuotaUsageVO quota_usage = null;
QuotaTariffVO tariff = _quotaTariffDao.findTariffPlanByUsageType(ruleType, usageRecord.getEndDate());
if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) {
BigDecimal ruleusage;
BigDecimal onehourcost;
onehourcost = tariff.getCurrencyValue().multiply(aggregationRatio);
ruleusage = new BigDecimal(usageRecord.getRawUsage()).multiply(onehourcost);
quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), ruleType, ruleusage,
usageRecord.getStartDate(), usageRecord.getEndDate());
_quotaUsageDao.persistQuotaUsage(quota_usage);
}
usageRecord.setQuotaCalculated(1);
_usageDao.persistUsage(usageRecord);
return quota_usage;
}
public QuotaUsageVO updateQuotaNetwork(UsageVO usageRecord, final int transferType) {
QuotaUsageVO quota_usage = null;
QuotaTariffVO tariff = _quotaTariffDao.findTariffPlanByUsageType(transferType, usageRecord.getEndDate());
if (tariff != null && tariff.getCurrencyValue().compareTo(BigDecimal.ZERO) != 0) {
BigDecimal onegbcost;
BigDecimal rawusageingb;
BigDecimal networkusage;
onegbcost = tariff.getCurrencyValue();
rawusageingb = new BigDecimal(usageRecord.getRawUsage()).divide(s_gb, 8, RoundingMode.HALF_EVEN);
networkusage = rawusageingb.multiply(onegbcost);
quota_usage = new QuotaUsageVO(usageRecord.getId(), usageRecord.getZoneId(), usageRecord.getAccountId(), usageRecord.getDomainId(), transferType, networkusage,
usageRecord.getStartDate(), usageRecord.getEndDate());
_quotaUsageDao.persistQuotaUsage(quota_usage);
}
usageRecord.setQuotaCalculated(1);
_usageDao.persistUsage(usageRecord);
return quota_usage;
}
}

View File

@ -0,0 +1,26 @@
//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
//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;
import java.util.Calendar;
import com.cloud.utils.component.Manager;
public interface QuotaStatement extends Manager {
void sendStatement();
Calendar[] getCurrentStatementTime();
}

View File

@ -0,0 +1,376 @@
//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;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.ejb.Local;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.quota.QuotaAlertManagerImpl.DeferredQuotaEmail;
import org.apache.cloudstack.quota.constant.QuotaConfig;
import org.apache.cloudstack.quota.dao.QuotaAccountDao;
import org.apache.cloudstack.quota.dao.QuotaUsageDao;
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.user.AccountVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.component.ManagerBase;
@Component
@Local(value = QuotaStatement.class)
public class QuotaStatementImpl extends ManagerBase implements QuotaStatement {
private static final Logger s_logger = Logger.getLogger(QuotaStatementImpl.class);
@Inject
private AccountDao _accountDao;
@Inject
private QuotaAccountDao _quotaAcc;
@Inject
private QuotaUsageDao _quotaUsage;
@Inject
private QuotaAlertManager _quotaAlert;
@Inject
private ConfigurationDao _configDao;
final public static int s_LAST_STATEMENT_SENT_DAYS = 6; //ideally should be less than 7 days
public enum STATEMENT_PERIODS {
BIMONTHLY, MONTHLY, QUATERLY, HALFYEARLY, YEARLY
};
private STATEMENT_PERIODS _period = STATEMENT_PERIODS.MONTHLY;
public QuotaStatementImpl() {
super();
}
private void mergeConfigs(Map<String, String> dbParams, Map<String, Object> xmlParams) {
for (Map.Entry<String, Object> param : xmlParams.entrySet()) {
dbParams.put(param.getKey(), (String)param.getValue());
}
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params);
Map<String, String> configs = _configDao.getConfiguration(params);
if (params != null) {
mergeConfigs(configs, params);
}
String period_str = configs.get(QuotaConfig.QuotaStatementPeriod.key());
int period = period_str == null ? 1 : Integer.valueOf(period_str);
STATEMENT_PERIODS _period = STATEMENT_PERIODS.values()[period];
return true;
}
@Override
public boolean start() {
if (s_logger.isInfoEnabled()) {
s_logger.info("Starting Statement Manager");
}
return true;
}
@Override
public boolean stop() {
if (s_logger.isInfoEnabled()) {
s_logger.info("Stopping Statement Manager");
}
return true;
}
@Override
public void sendStatement() {
List<DeferredQuotaEmail> deferredQuotaEmailList = new ArrayList<DeferredQuotaEmail>();
for (final QuotaAccountVO quotaAccount : _quotaAcc.listAllQuotaAccount()) {
if (quotaAccount.getQuotaBalance() == null) {
continue; // no quota usage for this account ever, ignore
}
//check if it is statement time
Calendar interval[] = statementTime(Calendar.getInstance(), _period);
Date lastStatementDate = quotaAccount.getLastStatementDate();
if (interval != null) {
AccountVO account = _accountDao.findById(quotaAccount.getId());
if (lastStatementDate == null || getDifferenceDays(lastStatementDate, new Date()) >= s_LAST_STATEMENT_SENT_DAYS + 1) {
BigDecimal quotaUsage = _quotaUsage.findTotalQuotaUsage(account.getAccountId(), account.getDomainId(), null, interval[0].getTime(), interval[1].getTime());
s_logger.info("For account=" + quotaAccount.getId() + ", quota used = " + quotaUsage);
// send statement
deferredQuotaEmailList.add(new DeferredQuotaEmail(account, quotaAccount, quotaUsage, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_STATEMENT));
} else {
if (s_logger.isDebugEnabled()) {
s_logger.debug("For " + quotaAccount.getId() + " the statement has been sent recently");
}
}
} else if (lastStatementDate != null) {
s_logger.info("For " + quotaAccount.getId() + " it is already more than " + getDifferenceDays(lastStatementDate, new Date())
+ " days, will send statement in next cycle");
}
}
for (DeferredQuotaEmail emailToBeSent : deferredQuotaEmailList) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Attempting to send quota STATEMENT email to users of account: " + emailToBeSent.getAccount().getAccountName());
}
_quotaAlert.sendQuotaAlert(emailToBeSent);
}
}
@Override
public Calendar[] getCurrentStatementTime() {
final Calendar today = Calendar.getInstance();
int day_of_month = today.get(Calendar.DAY_OF_MONTH);
int month_of_year = today.get(Calendar.MONTH);
Calendar firstDateOfCurrentPeriod, lastDateOfCurrentPeriod;
Calendar aCalendar = (Calendar)today.clone();
aCalendar.add(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
lastDateOfCurrentPeriod = aCalendar;
switch (_period) {
case BIMONTHLY:
if (day_of_month < 16) {
aCalendar = (Calendar)today.clone();
aCalendar.add(Calendar.MONTH, 0);
aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfCurrentPeriod = aCalendar;
return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
} else {
aCalendar = (Calendar)today.clone();
aCalendar.set(Calendar.DATE, 16);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfCurrentPeriod = aCalendar;
return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
}
case MONTHLY:
aCalendar = (Calendar)today.clone();
aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfCurrentPeriod = aCalendar;
return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
case QUATERLY:
if (month_of_year < Calendar.APRIL) {
aCalendar = (Calendar)today.clone();
aCalendar.set(Calendar.MONTH, Calendar.JANUARY);
aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfCurrentPeriod = aCalendar;
return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
} else if (month_of_year < Calendar.JULY) {
aCalendar = (Calendar)today.clone();
aCalendar.set(Calendar.MONTH, Calendar.APRIL);
aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfCurrentPeriod = aCalendar;
return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
} else if (month_of_year < Calendar.OCTOBER) {
aCalendar = (Calendar)today.clone();
aCalendar.set(Calendar.MONTH, Calendar.JULY);
aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfCurrentPeriod = aCalendar;
return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
} else {
aCalendar = (Calendar)today.clone();
aCalendar.set(Calendar.MONTH, Calendar.OCTOBER);
aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfCurrentPeriod = aCalendar;
return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
}
case HALFYEARLY:
// statements are sent in Jan=1, Jul 7,
if (month_of_year < Calendar.JULY) {
aCalendar = (Calendar)today.clone();
aCalendar.set(Calendar.MONTH, Calendar.JANUARY);
aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfCurrentPeriod = aCalendar;
return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
} else {
aCalendar = (Calendar)today.clone();
aCalendar.set(Calendar.MONTH, Calendar.JULY);
aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfCurrentPeriod = aCalendar;
return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
}
case YEARLY:
aCalendar = (Calendar)today.clone();
aCalendar.add(Calendar.MONTH, Calendar.JANUARY);
aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfCurrentPeriod = aCalendar;
return new Calendar[] {firstDateOfCurrentPeriod, lastDateOfCurrentPeriod};
default:
break;
}
return null;
}
public Calendar[] statementTime(final Calendar today, final STATEMENT_PERIODS period) {
//check if it is statement time
int day_of_month = today.get(Calendar.DAY_OF_MONTH);
int month_of_year = today.get(Calendar.MONTH);
Calendar firstDateOfPreviousPeriod, lastDateOfPreviousPeriod;
switch (period) {
case BIMONTHLY:
if (day_of_month < s_LAST_STATEMENT_SENT_DAYS) {
Calendar aCalendar = (Calendar)today.clone();
aCalendar.add(Calendar.MONTH, 0);
aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfPreviousPeriod = (Calendar)aCalendar.clone();
aCalendar.set(Calendar.DATE, 15);
lastDateOfPreviousPeriod = (Calendar)aCalendar.clone();
return new Calendar[] {firstDateOfPreviousPeriod, lastDateOfPreviousPeriod};
} else if (day_of_month > 15 && (day_of_month - 15) < s_LAST_STATEMENT_SENT_DAYS) {
Calendar aCalendar = (Calendar)today.clone();
aCalendar.add(Calendar.MONTH, -1);
aCalendar.set(Calendar.DATE, 16);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfPreviousPeriod = (Calendar)aCalendar.clone();
aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
lastDateOfPreviousPeriod = (Calendar)aCalendar.clone();
return new Calendar[] {firstDateOfPreviousPeriod, lastDateOfPreviousPeriod};
}
return null;
case MONTHLY:
if (day_of_month < s_LAST_STATEMENT_SENT_DAYS) {
Calendar aCalendar = (Calendar)today.clone();
aCalendar.add(Calendar.MONTH, -1);
aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfPreviousPeriod = (Calendar)aCalendar.clone();
aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
lastDateOfPreviousPeriod = (Calendar)aCalendar.clone();
return new Calendar[] {firstDateOfPreviousPeriod, lastDateOfPreviousPeriod};
}
return null;
case QUATERLY:
// statements are sent in Jan=1, Apr 4, Jul 7, Oct 10
if (month_of_year == Calendar.JANUARY || month_of_year == Calendar.APRIL || month_of_year == Calendar.JULY || month_of_year == Calendar.OCTOBER) {
if (day_of_month < s_LAST_STATEMENT_SENT_DAYS) {
Calendar aCalendar = (Calendar)today.clone();
aCalendar.add(Calendar.MONTH, -3);
aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfPreviousPeriod = (Calendar)aCalendar.clone();
aCalendar.add(Calendar.MONTH, 2);
aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
lastDateOfPreviousPeriod = (Calendar)aCalendar.clone();
return new Calendar[] {firstDateOfPreviousPeriod, lastDateOfPreviousPeriod};
}
}
return null;
case HALFYEARLY:
// statements are sent in Jan=1, Jul 7,
if (month_of_year == Calendar.JANUARY || month_of_year == Calendar.JULY) {
if (day_of_month < s_LAST_STATEMENT_SENT_DAYS) {
Calendar aCalendar = (Calendar)today.clone();
aCalendar.add(Calendar.MONTH, -6);
aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfPreviousPeriod = (Calendar)aCalendar.clone();
aCalendar.add(Calendar.MONTH, 5);
aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
lastDateOfPreviousPeriod = (Calendar)aCalendar.clone();
return new Calendar[] {firstDateOfPreviousPeriod, lastDateOfPreviousPeriod};
}
}
return null;
case YEARLY:
// statements are sent in Jan=1
if (month_of_year == Calendar.JANUARY) {
if (day_of_month < s_LAST_STATEMENT_SENT_DAYS) {
Calendar aCalendar = (Calendar)today.clone();
aCalendar.add(Calendar.MONTH, -12);
aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.HOUR, 0);
aCalendar.set(Calendar.MINUTE, 0);
aCalendar.set(Calendar.SECOND, 0);
firstDateOfPreviousPeriod = (Calendar)aCalendar.clone();
aCalendar.add(Calendar.MONTH, 11);
aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
lastDateOfPreviousPeriod = (Calendar)aCalendar.clone();
return new Calendar[] {firstDateOfPreviousPeriod, lastDateOfPreviousPeriod};
}
}
return null;
default:
break;
}
return null;
}
public static long getDifferenceDays(Date d1, Date d2) {
long diff = d2.getTime() - d1.getTime();
return TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
}
}

View File

@ -0,0 +1,57 @@
//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.constant;
import org.apache.cloudstack.framework.config.ConfigKey;
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> QuotaEnableEnforcement = new ConfigKey<String>("Advanced", String.class, "quota.enable.enforcement", "false",
"Enable the usage quota enforcement, i.e. on true when exceeding quota the respective account will be locked.", true);
public static final ConfigKey<String> QuotaCurrencySymbol = new ConfigKey<String>("Advanced", String.class, "quota.currency.symbol", "$",
"The symbol for the currency in use to measure usage.", true);
public static final ConfigKey<Integer> QuotaStatementPeriod = new ConfigKey<Integer>("Advanced", Integer.class, "quota.statement.period", "1",
"This variables define the statement generation interval. Values correspond to bimonthly=0, monthly=1, quarterly=2, half-yearly=3 and yearly=4.", 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);
public static final ConfigKey<String> QuotaSmtpTimeout = new ConfigKey<String>("Advanced", String.class, "quota.usage.smtp.connection.timeout", "60",
"Quota SMTP server connection timeout duration", true);
public static final ConfigKey<String> QuotaSmtpUser = new ConfigKey<String>("Advanced", String.class, "quota.usage.smtp.user", "", "Quota SMTP server username", true);
public static final ConfigKey<String> QuotaSmtpPassword = new ConfigKey<String>("Advanced", String.class, "quota.usage.smtp.password", "", "Quota SMTP server password", true);
public static final ConfigKey<String> QuotaSmtpPort = new ConfigKey<String>("Advanced", String.class, "quota.usage.smtp.port", "", "Quota SMTP port", true);
public static final ConfigKey<String> QuotaSmtpAuthType = new ConfigKey<String>("Advanced", String.class, "quota.usage.smtp.useAuth", "",
"If true, use secure SMTP authentication when sending emails.", true);
public static final ConfigKey<String> QuotaSmtpSender = new ConfigKey<String>("Advanced", String.class, "quota.usage.smtp.sender", "",
"Sender of quota alert email (will be in the From header of the email)", true);
enum QuotaEmailTemplateTypes {
QUOTA_LOW, QUOTA_EMPTY, QUOTA_UNLOCK_ACCOUNT, QUOTA_STATEMENT
}
}

View File

@ -0,0 +1,103 @@
// 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.constant;
import org.apache.cloudstack.usage.UsageTypes;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class QuotaTypes extends UsageTypes {
public static final int CPU_CLOCK_RATE = 15;
public static final int CPU_NUMBER = 16;
public static final int MEMORY = 17;
private final Integer quotaType;
private final String quotaName;
private final String quotaUnit;
private final String description;
private final String discriminator;
private final static Map<Integer, QuotaTypes> quotaTypeMap;
static {
final HashMap<Integer, QuotaTypes> quotaTypeList = new HashMap<Integer, QuotaTypes>();
quotaTypeList.put(RUNNING_VM, new QuotaTypes(RUNNING_VM, "RUNNING_VM", "Compute-Month", "Running Vm Usage"));
quotaTypeList.put(ALLOCATED_VM, new QuotaTypes(ALLOCATED_VM, "ALLOCATED_VM", "Compute-Month", "Allocated Vm Usage"));
quotaTypeList.put(IP_ADDRESS, new QuotaTypes(IP_ADDRESS, "IP_ADDRESS", "IP-Month", "IP Address Usage"));
quotaTypeList.put(NETWORK_BYTES_SENT, new QuotaTypes(NETWORK_BYTES_SENT, "NETWORK_BYTES_SENT", "GB", "Network Usage (Bytes Sent)"));
quotaTypeList.put(NETWORK_BYTES_RECEIVED, new QuotaTypes(NETWORK_BYTES_RECEIVED, "NETWORK_BYTES_RECEIVED", "GB", "Network Usage (Bytes Received)"));
quotaTypeList.put(VOLUME, new QuotaTypes(VOLUME, "VOLUME", "GB-Month", "Volume Usage"));
quotaTypeList.put(TEMPLATE, new QuotaTypes(TEMPLATE, "TEMPLATE", "GB-Month", "Template Usage"));
quotaTypeList.put(ISO, new QuotaTypes(ISO, "ISO", "GB-Month", "ISO Usage"));
quotaTypeList.put(SNAPSHOT, new QuotaTypes(SNAPSHOT, "SNAPSHOT", "GB-Month", "Snapshot Usage"));
quotaTypeList.put(SECURITY_GROUP, new QuotaTypes(SECURITY_GROUP, "SECURITY_GROUP", "Policy-Month", "Security Group Usage"));
quotaTypeList.put(LOAD_BALANCER_POLICY, new QuotaTypes(LOAD_BALANCER_POLICY, "LOAD_BALANCER_POLICY", "Policy-Month", "Load Balancer Usage"));
quotaTypeList.put(PORT_FORWARDING_RULE, new QuotaTypes(PORT_FORWARDING_RULE, "PORT_FORWARDING_RULE", "Policy-Month", "Port Forwarding Usage"));
quotaTypeList.put(NETWORK_OFFERING, new QuotaTypes(NETWORK_OFFERING, "NETWORK_OFFERING", "Policy-Month", "Network Offering Usage"));
quotaTypeList.put(VPN_USERS, new QuotaTypes(VPN_USERS, "VPN_USERS", "Policy-Month", "VPN users usage"));
quotaTypeList.put(VM_DISK_IO_READ, new QuotaTypes(VM_DISK_IO_READ, "VM_DISK_IO_READ", "GB", "VM Disk usage(I/O Read)"));
quotaTypeList.put(VM_DISK_IO_WRITE, new QuotaTypes(VM_DISK_IO_WRITE, "VM_DISK_IO_WRITE", "GB", "VM Disk usage(I/O Write)"));
quotaTypeList.put(VM_DISK_BYTES_READ, new QuotaTypes(VM_DISK_BYTES_READ, "VM_DISK_BYTES_READ", "GB", "VM Disk usage(Bytes Read)"));
quotaTypeList.put(VM_DISK_BYTES_WRITE, new QuotaTypes(VM_DISK_BYTES_WRITE, "VPN_USERS", "GB", "VM Disk usage(Bytes Write)"));
quotaTypeList.put(VM_SNAPSHOT, new QuotaTypes(VM_SNAPSHOT, "VM_SNAPSHOT", "GB-Month", "VM Snapshot storage usage"));
quotaTypeList.put(CPU_CLOCK_RATE, new QuotaTypes(CPU_CLOCK_RATE, "CPU_CLOCK_RATE", "Compute-Month", "Quota tariff for using 1 CPU of clock rate 100MHz"));
quotaTypeList.put(CPU_NUMBER, new QuotaTypes(CPU_NUMBER, "CPU_NUMBER", "Compute-Month", "Quota tariff for running VM that has 1vCPU"));
quotaTypeList.put(MEMORY, new QuotaTypes(MEMORY, "MEMORY", "Compute-Month", "Quota tariff for using 1MB or RAM for 1 hour"));
quotaTypeMap = Collections.unmodifiableMap(quotaTypeList);
}
private QuotaTypes(Integer quotaType, String name, String unit, String description) {
this.quotaType = quotaType;
this.description = description;
this.quotaName = name;
this.quotaUnit = unit;
this.discriminator = "None";
}
public static Map<Integer, QuotaTypes> listQuotaTypes() {
return quotaTypeMap;
}
public String getDiscriminator() {
return discriminator;
}
public String getQuotaName() {
return quotaName;
}
public String getQuotaUnit() {
return quotaUnit;
}
public String getDescription() {
return description;
}
public Integer getQuotaType() {
return quotaType;
}
static public String getDescription(int quotaType) {
QuotaTypes t = quotaTypeMap.get(quotaType);
if (t != null) {
return t.getDescription();
}
return null;
}
}

View File

@ -0,0 +1,35 @@
//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 java.util.List;
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
import com.cloud.utils.db.GenericDao;
public interface QuotaAccountDao extends GenericDao<QuotaAccountVO, Long> {
List<QuotaAccountVO> listAllQuotaAccount();
QuotaAccountVO findByIdQuotaAccount(Long id);
QuotaAccountVO persistQuotaAccount(QuotaAccountVO entity);
boolean updateQuotaAccount(Long id, QuotaAccountVO entity);
}

View File

@ -0,0 +1,74 @@
//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.db.GenericDaoBase;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.TransactionStatus;
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.ejb.Local;
import java.util.List;
@Component
@Local(value = { QuotaAccountDao.class })
public class QuotaAccountDaoImpl extends GenericDaoBase<QuotaAccountVO, Long> implements QuotaAccountDao {
public static final Logger s_logger = Logger.getLogger(QuotaAccountDaoImpl.class);
public List<QuotaAccountVO> listAllQuotaAccount() {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaAccountVO>>() {
@Override
public List<QuotaAccountVO> doInTransaction(final TransactionStatus status) {
return listAll();
}
});
}
public QuotaAccountVO findByIdQuotaAccount(final Long id) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaAccountVO>() {
@Override
public QuotaAccountVO doInTransaction(final TransactionStatus status) {
return findById(id);
}
});
}
public QuotaAccountVO persistQuotaAccount(final QuotaAccountVO entity) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaAccountVO>() {
@Override
public QuotaAccountVO doInTransaction(final TransactionStatus status) {
return persist(entity);
}
});
}
public boolean updateQuotaAccount(final Long id, final QuotaAccountVO entity) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(final TransactionStatus status) {
return update(id, entity);
}
});
}
}

View File

@ -0,0 +1,43 @@
//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 java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
import com.cloud.utils.db.GenericDao;
public interface QuotaBalanceDao extends GenericDao<QuotaBalanceVO, Long> {
QuotaBalanceVO saveQuotaBalance(QuotaBalanceVO qb);
List<QuotaBalanceVO> findCreditBalance(Long accountId, Long domainId, Date startDate, Date endDate);
QuotaBalanceVO findLastBalanceEntry(Long accountId, Long domainId, Date beforeThis);
QuotaBalanceVO findLaterBalanceEntry(Long accountId, Long domainId, Date afterThis);
List<QuotaBalanceVO> findQuotaBalance(Long accountId, Long domainId, Date startDate, Date endDate);
List<QuotaBalanceVO> lastQuotaBalanceVO(Long accountId, Long domainId, Date startDate);
BigDecimal lastQuotaBalance(Long accountId, Long domainId, Date startDate);
}

View File

@ -0,0 +1,189 @@
//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.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.TransactionStatus;
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.ejb.Local;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@Component
@Local(value = {QuotaBalanceDao.class})
public class QuotaBalanceDaoImpl extends GenericDaoBase<QuotaBalanceVO, Long> implements QuotaBalanceDao {
private static final Logger s_logger = Logger.getLogger(QuotaBalanceDaoImpl.class.getName());
public QuotaBalanceVO findLastBalanceEntry(final Long accountId, final Long domainId, final Date beforeThis) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaBalanceVO>() {
@Override
public QuotaBalanceVO doInTransaction(final TransactionStatus status) {
List<QuotaBalanceVO> quotaBalanceEntries = new ArrayList<>();
Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", false, 0L, 1L);
QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
qb.and(qb.entity().getCreditsId(), SearchCriteria.Op.EQ, 0);
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.LT, beforeThis);
quotaBalanceEntries = search(qb.create(), filter);
return !quotaBalanceEntries.isEmpty() ? quotaBalanceEntries.get(0) : null;
}
});
}
public QuotaBalanceVO findLaterBalanceEntry(final Long accountId, final Long domainId, final Date afterThis) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaBalanceVO>() {
@Override
public QuotaBalanceVO doInTransaction(final TransactionStatus status) {
List<QuotaBalanceVO> quotaBalanceEntries = new ArrayList<>();
Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", true, 0L, 1L);
QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
qb.and(qb.entity().getCreditsId(), SearchCriteria.Op.EQ, 0);
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.GT, afterThis);
quotaBalanceEntries = search(qb.create(), filter);
return quotaBalanceEntries.size() > 0 ? quotaBalanceEntries.get(0) : null;
}
});
}
public QuotaBalanceVO saveQuotaBalance(final QuotaBalanceVO qb) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaBalanceVO>() {
@Override
public QuotaBalanceVO doInTransaction(final TransactionStatus status) {
return persist(qb);
}
});
}
public List<QuotaBalanceVO> findCreditBalance(final Long accountId, final Long domainId, final Date lastbalancedate, final Date beforeThis) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaBalanceVO>>() {
@Override
public List<QuotaBalanceVO> doInTransaction(final TransactionStatus status) {
if ((lastbalancedate != null) && (beforeThis != null) && lastbalancedate.before(beforeThis)) {
Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", true, 0L, Long.MAX_VALUE);
QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
qb.and(qb.entity().getCreditsId(), SearchCriteria.Op.GT, 0);
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.BETWEEN, lastbalancedate, beforeThis);
return search(qb.create(), filter);
} else {
return new ArrayList<QuotaBalanceVO>();
}
}
});
}
public List<QuotaBalanceVO> findQuotaBalance(final Long accountId, final Long domainId, final Date startDate, final Date endDate) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaBalanceVO>>() {
@Override
public List<QuotaBalanceVO> doInTransaction(final TransactionStatus status) {
List<QuotaBalanceVO> quotaUsageRecords = null;
QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
if (accountId != null) {
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
}
if (domainId != null) {
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
}
if ((startDate != null) && (endDate != null) && startDate.before(endDate)) {
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.BETWEEN, startDate, endDate);
} else {
return Collections.<QuotaBalanceVO> emptyList();
}
quotaUsageRecords = listBy(qb.create());
if (quotaUsageRecords.size() == 0) {
quotaUsageRecords.addAll(lastQuotaBalanceVO(accountId, domainId, startDate));
}
return quotaUsageRecords;
}
});
}
public List<QuotaBalanceVO> lastQuotaBalanceVO(final Long accountId, final Long domainId, final Date pivotDate) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaBalanceVO>>() {
@Override
public List<QuotaBalanceVO> doInTransaction(final TransactionStatus status) {
List<QuotaBalanceVO> quotaUsageRecords = null;
List<QuotaBalanceVO> trimmedRecords = new ArrayList<QuotaBalanceVO>();
Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", false, 0L, 100L);
// ASSUMPTION there will be less than 100 continuous credit
// transactions
QueryBuilder<QuotaBalanceVO> qb = QueryBuilder.create(QuotaBalanceVO.class);
if (accountId != null) {
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
}
if (domainId != null) {
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
}
if ((pivotDate != null)) {
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.LTEQ, pivotDate);
}
quotaUsageRecords = search(qb.create(), filter);
// get records before startDate to find start balance
for (QuotaBalanceVO entry : quotaUsageRecords) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("FindQuotaBalIance Entry=" + entry);
}
if (entry.getCreditsId() > 0) {
trimmedRecords.add(entry);
} else {
trimmedRecords.add(entry);
break; // add only consecutive credit entries and last balance entry
}
}
return trimmedRecords;
}
});
}
public BigDecimal lastQuotaBalance(final Long accountId, final Long domainId, Date startDate) {
List<QuotaBalanceVO> quotaBalance = lastQuotaBalanceVO(accountId, domainId, startDate);
BigDecimal finalBalance = new BigDecimal(0);
if (quotaBalance.isEmpty()) {
s_logger.info("There are no balance entries on or before the requested date.");
return finalBalance;
}
for (QuotaBalanceVO entry : quotaBalance) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("lastQuotaBalance Entry=" + entry);
}
finalBalance = finalBalance.add(entry.getCreditBalance());
}
return finalBalance;
}
}

View File

@ -0,0 +1,32 @@
//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 java.util.Date;
import java.util.List;
import org.apache.cloudstack.quota.vo.QuotaCreditsVO;
import com.cloud.utils.db.GenericDao;
public interface QuotaCreditsDao extends GenericDao<QuotaCreditsVO, Long> {
List<QuotaCreditsVO> findCredits(long accountId, long domainId, Date startDate, Date endDate);
QuotaCreditsVO saveCredits(QuotaCreditsVO credits);
}

View File

@ -0,0 +1,78 @@
//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 java.util.Collections;
import java.util.Date;
import java.util.List;
import javax.ejb.Local;
import javax.inject.Inject;
import org.springframework.stereotype.Component;
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
import org.apache.cloudstack.quota.vo.QuotaCreditsVO;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.TransactionStatus;
@Component
@Local(value = { QuotaCreditsDao.class })
public class QuotaCreditsDaoImpl extends GenericDaoBase<QuotaCreditsVO, Long> implements QuotaCreditsDao {
@Inject
QuotaBalanceDao _quotaBalanceDao;
@Override
public List<QuotaCreditsVO> findCredits(final long accountId, final long domainId, final Date startDate, final Date endDate) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaCreditsVO>>() {
@Override
public List<QuotaCreditsVO> doInTransaction(final TransactionStatus status) {
if ((startDate != null) && (endDate != null) && startDate.before(endDate)) {
Filter filter = new Filter(QuotaCreditsVO.class, "updatedOn", true, 0L, Long.MAX_VALUE);
QueryBuilder<QuotaCreditsVO> qb = QueryBuilder.create(QuotaCreditsVO.class);
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
qb.and(qb.entity().getUpdatedOn(), SearchCriteria.Op.BETWEEN, startDate, endDate);
return search(qb.create(), filter);
} else {
return Collections.<QuotaCreditsVO> emptyList();
}
}
});
}
@Override
public QuotaCreditsVO saveCredits(final QuotaCreditsVO credits) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaCreditsVO>() {
@Override
public QuotaCreditsVO doInTransaction(final TransactionStatus status) {
persist(credits);
// make an entry in the balance table
QuotaBalanceVO bal = new QuotaBalanceVO(credits);
_quotaBalanceDao.persist(bal);
return credits;
}
});
}
}

View File

@ -0,0 +1,27 @@
//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.db.GenericDao;
import org.apache.cloudstack.quota.vo.QuotaEmailTemplatesVO;
import java.util.List;
public interface QuotaEmailTemplatesDao extends GenericDao<QuotaEmailTemplatesVO, Long> {
List<QuotaEmailTemplatesVO> listAllQuotaEmailTemplates(String templateName);
boolean updateQuotaEmailTemplate(QuotaEmailTemplatesVO template);
}

View File

@ -0,0 +1,74 @@
//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.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.TransactionStatus;
import com.google.common.base.Strings;
import org.apache.cloudstack.quota.vo.QuotaEmailTemplatesVO;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.ejb.Local;
import java.util.List;
@Component
@Local(value = { QuotaEmailTemplatesDao.class })
public class QuotaEmailTemplatesDaoImpl extends GenericDaoBase<QuotaEmailTemplatesVO, Long> implements QuotaEmailTemplatesDao {
private static final Logger s_logger = Logger.getLogger(QuotaEmailTemplatesDaoImpl.class);
protected SearchBuilder<QuotaEmailTemplatesVO> QuotaEmailTemplateSearch;
public QuotaEmailTemplatesDaoImpl() {
super();
QuotaEmailTemplateSearch = createSearchBuilder();
QuotaEmailTemplateSearch.and("template_name", QuotaEmailTemplateSearch.entity().getTemplateName(), SearchCriteria.Op.EQ);
QuotaEmailTemplateSearch.done();
}
@Override
public List<QuotaEmailTemplatesVO> listAllQuotaEmailTemplates(final String templateName) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaEmailTemplatesVO>>() {
@Override
public List<QuotaEmailTemplatesVO> doInTransaction(final TransactionStatus status) {
SearchCriteria<QuotaEmailTemplatesVO> sc = QuotaEmailTemplateSearch.create();
if (!Strings.isNullOrEmpty(templateName)) {
sc.setParameters("template_name", templateName);
}
return listBy(sc);
}
});
}
@Override
public boolean updateQuotaEmailTemplate(final QuotaEmailTemplatesVO template) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(final TransactionStatus status) {
return update(template.getId(), template);
}
});
}
}

View File

@ -0,0 +1,37 @@
//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.db.GenericDao;
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
import java.util.Date;
import java.util.List;
public interface QuotaTariffDao extends GenericDao<QuotaTariffVO, Long> {
QuotaTariffVO findTariffPlanByUsageType(int quotaType, Date onOrBefore);
List<QuotaTariffVO> listAllTariffPlans();
List<QuotaTariffVO> listAllTariffPlans(Date onOrBefore);
Boolean updateQuotaTariff(QuotaTariffVO plan);
QuotaTariffVO addQuotaTariff(QuotaTariffVO plan);
}

View File

@ -0,0 +1,133 @@
//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.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.TransactionStatus;
import org.apache.cloudstack.quota.constant.QuotaTypes;
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.ejb.Local;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Component
@Local(value = {QuotaTariffDao.class})
public class QuotaTariffDaoImpl extends GenericDaoBase<QuotaTariffVO, Long> implements QuotaTariffDao {
private static final Logger s_logger = Logger.getLogger(QuotaTariffDaoImpl.class.getName());
private final SearchBuilder<QuotaTariffVO> searchUsageType;
private final SearchBuilder<QuotaTariffVO> listAllIncludedUsageType;
public QuotaTariffDaoImpl() {
super();
searchUsageType = createSearchBuilder();
searchUsageType.and("usage_type", searchUsageType.entity().getUsageType(), SearchCriteria.Op.EQ);
searchUsageType.done();
listAllIncludedUsageType = createSearchBuilder();
listAllIncludedUsageType.and("onorbefore", listAllIncludedUsageType.entity().getEffectiveOn(), SearchCriteria.Op.LTEQ);
listAllIncludedUsageType.and("quotatype", listAllIncludedUsageType.entity().getUsageType(), SearchCriteria.Op.EQ);
listAllIncludedUsageType.done();
}
public QuotaTariffVO findTariffPlanByUsageType(final int quotaType, final Date effectiveDate) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaTariffVO>() {
@Override
public QuotaTariffVO doInTransaction(final TransactionStatus status) {
List<QuotaTariffVO> result = new ArrayList<>();
final Filter filter = new Filter(QuotaTariffVO.class, "updatedOn", false, 0L, 1L);
final SearchCriteria<QuotaTariffVO> sc = listAllIncludedUsageType.create();
sc.setParameters("onorbefore", effectiveDate);
sc.setParameters("quotatype", quotaType);
result = search(sc, filter);
if (result != null && !result.isEmpty()) {
return result.get(0);
} else {
if (s_logger.isDebugEnabled()) {
s_logger.debug("QuotaTariffDaoImpl::findTariffPlanByUsageType: Missing quota type " + quotaType);
}
return null;
}
}
});
}
public List<QuotaTariffVO> listAllTariffPlans() {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaTariffVO>>() {
@Override
public List<QuotaTariffVO> doInTransaction(final TransactionStatus status) {
return listAll();
}
});
}
public List<QuotaTariffVO> listAllTariffPlans(final Date effectiveDate) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaTariffVO>>() {
@Override
public List<QuotaTariffVO> doInTransaction(final TransactionStatus status) {
List<QuotaTariffVO> tariffs = new ArrayList<QuotaTariffVO>();
final Filter filter = new Filter(QuotaTariffVO.class, "updatedOn", false, 0L, 1L);
final SearchCriteria<QuotaTariffVO> sc = listAllIncludedUsageType.create();
sc.setParameters("onorbefore", effectiveDate);
for (Integer quotaType : QuotaTypes.listQuotaTypes().keySet()) {
sc.setParameters("quotatype", quotaType);
List<QuotaTariffVO> result = search(sc, filter);
if (result != null && !result.isEmpty()) {
tariffs.add(result.get(0));
if (s_logger.isDebugEnabled()) {
s_logger.debug("ListAllTariffPlans on or before " + effectiveDate + " quota type " + result.get(0).getDescription() + " , effective Date="
+ result.get(0).getEffectiveOn() + " val=" + result.get(0).getCurrencyValue());
}
}
}
return tariffs;
}
});
}
public Boolean updateQuotaTariff(final QuotaTariffVO plan) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(final TransactionStatus status) {
return update(plan.getId(), plan);
}
});
}
public QuotaTariffVO addQuotaTariff(final QuotaTariffVO plan) {
if (plan.getIdObj() != null) {
throw new IllegalStateException("The QuotaTariffVO being added should not have an Id set ");
}
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaTariffVO>() {
@Override
public QuotaTariffVO doInTransaction(final TransactionStatus status) {
return persist(plan);
}
});
}
}

View File

@ -0,0 +1,35 @@
//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.db.GenericDao;
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
public interface QuotaUsageDao extends GenericDao<QuotaUsageVO, Long> {
QuotaUsageVO persistQuotaUsage(QuotaUsageVO quotaUsage);
List<QuotaUsageVO> findQuotaUsage(Long accountId, Long domainId, Integer usageType, Date startDate, Date endDate);
BigDecimal findTotalQuotaUsage(Long accountId, Long domainId, Integer usageType, Date startDate, Date endDate);
QuotaUsageVO findLastQuotaUsageEntry(Long accountId, Long domainId, Date beforeThis);
}

View File

@ -0,0 +1,116 @@
//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.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.TransactionStatus;
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.ejb.Local;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Component
@Local(value = {QuotaUsageDao.class})
public class QuotaUsageDaoImpl extends GenericDaoBase<QuotaUsageVO, Long> implements QuotaUsageDao {
private static final Logger s_logger = Logger.getLogger(QuotaUsageDaoImpl.class);
public BigDecimal findTotalQuotaUsage(final Long accountId, final Long domainId, final Integer usageType, final Date startDate, final Date endDate) {
List<QuotaUsageVO> quotaUsage = findQuotaUsage(accountId, domainId, null, startDate, endDate);
BigDecimal total = new BigDecimal(0);
for (QuotaUsageVO quotaRecord : quotaUsage) {
total = total.add(quotaRecord.getQuotaUsed());
}
return total;
}
public List<QuotaUsageVO> findQuotaUsage(final Long accountId, final Long domainId, final Integer usageType, final Date startDate, final Date endDate) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<List<QuotaUsageVO>>() {
@Override
public List<QuotaUsageVO> doInTransaction(final TransactionStatus status) {
List<QuotaUsageVO> quv;
if ((startDate != null) && (endDate != null) && startDate.before(endDate)) {
QueryBuilder<QuotaUsageVO> qb = QueryBuilder.create(QuotaUsageVO.class);
if (accountId != null) {
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
}
if (domainId != null) {
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
}
if (usageType != null) {
qb.and(qb.entity().getUsageType(), SearchCriteria.Op.EQ, usageType);
}
qb.and(qb.entity().getStartDate(), SearchCriteria.Op.BETWEEN, startDate, endDate);
qb.and(qb.entity().getEndDate(), SearchCriteria.Op.BETWEEN, startDate, endDate);
quv = listBy(qb.create());
} else {
quv = new ArrayList<QuotaUsageVO>();
}
if (quv.isEmpty()){
//add a dummy entry
QuotaUsageVO qu = new QuotaUsageVO();
qu.setAccountId(accountId);
qu.setDomainId(domainId);
qu.setStartDate(startDate);
qu.setEndDate(endDate);
qu.setQuotaUsed(new BigDecimal(0));
qu.setUsageType(-1);
quv.add(qu);
}
return quv;
}
});
}
public QuotaUsageVO findLastQuotaUsageEntry(final Long accountId, final Long domainId, final Date beforeThis) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaUsageVO>() {
@Override
public QuotaUsageVO doInTransaction(final TransactionStatus status) {
List<QuotaUsageVO> quotaUsageEntries = new ArrayList<>();
Filter filter = new Filter(QuotaUsageVO.class, "startDate", false, 0L, 1L);
QueryBuilder<QuotaUsageVO> qb = QueryBuilder.create(QuotaUsageVO.class);
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
qb.and(qb.entity().getDomainId(), SearchCriteria.Op.EQ, domainId);
qb.and(qb.entity().getStartDate(), SearchCriteria.Op.LT, beforeThis);
quotaUsageEntries = search(qb.create(), filter);
return !quotaUsageEntries.isEmpty() ? quotaUsageEntries.get(0) : null;
}
});
}
public QuotaUsageVO persistQuotaUsage(final QuotaUsageVO quotaUsage) {
return Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<QuotaUsageVO>() {
@Override
public QuotaUsageVO doInTransaction(final TransactionStatus status) {
return persist(quotaUsage);
}
});
}
}

View File

@ -0,0 +1,25 @@
// 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 org.apache.cloudstack.quota.vo.ServiceOfferingVO;
import com.cloud.utils.db.GenericDao;
public interface ServiceOfferingDao extends GenericDao<ServiceOfferingVO, Long> {
ServiceOfferingVO findServiceOffering(Long vmId, long serviceOfferingId);
}

View File

@ -0,0 +1,84 @@
// 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 java.util.Map;
import javax.ejb.Local;
import javax.inject.Inject;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.apache.cloudstack.quota.vo.ServiceOfferingVO;
import com.cloud.event.UsageEventVO;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.TransactionStatus;
import com.cloud.utils.exception.CloudRuntimeException;
@Component
@Local(value = {ServiceOfferingDao.class})
@DB()
public class ServiceOfferingDaoImpl extends GenericDaoBase<ServiceOfferingVO, Long> implements ServiceOfferingDao {
protected static final Logger s_logger = Logger.getLogger(ServiceOfferingDaoImpl.class);
@Inject
UserVmDetailsDao userVmDetailsDao;
public ServiceOfferingVO findServiceOffering(final Long vmId, final long serviceOfferingId) {
return Transaction.execute(TransactionLegacy.CLOUD_DB, new TransactionCallback<ServiceOfferingVO>() {
@Override
public ServiceOfferingVO doInTransaction(final TransactionStatus status) {
ServiceOfferingVO offering = findById(serviceOfferingId);
if (offering.isDynamic()) {
if (vmId == null) {
throw new CloudRuntimeException("missing argument vmId");
}
offering.setDynamicFlag(true);
Map<String, String> dynamicOffering = userVmDetailsDao.listDetailsKeyPairs(vmId);
return getcomputeOffering(offering, dynamicOffering);
}
return offering;
}
});
}
private ServiceOfferingVO getcomputeOffering(final ServiceOfferingVO serviceOffering, final Map<String, String> customParameters) {
return Transaction.execute(TransactionLegacy.CLOUD_DB, new TransactionCallback<ServiceOfferingVO>() {
@Override
public ServiceOfferingVO doInTransaction(final TransactionStatus status) {
ServiceOfferingVO dummyoffering = new ServiceOfferingVO(serviceOffering);
dummyoffering.setDynamicFlag(true);
if (customParameters.containsKey(UsageEventVO.DynamicParameters.cpuNumber.name())) {
dummyoffering.setCpu(Integer.parseInt(customParameters.get(UsageEventVO.DynamicParameters.cpuNumber.name())));
}
if (customParameters.containsKey(UsageEventVO.DynamicParameters.cpuSpeed.name())) {
dummyoffering.setSpeed(Integer.parseInt(customParameters.get(UsageEventVO.DynamicParameters.cpuSpeed.name())));
}
if (customParameters.containsKey(UsageEventVO.DynamicParameters.memory.name())) {
dummyoffering.setRamSize(Integer.parseInt(customParameters.get(UsageEventVO.DynamicParameters.memory.name())));
}
return dummyoffering;
}
});
}
}

View File

@ -0,0 +1,27 @@
// 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 java.util.Map;
import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.quota.vo.UserVmDetailVO;
public interface UserVmDetailsDao extends GenericDao<UserVmDetailVO, Long> {
Map<String, String> listDetailsKeyPairs(long resourceId);
}

View File

@ -0,0 +1,59 @@
// 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 java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.Local;
import org.springframework.stereotype.Component;
import org.apache.cloudstack.quota.vo.UserVmDetailVO;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
@Component
@Local(value = UserVmDetailsDao.class)
public class UserVmDetailsDaoImpl extends GenericDaoBase<UserVmDetailVO, Long> implements UserVmDetailsDao {
private SearchBuilder<UserVmDetailVO> AllFieldsSearch;
public UserVmDetailsDaoImpl() {
AllFieldsSearch = createSearchBuilder();
AllFieldsSearch.and("resourceId", AllFieldsSearch.entity().getResourceId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("name", AllFieldsSearch.entity().getName(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("value", AllFieldsSearch.entity().getValue(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("display", AllFieldsSearch.entity().isDisplay(), SearchCriteria.Op.EQ);
AllFieldsSearch.done();
}
@Override
public Map<String, String> listDetailsKeyPairs(long resourceId) {
Map<String, String> details = new HashMap<String, String>();
SearchCriteria<UserVmDetailVO> sc = AllFieldsSearch.create();
sc.setParameters("resourceId", resourceId);
List<UserVmDetailVO> results = search(sc, null);
for (UserVmDetailVO result : results) {
details.put(result.getName(), result.getValue());
}
return details;
}
}

View File

@ -0,0 +1,149 @@
//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.vo;
import org.apache.cloudstack.api.InternalIdentity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.math.BigDecimal;
import java.util.Date;
@Entity
@Table(name = "quota_account")
public class QuotaAccountVO implements InternalIdentity {
private static final long serialVersionUID = -7112846845287653210L;
@Id
@Column(name = "account_id")
private Long accountId = null;
@Column(name = "quota_enforce")
private Integer quotaEnforce = 0;
@Column(name = "quota_balance")
private BigDecimal quotaBalance;
@Column(name = "quota_balance_date")
@Temporal(value = TemporalType.TIMESTAMP)
private Date quotaBalanceDate = null;
@Column(name = "quota_min_balance")
private BigDecimal quotaMinBalance;
@Column(name = "quota_alert_type")
private Integer quotaAlertType = null;
@Column(name = "quota_alert_date")
@Temporal(value = TemporalType.TIMESTAMP)
private Date quotaAlertDate = null;
@Column(name = "last_statement_date")
@Temporal(value = TemporalType.TIMESTAMP)
private Date lastStatementDate = null;
public QuotaAccountVO() {
}
public QuotaAccountVO(Long accountId) {
super();
this.accountId = accountId;
}
@Override
public long getId() {
return accountId;
}
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public Integer getQuotaEnforce() {
return quotaEnforce == null ? 0 : quotaEnforce;
}
public void setQuotaEnforce(Integer quotaEnforce) {
this.quotaEnforce = quotaEnforce;
}
public BigDecimal getQuotaBalance() {
return quotaBalance;
}
public void setQuotaBalance(BigDecimal quotaBalance) {
this.quotaBalance = quotaBalance;
}
public BigDecimal getQuotaMinBalance() {
return quotaMinBalance == null ? new BigDecimal(0) : quotaMinBalance;
}
public void setQuotaMinBalance(BigDecimal quotaMinBalance) {
this.quotaMinBalance = quotaMinBalance;
}
public Integer getQuotaAlertType() {
return quotaAlertType;
}
public void setQuotaAlertType(Integer quotaAlertType) {
this.quotaAlertType = quotaAlertType;
}
public Date getQuotaAlertDate() {
return quotaAlertDate == null ? null : new Date(quotaAlertDate.getTime());
}
public void setQuotaAlertDate(Date quotaAlertDate) {
this.quotaAlertDate = quotaAlertDate == null ? null : new Date(quotaAlertDate.getTime());
}
public Date getQuotaBalanceDate() {
return quotaBalanceDate == null ? null : new Date(quotaBalanceDate.getTime());
}
public void setQuotaBalanceDate(Date quotaBalanceDate) {
this.quotaBalanceDate = quotaBalanceDate == null ? null : new Date(quotaBalanceDate.getTime());
}
public Date getLastStatementDate() {
return lastStatementDate == null ? null : new Date(lastStatementDate.getTime());
}
public void setLastStatementDate(Date lastStatementDate) {
this.lastStatementDate = lastStatementDate == null ? null : new Date(lastStatementDate.getTime());
}
@Override
public String toString() {
return "QuotaAccountVO [accountId=" + accountId + ", quotaEnforce=" + quotaEnforce + ", quotaBalance=" + quotaBalance + ", quotaBalanceDate=" + quotaBalanceDate
+ ", quotaMinBalance=" + quotaMinBalance + ", quotaAlertType=" + quotaAlertType + ", quotaAlertDate=" + quotaAlertDate + ", lastStatementDate=" + lastStatementDate
+ "]";
}
}

View File

@ -0,0 +1,133 @@
//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.vo;
import org.apache.cloudstack.api.InternalIdentity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.math.BigDecimal;
import java.util.Date;
@Entity
@Table(name = "quota_balance")
public class QuotaBalanceVO implements InternalIdentity {
private static final long serialVersionUID = -7112846845287653210L;
@Id
@Column(name = "id")
private Long id;
@Column(name = "account_id")
private Long accountId = null;
@Column(name = "domain_id")
private Long domainId = null;
@Column(name = "credit_balance")
private BigDecimal creditBalance;
@Column(name = "credits_id")
private Long creditsId;
@Column(name = "updated_on")
@Temporal(value = TemporalType.TIMESTAMP)
private Date updatedOn = null;
public QuotaBalanceVO() {
}
public QuotaBalanceVO(final QuotaCreditsVO credit) {
super();
this.accountId = credit.getAccountId();
this.domainId = credit.getDomainId();
this.creditBalance = credit.getCredit();
this.updatedOn = credit.getUpdatedOn() == null ? null : new Date(credit.getUpdatedOn().getTime());
this.creditsId = credit.getId();
}
public QuotaBalanceVO(final Long accountId, final Long domainId, final BigDecimal creditBalance, final Date updatedOn) {
super();
this.accountId = accountId;
this.domainId = domainId;
this.creditBalance = creditBalance;
this.creditsId = 0L;
this.updatedOn = updatedOn == null ? null : new Date(updatedOn.getTime());
}
@Override
public long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public Long getDomainId() {
return domainId;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public Long getCreditsId() {
return creditsId;
}
public void setCreditsId(Long creditsId) {
this.creditsId = creditsId;
}
public BigDecimal getCreditBalance() {
return creditBalance;
}
public void setCreditBalance(BigDecimal creditBalance) {
this.creditBalance = creditBalance;
}
public Date getUpdatedOn() {
return updatedOn == null ? null : new Date(updatedOn.getTime());
}
public void setUpdatedOn(Date updatedOn) {
this.updatedOn = updatedOn == null ? null : new Date(updatedOn.getTime());
}
@Override
public String toString() {
return "QuotaBalanceVO [id=" + id + ", accountId=" + accountId + ", domainId=" + domainId + ", creditBalance=" + creditBalance + ", creditsId=" + creditsId + ", updatedOn="
+ updatedOn + "]";
}
}

View File

@ -0,0 +1,116 @@
//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.vo;
import org.apache.cloudstack.api.InternalIdentity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.math.BigDecimal;
import java.util.Date;
@Entity
@Table(name = "quota_credits")
public class QuotaCreditsVO implements InternalIdentity {
private static final long serialVersionUID = -3576833845287653210L;
@Id
@Column(name = "id")
private Long id;
@Column(name = "account_id")
private Long accountId = null;
@Column(name = "domain_id")
private Long domainId = null;
@Column(name = "credit")
private BigDecimal credit;
@Column(name = "updated_on")
@Temporal(value = TemporalType.TIMESTAMP)
private Date updatedOn = null;
public QuotaCreditsVO() {
}
public QuotaCreditsVO(long accountId, long domainId, BigDecimal credit, long updatedBy) {
super();
this.accountId = accountId;
this.domainId = domainId;
this.credit = credit;
this.updatedBy = updatedBy;
}
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public Long getDomainId() {
return domainId;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public BigDecimal getCredit() {
return credit;
}
public void setCredit(BigDecimal credit) {
this.credit = credit;
}
public Date getUpdatedOn() {
return updatedOn == null ? null : new Date(updatedOn.getTime());
}
public void setUpdatedOn(Date updatedOn) {
this.updatedOn = updatedOn == null ? null : new Date(updatedOn.getTime());
}
public Long getUpdatedBy() {
return updatedBy;
}
public void setUpdatedBy(Long updatedBy) {
this.updatedBy = updatedBy;
}
public void setId(Long id) {
this.id = id;
}
// User ID of the creditor
@Column(name = "updated_by")
private Long updatedBy = null;
@Override
public long getId() {
return this.id;
}
}

View File

@ -0,0 +1,109 @@
//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.vo;
import org.apache.cloudstack.api.InternalIdentity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.util.Date;
@Entity
@Table(name = "quota_email_templates")
public class QuotaEmailTemplatesVO implements InternalIdentity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "template_name")
private String templateName;
@Column(name = "template_subject")
private String templateSubject;
@Column(name = "template_body")
private String templateBody;
@Column(name = "locale")
private String locale;
@Column(name = "updated")
@Temporal(value = TemporalType.TIMESTAMP)
private Date lastUpdated = null;
public QuotaEmailTemplatesVO() {
}
public QuotaEmailTemplatesVO(String templateName, String templateSubject, String templateBody) {
super();
this.templateName = templateName;
this.templateSubject = templateSubject;
this.templateBody = templateBody;
}
@Override
public long getId() {
return id;
}
public String getTemplateName() {
return templateName;
}
public void setTemplateName(String templateName) {
this.templateName = templateName;
}
public String getTemplateSubject() {
return templateSubject;
}
public void setTemplateSubject(String templateSubject) {
this.templateSubject = templateSubject;
}
public String getTemplateBody() {
return templateBody;
}
public void setTemplateBody(String templateBody) {
this.templateBody = templateBody;
}
public Date getLastUpdated() {
return lastUpdated == null ? null : new Date(lastUpdated.getTime());
}
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated == null ? null : new Date(lastUpdated.getTime());
}
public String getLocale() {
return locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
}

View File

@ -0,0 +1,170 @@
//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.vo;
import org.apache.cloudstack.api.InternalIdentity;
import org.apache.cloudstack.quota.constant.QuotaTypes;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.math.BigDecimal;
import java.util.Date;
@Entity
@Table(name = "quota_tariff")
public class QuotaTariffVO implements InternalIdentity {
private static final long serialVersionUID = -7117933766387653203L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "usage_type")
private int usageType;
@Column(name = "usage_name")
private String usageName;
@Column(name = "usage_unit")
private String usageUnit;
@Column(name = "usage_discriminator")
private String usageDiscriminator;
@Column(name = "currency_value")
private BigDecimal currencyValue;
@Column(name = "effective_on")
@Temporal(value = TemporalType.TIMESTAMP)
private Date effectiveOn = null;
@Column(name = "updated_on")
@Temporal(value = TemporalType.TIMESTAMP)
private Date updatedOn = null;
@Column(name = "updated_by")
private Long updatedBy = null;
public QuotaTariffVO() {
}
public QuotaTariffVO(final int usagetype) {
this.usageType = usagetype;
}
public QuotaTariffVO(final int usagetype, final String usagename, final String usageunit, final String usagediscriminator, final BigDecimal currencyvalue,
final Date effectiveOn, final Date updatedOn, final long updatedBy) {
this.usageType = usagetype;
this.usageName = usagename;
this.usageUnit = usageunit;
this.usageDiscriminator = usagediscriminator;
this.currencyValue = currencyvalue;
this.effectiveOn = effectiveOn;
this.updatedOn = updatedOn == null ? null : new Date(updatedOn.getTime());
this.updatedBy = updatedBy;
}
public void setId(Long id) {
this.id = id;
}
public Date getEffectiveOn() {
return effectiveOn == null ? null : new Date(effectiveOn.getTime());
}
public void setEffectiveOn(Date effectiveOn) {
this.effectiveOn = effectiveOn == null ? null : new Date(effectiveOn.getTime());
}
public Date getUpdatedOn() {
return updatedOn == null ? null : new Date(updatedOn.getTime());
}
public void setUpdatedOn(Date updatedOn) {
this.updatedOn = updatedOn == null ? null : new Date(updatedOn.getTime());
}
public Long getUpdatedBy() {
return updatedBy;
}
public void setUpdatedBy(Long updatedBy) {
this.updatedBy = updatedBy;
}
public int getUsageType() {
return usageType;
}
public void setUsageType(int usageType) {
this.usageType = usageType;
}
public String getUsageName() {
return usageName;
}
public void setUsageName(String usageName) {
this.usageName = usageName;
}
public String getUsageUnit() {
return usageUnit;
}
public void setUsageUnit(String usageUnit) {
this.usageUnit = usageUnit;
}
public String getUsageDiscriminator() {
return usageDiscriminator;
}
public void setUsageDiscriminator(String usageDiscriminator) {
this.usageDiscriminator = usageDiscriminator;
}
public BigDecimal getCurrencyValue() {
return currencyValue;
}
public void setCurrencyValue(BigDecimal currencyValue) {
this.currencyValue = currencyValue;
}
public String getDescription() {
return QuotaTypes.getDescription(usageType);
}
public Long getIdObj(){
return id;
}
@Override
public long getId() {
return this.id;
}
}

View File

@ -0,0 +1,177 @@
//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.vo;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.apache.cloudstack.api.InternalIdentity;
@Entity
@Table(name = "quota_usage")
public class QuotaUsageVO implements InternalIdentity {
private static final long serialVersionUID = -7117933845287204781L;
@Id
@Column(name = "id")
private Long id;
@Column(name = "zone_id")
private Long zoneId = null;
@Column(name = "account_id")
private Long accountId = null;
@Column(name = "domain_id")
private Long domainId = null;
@Column(name = "usage_item_id")
private Long usageItemId;
@Column(name = "usage_type")
private int usageType;
@Column(name = "quota_used")
private BigDecimal quotaUsed;
@Column(name = "start_date")
@Temporal(value = TemporalType.TIMESTAMP)
private Date startDate = null;
@Column(name = "end_date")
@Temporal(value = TemporalType.TIMESTAMP)
private Date endDate = null;
public QuotaUsageVO() {
usageType = -1;
quotaUsed = new BigDecimal(0);
endDate = new Date();
startDate = new Date();
}
public QuotaUsageVO(Long usageItemId, Long zoneId, Long accountId, Long domainId, int usageType, BigDecimal quotaUsed, Date startDate, Date endDate) {
super();
this.usageItemId = usageItemId;
this.zoneId = zoneId;
this.accountId = accountId;
this.domainId = domainId;
this.usageType = usageType;
this.quotaUsed = quotaUsed;
this.startDate = startDate == null ? null : new Date(startDate.getTime());
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public QuotaUsageVO(QuotaUsageVO toclone) {
super();
this.usageItemId = toclone.usageItemId;
this.zoneId = toclone.zoneId;
this.accountId = toclone.accountId;
this.domainId = toclone.domainId;
this.usageType = toclone.usageType;
this.quotaUsed = toclone.quotaUsed;
this.startDate = startDate == null ? null : new Date(startDate.getTime());
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public Long getZoneId() {
return zoneId;
}
public void setZoneId(Long zoneId) {
this.zoneId = zoneId;
}
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public Long getDomainId() {
return domainId;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
@Override
public long getId() {
return id;
}
public Long getUsageItemId() {
return usageItemId;
}
public void setUsageItemId(Long usageItemId) {
this.usageItemId = usageItemId;
}
public int getUsageType() {
return usageType;
}
public void setUsageType(int usageType) {
this.usageType = usageType;
}
public BigDecimal getQuotaUsed() {
return quotaUsed;
}
public void setQuotaUsed(BigDecimal quotaUsed) {
this.quotaUsed = quotaUsed;
}
public Date getStartDate() {
return startDate == null ? null : new Date(startDate.getTime());
}
public void setStartDate(Date startDate) {
this.startDate = startDate == null ? null : new Date(startDate.getTime());
}
public Date getEndDate() {
return endDate == null ? null : new Date(endDate.getTime());
}
public void setEndDate(Date endDate) {
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public void setId(Long id) {
this.id = id;
}
@Override
public String toString() {
return "QuotaUsageVO [id=" + id + ", zoneId=" + zoneId + ", accountId=" + accountId + ", domainId=" + domainId + ", usageItemId=" + usageItemId + ", usageType=" + usageType
+ ", quotaUsed=" + quotaUsed + ", startDate=" + startDate + ", endDate=" + endDate + "]";
}
}

View File

@ -0,0 +1,336 @@
//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.vo;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import javax.persistence.Transient;
import com.cloud.offering.ServiceOffering;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.Storage.ProvisioningType;
import com.cloud.vm.VirtualMachine;
@Entity
@Table(name = "service_offering")
@DiscriminatorValue(value = "Service")
@PrimaryKeyJoinColumn(name = "id")
public class ServiceOfferingVO extends DiskOfferingVO implements ServiceOffering {
@Column(name = "cpu")
private Integer cpu;
@Column(name = "speed")
private Integer speed;
@Column(name = "ram_size")
private Integer ramSize;
@Column(name = "nw_rate")
private Integer rateMbps;
@Column(name = "mc_rate")
private Integer multicastRateMbps;
@Column(name = "ha_enabled")
private boolean offerHA;
@Column(name = "limit_cpu_use")
private boolean limitCpuUse;
@Column(name = "is_volatile")
private boolean volatileVm;
@Column(name = "host_tag")
private String hostTag;
@Column(name = "default_use")
private boolean defaultUse;
@Column(name = "vm_type")
private String vmType;
@Column(name = "sort_key")
int sortKey;
@Column(name = "deployment_planner")
private String deploymentPlanner = null;
// This is a delayed load value. If the value is null,
// then this field has not been loaded yet.
// Call service offering dao to load it.
@Transient
Map<String, String> details;
// This flag is required to tell if the offering is dynamic once the cpu, memory and speed are set.
// In some cases cpu, memory and speed are set to non-null values even if the offering is dynamic.
@Transient
boolean isDynamic;
protected ServiceOfferingVO() {
super();
}
public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, String displayText,
ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, boolean defaultUse) {
super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true);
this.cpu = cpu;
this.ramSize = ramSize;
this.speed = speed;
this.rateMbps = rateMbps;
this.multicastRateMbps = multicastRateMbps;
this.offerHA = offerHA;
limitCpuUse = false;
volatileVm = false;
this.defaultUse = defaultUse;
this.vmType = vmType == null ? null : vmType.toString().toLowerCase();
}
public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA, boolean limitCpuUse,
boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse, VirtualMachine.Type vmType, Long domainId) {
super(name, displayText, provisioningType, false, tags, recreatable, useLocalStorage, systemUse, true, domainId);
this.cpu = cpu;
this.ramSize = ramSize;
this.speed = speed;
this.rateMbps = rateMbps;
this.multicastRateMbps = multicastRateMbps;
this.offerHA = offerHA;
this.limitCpuUse = limitCpuUse;
this.volatileVm = volatileVm;
this.vmType = vmType == null ? null : vmType.toString().toLowerCase();
}
public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA,
boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse,
VirtualMachine.Type vmType, Long domainId, String hostTag) {
this(name,
cpu,
ramSize,
speed,
rateMbps,
multicastRateMbps,
offerHA,
limitResourceUse,
volatileVm,
displayText,
provisioningType,
useLocalStorage,
recreatable,
tags,
systemUse,
vmType,
domainId);
this.hostTag = hostTag;
}
public ServiceOfferingVO(String name, Integer cpu, Integer ramSize, Integer speed, Integer rateMbps, Integer multicastRateMbps, boolean offerHA,
boolean limitResourceUse, boolean volatileVm, String displayText, ProvisioningType provisioningType, boolean useLocalStorage, boolean recreatable, String tags, boolean systemUse,
VirtualMachine.Type vmType, Long domainId, String hostTag, String deploymentPlanner) {
this(name,
cpu,
ramSize,
speed,
rateMbps,
multicastRateMbps,
offerHA,
limitResourceUse,
volatileVm,
displayText,
provisioningType,
useLocalStorage,
recreatable,
tags,
systemUse,
vmType,
domainId,
hostTag);
this.deploymentPlanner = deploymentPlanner;
}
public ServiceOfferingVO(ServiceOfferingVO offering) {
super(offering.getId(),
offering.getName(),
offering.getDisplayText(),
offering.getProvisioningType(),
false,
offering.getTags(),
offering.isRecreatable(),
offering.getUseLocalStorage(),
offering.getSystemUse(),
true,
offering.isCustomizedIops()== null ? false:offering.isCustomizedIops(),
offering.getDomainId(),
offering.getMinIops(),
offering.getMaxIops());
cpu = offering.getCpu();
ramSize = offering.getRamSize();
speed = offering.getSpeed();
rateMbps = offering.getRateMbps();
multicastRateMbps = offering.getMulticastRateMbps();
offerHA = offering.getOfferHA();
limitCpuUse = offering.getLimitCpuUse();
volatileVm = offering.getVolatileVm();
hostTag = offering.getHostTag();
vmType = offering.getSystemVmType();
}
@Override
public boolean getOfferHA() {
return offerHA;
}
public void setOfferHA(boolean offerHA) {
this.offerHA = offerHA;
}
@Override
public boolean getLimitCpuUse() {
return limitCpuUse;
}
public void setLimitResourceUse(boolean limitCpuUse) {
this.limitCpuUse = limitCpuUse;
}
@Override
public boolean getDefaultUse() {
return defaultUse;
}
@Override
@Transient
public String[] getTagsArray() {
String tags = getTags();
if (tags == null || tags.length() == 0) {
return new String[0];
}
return tags.split(",");
}
@Override
public Integer getCpu() {
return cpu;
}
public void setCpu(int cpu) {
this.cpu = cpu;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public void setRamSize(int ramSize) {
this.ramSize = ramSize;
}
@Override
public Integer getSpeed() {
return speed;
}
@Override
public Integer getRamSize() {
return ramSize;
}
public void setRateMbps(Integer rateMbps) {
this.rateMbps = rateMbps;
}
@Override
public Integer getRateMbps() {
return rateMbps;
}
public void setMulticastRateMbps(Integer multicastRateMbps) {
this.multicastRateMbps = multicastRateMbps;
}
@Override
public Integer getMulticastRateMbps() {
return multicastRateMbps;
}
public void setHostTag(String hostTag) {
this.hostTag = hostTag;
}
@Override
public String getHostTag() {
return hostTag;
}
@Override
public String getSystemVmType() {
return vmType;
}
@Override
public void setSortKey(int key) {
sortKey = key;
}
@Override
public int getSortKey() {
return sortKey;
}
@Override
public boolean getVolatileVm() {
return volatileVm;
}
@Override
public String getDeploymentPlanner() {
return deploymentPlanner;
}
public Map<String, String> getDetails() {
return details;
}
public String getDetail(String name) {
assert (details != null) : "Did you forget to load the details?";
return details != null ? details.get(name) : null;
}
public void setDetail(String name, String value) {
assert (details != null) : "Did you forget to load the details?";
details.put(name, value);
}
public void setDetails(Map<String, String> details) {
this.details = details;
}
@Override
public boolean isDynamic() {
return cpu == null || speed == null || ramSize == null || isDynamic;
}
public void setDynamicFlag(boolean isdynamic) {
isDynamic = isdynamic;
}
}

View File

@ -0,0 +1,83 @@
//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.vo;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.apache.cloudstack.api.ResourceDetail;
@Entity
@Table(name = "user_vm_details")
public class UserVmDetailVO implements ResourceDetail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "vm_id")
private long resourceId;
@Column(name = "name")
private String name;
@Column(name = "value", length = 5120)
private String value;
@Column(name = "display")
private boolean display = true;
public UserVmDetailVO() {
}
public UserVmDetailVO(long vmId, String name, String value, boolean display) {
this.resourceId = vmId;
this.name = name;
this.value = value;
this.display = display;
}
@Override
public long getId() {
return id;
}
@Override
public String getName() {
return name;
}
@Override
public String getValue() {
return value;
}
@Override
public long getResourceId() {
return resourceId;
}
@Override
public boolean isDisplay() {
return display;
}
}

View File

@ -0,0 +1,197 @@
// 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;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.user.Account;
import com.cloud.user.AccountVO;
import com.cloud.user.UserVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.db.TransactionLegacy;
import junit.framework.TestCase;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.quota.constant.QuotaConfig;
import org.apache.cloudstack.quota.dao.QuotaAccountDao;
import org.apache.cloudstack.quota.dao.QuotaEmailTemplatesDao;
import org.apache.cloudstack.quota.dao.QuotaUsageDao;
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
import org.apache.cloudstack.quota.vo.QuotaEmailTemplatesVO;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import javax.mail.MessagingException;
import javax.naming.ConfigurationException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class QuotaAlertManagerImplTest extends TestCase {
@Mock
AccountDao accountDao;
@Mock
QuotaAccountDao quotaAcc;
@Mock
UserDao userDao;
@Mock
DomainDao domainDao;
@Mock
QuotaEmailTemplatesDao quotaEmailTemplateDao;
@Mock
ConfigurationDao configDao;
@Mock
QuotaUsageDao quotaUsage;
@Mock
QuotaAlertManagerImpl.EmailQuotaAlert emailQuotaAlert;
@Spy
QuotaAlertManagerImpl quotaAlertManager = new QuotaAlertManagerImpl();
private void injectMockToField(Object mock, String fieldName) throws NoSuchFieldException, IllegalAccessException {
Field f = QuotaAlertManagerImpl.class.getDeclaredField(fieldName);
f.setAccessible(true);
f.set(quotaAlertManager, mock);
}
@Before
public void setup() throws IllegalAccessException, NoSuchFieldException, ConfigurationException {
// Dummy transaction stack setup
TransactionLegacy.open("QuotaAlertManagerImplTest");
injectMockToField(accountDao, "_accountDao");
injectMockToField(quotaAcc, "_quotaAcc");
injectMockToField(userDao, "_userDao");
injectMockToField(domainDao, "_domainDao");
injectMockToField(quotaEmailTemplateDao, "_quotaEmailTemplateDao");
injectMockToField(configDao, "_configDao");
injectMockToField(quotaUsage, "_quotaUsage");
injectMockToField(emailQuotaAlert, "_emailQuotaAlert");
}
@Test
public void testCheckAndSendQuotaAlertEmails() {
AccountVO accountVO = new AccountVO();
accountVO.setId(2L);
accountVO.setDomainId(1L);
accountVO.setType(Account.ACCOUNT_TYPE_NORMAL);
Mockito.when(accountDao.findById(Mockito.anyLong())).thenReturn(accountVO);
QuotaAccountVO acc = new QuotaAccountVO(2L);
acc.setQuotaBalance(new BigDecimal(404));
acc.setQuotaMinBalance(new BigDecimal(100));
acc.setQuotaBalanceDate(new Date());
acc.setQuotaAlertDate(null);
acc.setQuotaEnforce(0);
List<QuotaAccountVO> accounts = new ArrayList<>();
accounts.add(acc);
Mockito.when(quotaAcc.listAllQuotaAccount()).thenReturn(accounts);
// Don't test sendQuotaAlert yet
Mockito.doNothing().when(quotaAlertManager).sendQuotaAlert(Mockito.any(QuotaAlertManagerImpl.DeferredQuotaEmail.class));
Mockito.doReturn(true).when(quotaAlertManager).lockAccount(Mockito.anyLong());
// call real method on send monthly statement
Mockito.doCallRealMethod().when(quotaAlertManager).checkAndSendQuotaAlertEmails();
// Case1: valid balance, no email should be sent
quotaAlertManager.checkAndSendQuotaAlertEmails();
Mockito.verify(quotaAlertManager, Mockito.times(0)).sendQuotaAlert(Mockito.any(QuotaAlertManagerImpl.DeferredQuotaEmail.class));
// Case2: low balance, email should be sent
accounts.get(0).setQuotaBalance(new BigDecimal(99));
//Mockito.when(quotaAcc.listAll()).thenReturn(accounts);
quotaAlertManager.checkAndSendQuotaAlertEmails();
Mockito.verify(quotaAlertManager, Mockito.times(1)).sendQuotaAlert(Mockito.any(QuotaAlertManagerImpl.DeferredQuotaEmail.class));
}
@Test
public void testSendQuotaAlert() throws UnsupportedEncodingException, MessagingException {
Mockito.doCallRealMethod().when(quotaAlertManager).sendQuotaAlert(Mockito.any(QuotaAlertManagerImpl.DeferredQuotaEmail.class));
AccountVO account = new AccountVO();
account.setId(2L);
account.setDomainId(1L);
account.setType(Account.ACCOUNT_TYPE_NORMAL);
account.setAccountName("admin");
account.setUuid("uuid");
QuotaAccountVO quotaAccount = new QuotaAccountVO(2L);
quotaAccount.setQuotaBalance(new BigDecimal(404));
quotaAccount.setQuotaMinBalance(new BigDecimal(100));
quotaAccount.setQuotaBalanceDate(new Date());
quotaAccount.setQuotaAlertDate(null);
quotaAccount.setQuotaEnforce(0);
QuotaAlertManagerImpl.DeferredQuotaEmail email = new QuotaAlertManagerImpl.DeferredQuotaEmail(account, quotaAccount, new BigDecimal(100),
QuotaConfig.QuotaEmailTemplateTypes.QUOTA_LOW);
QuotaEmailTemplatesVO quotaEmailTemplatesVO = new QuotaEmailTemplatesVO();
quotaEmailTemplatesVO.setTemplateSubject("Low quota");
quotaEmailTemplatesVO.setTemplateBody("Low quota {{accountID}}");
List<QuotaEmailTemplatesVO> emailTemplates = new ArrayList<>();
emailTemplates.add(quotaEmailTemplatesVO);
Mockito.when(quotaEmailTemplateDao.listAllQuotaEmailTemplates(Mockito.anyString())).thenReturn(emailTemplates);
DomainVO domain = new DomainVO();
domain.setUuid("uuid");
domain.setName("/domain");
Mockito.when(domainDao.findByIdIncludingRemoved(Mockito.anyLong())).thenReturn(new DomainVO());
UserVO user = new UserVO();
user.setUsername("user1");
user.setEmail("user1@apache.org");
List<UserVO> users = new ArrayList<>();
users.add(user);
Mockito.when(userDao.listByAccount(Mockito.anyLong())).thenReturn(users);
quotaAlertManager.sendQuotaAlert(email);
assertTrue(email.getSendDate()!= null);
Mockito.verify(emailQuotaAlert, Mockito.times(1)).sendQuotaAlert(Mockito.anyList(), Mockito.anyString(), Mockito.anyString());
}
@Test
public void testGetDifferenceDays() {
Date now = new Date();
assertTrue(QuotaAlertManagerImpl.getDifferenceDays(now, now) == 0L);
assertTrue(QuotaAlertManagerImpl.getDifferenceDays(now, new DateTime(now).plusDays(1).toDate()) == 1L);
}
@Test
public void testLockAccount() {
AccountVO accountVO = new AccountVO();
accountVO.setId(2L);
accountVO.setDomainId(1L);
accountVO.setType(Account.ACCOUNT_TYPE_NORMAL);
accountVO.setState(Account.State.enabled);
Mockito.when(accountDao.findById(Mockito.anyLong())).thenReturn(accountVO);
Mockito.when(accountDao.createForUpdate()).thenReturn(accountVO);
Mockito.when(accountDao.update(Mockito.eq(accountVO.getId()), Mockito.eq(accountVO))).thenReturn(true);
assertTrue(quotaAlertManager.lockAccount(accountVO.getId()));
}
}

View File

@ -0,0 +1,200 @@
// 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;
import com.cloud.usage.UsageVO;
import com.cloud.usage.dao.UsageDao;
import com.cloud.user.Account;
import com.cloud.user.AccountVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.Pair;
import com.cloud.utils.db.TransactionLegacy;
import junit.framework.TestCase;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
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.QuotaUsageDao;
import org.apache.cloudstack.quota.dao.ServiceOfferingDao;
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
import org.apache.cloudstack.usage.UsageTypes;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import javax.naming.ConfigurationException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RunWith(MockitoJUnitRunner.class)
public class QuotaManagerImplTest extends TestCase {
@Mock
private AccountDao accountDao;
@Mock
private QuotaAccountDao quotaAcc;
@Mock
private UsageDao usageDao;
@Mock
private QuotaTariffDao quotaTariffDao;
@Mock
private QuotaUsageDao quotaUsageDao;
@Mock
private ServiceOfferingDao serviceOfferingDao;
@Mock
private QuotaBalanceDao quotaBalanceDao;
@Mock
private ConfigurationDao configDao;
@Spy
QuotaManagerImpl quotaManager = new QuotaManagerImpl();
private void injectMockToField(Object mock, String fieldName) throws NoSuchFieldException, IllegalAccessException {
Field f = QuotaManagerImpl.class.getDeclaredField(fieldName);
f.setAccessible(true);
f.set(quotaManager, mock);
}
@Before
public void setup() throws IllegalAccessException, NoSuchFieldException, ConfigurationException {
// Dummy transaction stack setup
TransactionLegacy.open("QuotaManagerImplTest");
injectMockToField(accountDao, "_accountDao");
injectMockToField(quotaAcc, "_quotaAcc");
injectMockToField(usageDao, "_usageDao");
injectMockToField(quotaTariffDao, "_quotaTariffDao");
injectMockToField(quotaUsageDao, "_quotaUsageDao");
injectMockToField(serviceOfferingDao, "_serviceOfferingDao");
injectMockToField(quotaBalanceDao, "_quotaBalanceDao");
injectMockToField(configDao, "_configDao");
}
@Test
public void testConfig() throws ConfigurationException {
Mockito.when(configDao.getConfiguration(Mockito.anyMapOf(String.class, Object.class))).thenReturn(new HashMap<String, String>());
Map<String, Object> map = new HashMap<>();
map.put("usage.stats.job.aggregation.range", "0");
assertTrue(quotaManager.configure("quotaManager", map));
}
@Test
public void testCalculateQuotaUsage() {
AccountVO accountVO = new AccountVO();
accountVO.setId(2L);
accountVO.setDomainId(1L);
accountVO.setType(Account.ACCOUNT_TYPE_NORMAL);
List<AccountVO> accountVOList = new ArrayList<>();
accountVOList.add(accountVO);
Mockito.when(accountDao.listAll()).thenReturn(accountVOList);
UsageVO usageVO = new UsageVO();
usageVO.setQuotaCalculated(0);
List<UsageVO> usageVOList = new ArrayList<UsageVO>();
usageVOList.add(usageVO);
Pair<List<? extends UsageVO>, Integer> usageRecords = new Pair<List<? extends UsageVO>, Integer>(usageVOList, usageVOList.size());
Mockito.when(usageDao.getUsageRecordsPendingQuotaAggregation(Mockito.anyLong(), Mockito.anyLong())).thenReturn(usageRecords);
QuotaUsageVO quotaUsageVO = new QuotaUsageVO();
quotaUsageVO.setAccountId(2L);
List<QuotaUsageVO> quotaListForAccount = new ArrayList<>();
quotaListForAccount.add(quotaUsageVO);
Mockito.doReturn(quotaListForAccount).when(quotaManager).aggregatePendingQuotaRecordsForAccount(Mockito.eq(accountVO), Mockito.eq(usageRecords));
Mockito.doNothing().when(quotaManager).processQuotaBalanceForAccount(Mockito.eq(accountVO), Mockito.eq(quotaListForAccount));
assertTrue(quotaManager.calculateQuotaUsage());
}
@Test
public void testAggregatePendingQuotaRecordsForAccount() {
AccountVO accountVO = new AccountVO();
accountVO.setId(2L);
accountVO.setDomainId(1L);
accountVO.setType(Account.ACCOUNT_TYPE_NORMAL);
UsageVO usageVO = new UsageVO();
usageVO.setQuotaCalculated(0);
usageVO.setUsageType(UsageTypes.ALLOCATED_VM);
List<UsageVO> usageVOList = new ArrayList<UsageVO>();
usageVOList.add(usageVO);
Pair<List<? extends UsageVO>, Integer> usageRecords = new Pair<List<? extends UsageVO>, Integer>(usageVOList, usageVOList.size());
QuotaUsageVO quotaUsageVO = new QuotaUsageVO();
quotaUsageVO.setAccountId(2L);
Mockito.doReturn(quotaUsageVO).when(quotaManager).updateQuotaAllocatedVMUsage(Mockito.eq(usageVO), Mockito.any(BigDecimal.class));
assertTrue(quotaManager.aggregatePendingQuotaRecordsForAccount(accountVO, new Pair<List<? extends UsageVO>, Integer>(null, 0)).size() == 0);
assertTrue(quotaManager.aggregatePendingQuotaRecordsForAccount(accountVO, usageRecords).size() == 1);
}
@Test
public void testUpdateQuotaRecords() {
UsageVO usageVO = new UsageVO();
usageVO.setId(100L);
usageVO.setQuotaCalculated(0);
usageVO.setUsageType(UsageTypes.NETWORK_BYTES_SENT);
usageVO.setRawUsage(9000000000.0);
usageVO.setSize(1010101010L);
QuotaTariffVO tariffVO = new QuotaTariffVO();
tariffVO.setCurrencyValue(new BigDecimal(1));
Mockito.when(quotaTariffDao.findTariffPlanByUsageType(Mockito.anyInt(), Mockito.any(Date.class))).thenReturn(tariffVO);
QuotaUsageVO qu = quotaManager.updateQuotaNetwork(usageVO, UsageTypes.NETWORK_BYTES_SENT);
assertTrue(qu.getQuotaUsed().compareTo(BigDecimal.ZERO) > 0);
qu = quotaManager.updateQuotaAllocatedVMUsage(usageVO, new BigDecimal(0.5));
assertTrue(qu.getQuotaUsed().compareTo(BigDecimal.ZERO) > 0);
qu = quotaManager.updateQuotaDiskUsage(usageVO, new BigDecimal(0.5), UsageTypes.VOLUME);
assertTrue(qu.getQuotaUsed().compareTo(BigDecimal.ZERO) > 0);
qu = quotaManager.updateQuotaRaw(usageVO, new BigDecimal(0.5), UsageTypes.VPN_USERS);
assertTrue(qu.getQuotaUsed().compareTo(BigDecimal.ZERO) > 0);
Mockito.verify(quotaUsageDao, Mockito.times(4)).persistQuotaUsage(Mockito.any(QuotaUsageVO.class));
Mockito.verify(usageDao, Mockito.times(4)).persistUsage(Mockito.any(UsageVO.class));
}
@Test
public void testProcessQuotaBalanceForAccount() {
Date now = new Date();
AccountVO accountVO = new AccountVO();
accountVO.setId(2L);
accountVO.setDomainId(1L);
accountVO.setType(Account.ACCOUNT_TYPE_NORMAL);
QuotaUsageVO quotaUsageVO = new QuotaUsageVO();
quotaUsageVO.setAccountId(2L);
quotaUsageVO.setStartDate(new Date(now.getTime()));
quotaUsageVO.setEndDate(new Date(now.getTime()));
List<QuotaUsageVO> quotaListForAccount = new ArrayList<>();
quotaListForAccount.add(quotaUsageVO);
quotaManager.processQuotaBalanceForAccount(accountVO, quotaListForAccount);
Mockito.verify(quotaAcc, Mockito.times(1)).persistQuotaAccount(Mockito.any(QuotaAccountVO.class));
}
}

View File

@ -0,0 +1,255 @@
// 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;
import com.cloud.user.AccountVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.db.TransactionLegacy;
import junit.framework.TestCase;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.quota.QuotaStatementImpl.STATEMENT_PERIODS;
import org.apache.cloudstack.quota.constant.QuotaConfig;
import org.apache.cloudstack.quota.dao.QuotaAccountDao;
import org.apache.cloudstack.quota.dao.QuotaUsageDao;
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import javax.mail.MessagingException;
import javax.naming.ConfigurationException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class QuotaStatementTest extends TestCase {
@Mock
AccountDao accountDao;
@Mock
QuotaAccountDao quotaAcc;
@Mock
ConfigurationDao configDao;
@Mock
QuotaUsageDao quotaUsage;
@Mock
QuotaAlertManager alertManager;
@Spy
QuotaStatementImpl quotaStatement = new QuotaStatementImpl();
private void injectMockToField(Object mock, String fieldName) throws NoSuchFieldException, IllegalAccessException {
Field f = QuotaStatementImpl.class.getDeclaredField(fieldName);
f.setAccessible(true);
f.set(quotaStatement, mock);
}
@Before
public void setup() throws IllegalAccessException, NoSuchFieldException, ConfigurationException {
// Dummy transaction stack setup
TransactionLegacy.open("QuotaStatementImplTest");
injectMockToField(accountDao, "_accountDao");
injectMockToField(quotaAcc, "_quotaAcc");
injectMockToField(configDao, "_configDao");
injectMockToField(quotaUsage, "_quotaUsage");
injectMockToField(alertManager, "_quotaAlert");
}
@Test
public void testStatementPeriodBIMONTHLY() {
Calendar date = Calendar.getInstance();
//BIMONTHLY - first statement of month
date.set(Calendar.DATE, QuotaStatementImpl.s_LAST_STATEMENT_SENT_DAYS + 1);
Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.BIMONTHLY);
assertTrue(period == null);
//1 of this month
date.set(Calendar.DATE, 1);
period = quotaStatement.statementTime(date, STATEMENT_PERIODS.BIMONTHLY);
assertTrue(period != null);
assertTrue(period.length == 2);
assertTrue(period[0].toString(), period[0].before(period[1]));
assertTrue(period[0].toString(), period[0].get(Calendar.DATE) == 1);
assertTrue(period[1].toString(), period[1].get(Calendar.DATE) == 15);
//BIMONTHLY - second statement of month
date = Calendar.getInstance();
date.set(Calendar.DATE, QuotaStatementImpl.s_LAST_STATEMENT_SENT_DAYS + 16);
period = quotaStatement.statementTime(date, STATEMENT_PERIODS.BIMONTHLY);
assertTrue(period == null);
//17 of this month
date.set(Calendar.DATE, 17);
period = quotaStatement.statementTime(date, STATEMENT_PERIODS.BIMONTHLY);
assertTrue(period != null);
assertTrue(period.length == 2);
assertTrue(period[0].toString(), period[0].before(period[1]));
assertTrue(period[0].toString(), period[0].get(Calendar.DATE) == 16);
//get last day of the previous month
Calendar aCalendar = Calendar.getInstance();
aCalendar.add(Calendar.MONTH, -1);
aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
assertTrue(period[1].toString(), period[1].get(Calendar.DATE) == aCalendar.get(Calendar.DATE));
}
@Test
public void testStatementPeriodMONTHLY() {
Calendar date = Calendar.getInstance();
Calendar aCalendar = Calendar.getInstance();
//MONTHLY
date = Calendar.getInstance();
date.set(Calendar.DATE, QuotaStatementImpl.s_LAST_STATEMENT_SENT_DAYS + 1);
Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.MONTHLY);
assertTrue(period == null);
//1 of this month
date.set(Calendar.DATE, QuotaStatementImpl.s_LAST_STATEMENT_SENT_DAYS - 1);
period = quotaStatement.statementTime(date, STATEMENT_PERIODS.MONTHLY);
assertTrue(period != null);
assertTrue(period.length == 2);
assertTrue(period[0].toString(), period[0].before(period[1]));
assertTrue(period[0].toString(), period[0].get(Calendar.DATE) == 1);
//get last day of the previous month
aCalendar = Calendar.getInstance();
aCalendar.add(Calendar.MONTH, -1);
aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
assertTrue(period[1].toString(), period[1].get(Calendar.DATE) == aCalendar.get(Calendar.DATE));
}
@Test
public void testStatementPeriodQUATERLY() {
Calendar date = Calendar.getInstance();
Calendar aCalendar = Calendar.getInstance();
//QUATERLY
date = Calendar.getInstance();
date.set(Calendar.MONTH, Calendar.JANUARY); // 1 Jan
date.set(Calendar.DATE, 1);
Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.QUATERLY);
assertTrue(period != null);
assertTrue(period.length == 2);
assertTrue("period[0].before(period[1])" + period[0].toString(), period[0].before(period[1]));
assertTrue("period[0].get(Calendar.DATE) == 1" + period[0].toString(), period[0].get(Calendar.DATE) == 1);
assertTrue("period[0].get(Calendar.MONTH) == Calendar.OCTOBER" + period[0].toString(), period[0].get(Calendar.MONTH) == Calendar.OCTOBER); //october
//get last day of the previous month
aCalendar = Calendar.getInstance();
aCalendar.set(Calendar.MONTH, Calendar.DECEMBER);
aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
assertTrue(" period[1].get(Calendar.DATE) == aCalendar.get(Calendar.DATE)" + period[1].toString(), period[1].get(Calendar.DATE) == aCalendar.get(Calendar.DATE));
assertTrue("period[1].get(Calendar.MONTH) == aCalendar.get(Calendar.MONTH)" + period[1].toString(), period[1].get(Calendar.MONTH) == aCalendar.get(Calendar.MONTH));
}
@Test
public void testStatementPeriodHALFYEARLY() {
Calendar date = Calendar.getInstance();
Calendar aCalendar = Calendar.getInstance();
//QUATERLY
date = Calendar.getInstance();
date.set(Calendar.MONTH, Calendar.JANUARY); // 1 Jan
date.set(Calendar.DATE, 1);
Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.HALFYEARLY);
assertTrue(period != null);
assertTrue(period.length == 2);
assertTrue("period[0].before(period[1])" + period[0].toString(), period[0].before(period[1]));
assertTrue("period[0].get(Calendar.DATE) == 1" + period[0].toString(), period[0].get(Calendar.DATE) == 1);
assertTrue("period[0].get(Calendar.MONTH) == Calendar.JULY" + period[0].toString(), period[0].get(Calendar.MONTH) == Calendar.JULY); //july
//get last day of the previous month
aCalendar = Calendar.getInstance();
aCalendar.set(Calendar.MONTH, Calendar.DECEMBER);
aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
assertTrue(" period[1].get(Calendar.DATE) == aCalendar.get(Calendar.DATE)" + period[1].toString(), period[1].get(Calendar.DATE) == aCalendar.get(Calendar.DATE));
assertTrue("period[1].get(Calendar.MONTH) == aCalendar.get(Calendar.MONTH)" + period[1].toString(), period[1].get(Calendar.MONTH) == aCalendar.get(Calendar.MONTH));
}
@Test
public void testStatementPeriodYEARLY() {
Calendar date = Calendar.getInstance();
Calendar aCalendar = Calendar.getInstance();
//QUATERLY
date = Calendar.getInstance();
date.set(Calendar.MONTH, Calendar.JANUARY); // 1 Jan
date.set(Calendar.DATE, 1);
Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.YEARLY);
assertTrue("period != null", period != null);
assertTrue(period.length == 2);
assertTrue("period[0].before(period[1])" + period[0].toString(), period[0].before(period[1]));
assertTrue("period[0].get(Calendar.DATE) == 1" + period[0].toString(), period[0].get(Calendar.DATE) == 1);
assertTrue("period[0].get(Calendar.MONTH) == Calendar.JANUARY" + period[0].toString(), period[0].get(Calendar.MONTH) == Calendar.JANUARY); //january
//get last day of the previous month
aCalendar = Calendar.getInstance();
aCalendar.set(Calendar.MONTH, Calendar.DECEMBER);
aCalendar.set(Calendar.DATE, aCalendar.getActualMaximum(Calendar.DAY_OF_MONTH) + 1);
assertTrue(" period[1].get(Calendar.DATE) == aCalendar.get(Calendar.DATE)" + period[1].toString(), period[1].get(Calendar.DATE) == aCalendar.get(Calendar.DATE));
assertTrue("period[1].get(Calendar.MONTH) == aCalendar.get(Calendar.MONTH)" + period[1].toString(), period[1].get(Calendar.MONTH) == aCalendar.get(Calendar.MONTH));
}
@Test
public void testSendStatement() throws UnsupportedEncodingException, MessagingException {
Calendar date = Calendar.getInstance();
AccountVO accountVO = new AccountVO();
accountVO.setId(2L);
accountVO.setDomainId(1L);
Mockito.when(accountDao.findById(Mockito.anyLong())).thenReturn(accountVO);
QuotaAccountVO acc = new QuotaAccountVO(2L);
acc.setQuotaBalance(new BigDecimal(404));
acc.setLastStatementDate(null);
List<QuotaAccountVO> accounts = new ArrayList<>();
accounts.add(acc);
Mockito.when(quotaAcc.listAllQuotaAccount()).thenReturn(accounts);
Mockito.when(quotaUsage.findTotalQuotaUsage(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyInt(), Mockito.any(Date.class), Mockito.any(Date.class)))
.thenReturn(new BigDecimal(100));
QuotaAlertManagerImpl.DeferredQuotaEmail email = new QuotaAlertManagerImpl.DeferredQuotaEmail(accountVO, acc, new BigDecimal(100),
QuotaConfig.QuotaEmailTemplateTypes.QUOTA_LOW);
// call real method on send monthly statement
Mockito.doCallRealMethod().when(quotaStatement).sendStatement();
Calendar period[] = quotaStatement.statementTime(date, STATEMENT_PERIODS.MONTHLY);
if (period != null){
Mockito.verify(alertManager, Mockito.times(1)).sendQuotaAlert(email);
}
}
}

View File

@ -0,0 +1,48 @@
// 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.constant;
import junit.framework.TestCase;
import org.apache.cloudstack.api.response.UsageTypeResponse;
import org.apache.cloudstack.usage.UsageTypes;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.List;
import java.util.Map;
@RunWith(MockitoJUnitRunner.class)
public class QuotaTypesTest extends TestCase {
@Test
public void testQuotaTypesList() {
Map<Integer, QuotaTypes> quotaTypes = QuotaTypes.listQuotaTypes();
List<UsageTypeResponse> usageTypesResponseList = UsageTypes.listUsageTypes();
for (UsageTypeResponse usageTypeResponse : usageTypesResponseList) {
final Integer usageTypeInt = usageTypeResponse.getUsageType();
assertTrue(quotaTypes.containsKey(usageTypeInt));
}
}
@Test
public void testQuotaTypeDescription() {
assertNull(QuotaTypes.getDescription(-1));
assertNotNull(QuotaTypes.getDescription(QuotaTypes.MEMORY));
}
}

View File

@ -0,0 +1,99 @@
<!-- 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. -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-plugin-database-quota</artifactId>
<name>Apache CloudStack Plugin - Quota Service</name>
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
<version>4.7.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-schema</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-utils</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-framework-quota</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${cs.commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${cs.joda-time.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${cs.junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>${cs.hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>${cs.mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${cs.powermock.version}</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${cs.powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,18 @@
# 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.
name=quota
parent=api

View File

@ -0,0 +1,31 @@
<!--
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.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="QuotaService" class="org.apache.cloudstack.quota.QuotaServiceImpl" />
<bean id="QuotaResponseBuilder" class="org.apache.cloudstack.api.response.QuotaResponseBuilderImpl"/>
</beans>

View File

@ -0,0 +1,125 @@
//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.api.command;
import java.util.Date;
import java.util.List;
import javax.inject.Inject;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.QuotaBalanceResponse;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
import org.apache.cloudstack.api.response.QuotaStatementItemResponse;
@APICommand(name = "quotaBalance", responseObject = QuotaStatementItemResponse.class, description = "Create a quota balance statement", since = "4.6.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class QuotaBalanceCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(QuotaBalanceCmd.class);
private static final String s_name = "quotabalanceresponse";
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = true, description = "Account Id for which statement needs to be generated")
private String accountName;
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class, description = "If domain Id is given and the caller is domain admin then the statement is generated for domain.")
private Long domainId;
@Parameter(name = ApiConstants.END_DATE, type = CommandType.DATE, description = "End date range for quota query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.")
private Date endDate;
@Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, description = "Start date range quota query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-01.")
private Date startDate;
@Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, description = "List usage records for the specified account")
private Long accountId;
@Inject
QuotaResponseBuilder _responseBuilder;
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public Long getDomainId() {
return domainId;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public Date getEndDate() {
return endDate == null ? null : _responseBuilder.startOfNextDay(endDate == null ? null : new Date(endDate.getTime()));
}
public void setEndDate(Date endDate) {
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public Date getStartDate() {
return startDate == null ? null : new Date(startDate.getTime());
}
public void setStartDate(Date startDate) {
this.startDate = startDate == null ? null : new Date(startDate.getTime());
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return _accountService.getActiveAccountByName(accountName, domainId).getAccountId();
}
@Override
public void execute() {
List<QuotaBalanceVO> quotaUsage = _responseBuilder.getQuotaBalance(this);
QuotaBalanceResponse response;
if (getEndDate() == null) {
response = _responseBuilder.createQuotaLastBalanceResponse(quotaUsage, getStartDate());
} else {
response = _responseBuilder.createQuotaBalanceResponse(quotaUsage, getStartDate(), endDate == null ? null : new Date(endDate.getTime()));
}
response.setResponseName(getCommandName());
setResponseObject(response);
}
}

View File

@ -0,0 +1,147 @@
//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.api.command;
import com.cloud.user.Account;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.QuotaCreditsResponse;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.quota.QuotaService;
import org.apache.log4j.Logger;
import javax.inject.Inject;
@APICommand(name = "quotaCredits", responseObject = QuotaCreditsResponse.class, description = "Add +-credits to an account", since = "4.6.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class QuotaCreditsCmd extends BaseCmd {
@Inject
QuotaResponseBuilder _responseBuilder;
@Inject
QuotaService _quotaService;
public static final Logger s_logger = Logger.getLogger(QuotaStatementCmd.class);
private static final String s_name = "quotacreditsresponse";
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = true, description = "Account Id for which quota credits need to be added")
private String accountName;
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class, description = "Domain for which quota credits need to be added")
private Long domainId;
@Parameter(name = ApiConstants.VALUE, type = CommandType.DOUBLE, required = true, description = "Value of the credits to be added+, subtracted-")
private Double value;
@Parameter(name = "min_balance", type = CommandType.DOUBLE, required = false, description = "Minimum balance threshold of the account")
private Double minBalance;
@Parameter(name = "quota_enforce", type = CommandType.BOOLEAN, required = false, description = "Account for which quota enforce is set to false will not be locked when there is no credit balance")
private Boolean quotaEnforce;
public Double getMinBalance() {
return minBalance;
}
public void setMinBalance(Double minBalance) {
this.minBalance = minBalance;
}
public Boolean getQuotaEnforce() {
return quotaEnforce;
}
public void setQuotaEnforce(Boolean quotaEnforce) {
this.quotaEnforce = quotaEnforce;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public Long getDomainId() {
return domainId;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public Double getValue() {
return value;
}
public void setValue(Double value) {
this.value = value;
}
public QuotaCreditsCmd() {
super();
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public void execute() {
Long accountId = null;
Account account = _accountService.getActiveAccountByName(accountName, domainId);
if (account != null) {
accountId = account.getAccountId();
}
if (accountId == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "The account does not exists or has been removed/disabled");
}
if (getValue() == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Please send a valid non-empty quota value");
}
if (getQuotaEnforce() != null && getQuotaEnforce()) {
_quotaService.setLockAccount(accountId, getQuotaEnforce());
}
if (getMinBalance() != null) {
_quotaService.setMinBalance(accountId, getMinBalance());
}
else {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Please set a value for min balance");
}
final QuotaCreditsResponse response = _responseBuilder.addQuotaCredits(accountId, getDomainId(), getValue(), CallContext.current().getCallingUserId());
response.setResponseName(getCommandName());
response.setObjectName("quotacredits");
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,60 @@
//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.api.command;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.QuotaEmailTemplateResponse;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.log4j.Logger;
import javax.inject.Inject;
@APICommand(name = "quotaEmailTemplateList", responseObject = QuotaEmailTemplateResponse.class, description = "Lists all quota email templates", since = "4.6.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class QuotaEmailTemplateListCmd extends BaseListCmd {
public static final Logger s_logger = Logger.getLogger(QuotaEmailTemplateListCmd.class);
private static final String s_name = "quotaemailtemplatelistresponse";
@Inject
QuotaResponseBuilder _quotaResponseBuilder;
@Parameter(name = "templatetype", type = CommandType.STRING, description = "List by type of the quota email template, allowed types: QUOTA_LOW, QUOTA_EMPTY")
private String templateName;
public String getTemplateName() {
return templateName;
}
public void setTemplateName(String templateName) {
this.templateName = templateName;
}
@Override
public void execute() {
final ListResponse<QuotaEmailTemplateResponse> response = new ListResponse<QuotaEmailTemplateResponse>();
response.setResponses(_quotaResponseBuilder.listQuotaEmailTemplates(this));
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public String getCommandName() {
return s_name;
}
}

View File

@ -0,0 +1,122 @@
//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.api.command;
import com.cloud.user.Account;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.quota.constant.QuotaConfig;
import org.apache.log4j.Logger;
import javax.inject.Inject;
import java.util.Arrays;
@APICommand(name = "quotaEmailTemplateUpdate", responseObject = SuccessResponse.class, description = "Updates existing email templates for quota alerts", since = "4.6.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class QuotaEmailTemplateUpdateCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(QuotaEmailTemplateUpdateCmd.class);
private static final String s_name = "quotaemailtemplateupdateresponse";
@Inject
QuotaResponseBuilder _quotaResponseBuilder;
@Parameter(name = "templatetype", type = CommandType.STRING, required=true, description = "Type of the quota email template, allowed types: QUOTA_LOW, QUOTA_EMPTY")
private String templateName;
@Parameter(name = "templatesubject", type = CommandType.STRING, required=true, description = "The quota email template subject, max: 77 characters", length = 77)
private String templateSubject;
@Parameter(name = "templatebody", type = CommandType.STRING, required=true, description = "The quota email template body, max: 500k characters", length = 512000)
private String templateBody;
@Parameter(name = "locale", type = CommandType.STRING, description = "The locale of the email text")
private String locale;
@Override
public void execute() {
final String templateName = getTemplateName();
if (templateName == null || getTemplateSubject() == null || getTemplateBody() == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Failed to update quota email template due to empty or invalid template name or text");
}
boolean isValidTemplateName = false;
for (QuotaConfig.QuotaEmailTemplateTypes e: QuotaConfig.QuotaEmailTemplateTypes.values()) {
if (e.toString().equalsIgnoreCase(templateName)) {
isValidTemplateName = true;
setTemplateName(e.toString());
break;
}
}
if (!isValidTemplateName) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid quota email template type, allowed values are: " + Arrays.toString(QuotaConfig.QuotaEmailTemplateTypes.values()));
}
if (!_quotaResponseBuilder.updateQuotaEmailTemplate(this)) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Unable to update quota email template due to an internal error");
}
final SuccessResponse response = new SuccessResponse();
response.setResponseName(getCommandName());
response.setSuccess(true);
setResponseObject(response);
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
public void setTemplateName(String templateName) {
this.templateName = templateName;
}
public String getTemplateName() {
return templateName;
}
public String getTemplateSubject() {
return templateSubject;
}
public String getTemplateBody() {
return templateBody;
}
public String getLocale() {
return locale;
}
public void setTemplateSubject(String templateSubject) {
this.templateSubject = templateSubject;
}
public void setTemplateBody(String templateBody) {
this.templateBody = templateBody;
}
public void setLocale(String locale) {
this.locale = locale;
}
}

View File

@ -0,0 +1,141 @@
//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.api.command;
import java.util.Date;
import java.util.List;
import javax.inject.Inject;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.api.response.QuotaStatementResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
import org.apache.cloudstack.api.response.QuotaStatementItemResponse;
import com.cloud.user.Account;
@APICommand(name = "quotaStatement", responseObject = QuotaStatementItemResponse.class, description = "Create a quota statement", since = "4.6.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class QuotaStatementCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(QuotaStatementCmd.class);
private static final String s_name = "quotastatementresponse";
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = true, description = "Optional, Account Id for which statement needs to be generated")
private String accountName;
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class, description = "Optional, If domain Id is given and the caller is domain admin then the statement is generated for domain.")
private Long domainId;
@Parameter(name = ApiConstants.END_DATE, type = CommandType.DATE, required = true, description = "End date range for quota query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.")
private Date endDate;
@Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, required = true, description = "Start date range quota query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-01.")
private Date startDate;
@Parameter(name = ApiConstants.TYPE, type = CommandType.INTEGER, description = "List quota usage records for the specified usage type")
private Integer usageType;
@Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, description = "List usage records for the specified account")
private Long accountId;
@Inject
QuotaResponseBuilder _responseBuilder;
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public Integer getUsageType() {
return usageType;
}
public void setUsageType(Integer usageType) {
this.usageType = usageType;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public Long getDomainId() {
return domainId;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public Date getEndDate() {
return _responseBuilder.startOfNextDay(endDate == null ? new Date() : new Date(endDate.getTime()));
}
public void setEndDate(Date endDate) {
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public Date getStartDate() {
return startDate == null ? null : new Date(startDate.getTime());
}
public void setStartDate(Date startDate) {
this.startDate = startDate == null ? null : new Date(startDate.getTime());
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
Long accountId = _accountService.getActiveAccountByName(accountName, domainId).getAccountId();
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
return Account.ACCOUNT_ID_SYSTEM;
}
@Override
public void execute() {
List<QuotaUsageVO> quotaUsage = _responseBuilder.getQuotaUsage(this);
QuotaStatementResponse response = _responseBuilder.createQuotaStatementResponse(quotaUsage);
response.setStartDate(startDate == null ? null : new Date(startDate.getTime()));
response.setEndDate(endDate == null ? null : new Date(endDate.getTime()));
response.setResponseName(getCommandName());
setResponseObject(response);
}
}

View File

@ -0,0 +1,110 @@
//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.api.command;
import com.cloud.user.Account;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.BaseCmd.CommandType;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.api.response.QuotaSummaryResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.log4j.Logger;
import java.util.List;
import javax.inject.Inject;
@APICommand(name = "quotaSummary", responseObject = QuotaSummaryResponse.class, description = "Lists balance and quota usage for all accounts", since = "4.6.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class QuotaSummaryCmd extends BaseListCmd {
public static final Logger s_logger = Logger.getLogger(QuotaSummaryCmd.class);
private static final String s_name = "quotasummaryresponse";
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = false, description = "Optional, Account Id for which statement needs to be generated")
private String accountName;
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = false, entityType = DomainResponse.class, description = "Optional, If domain Id is given and the caller is domain admin then the statement is generated for domain.")
private Long domainId;
@Parameter(name = ApiConstants.LIST_ALL, type = CommandType.BOOLEAN, required = false, description = "Optional, to list all accounts irrespective of the quota activity")
private Boolean listAll;
@Inject
QuotaResponseBuilder _responseBuilder;
public QuotaSummaryCmd() {
super();
}
@Override
public void execute() {
Account caller = CallContext.current().getCallingAccount();
List<QuotaSummaryResponse> responses;
if (caller.getAccountId() <= 2) { //non root admin or system
if (getAccountName() != null && getDomainId() != null)
responses = _responseBuilder.createQuotaSummaryResponse(caller.getAccountName(), caller.getDomainId());
else
responses = _responseBuilder.createQuotaSummaryResponse(getListAll());
} else {
responses = _responseBuilder.createQuotaSummaryResponse(caller.getAccountName(), caller.getDomainId());
}
final ListResponse<QuotaSummaryResponse> response = new ListResponse<QuotaSummaryResponse>();
response.setResponses(responses);
response.setResponseName(getCommandName());
setResponseObject(response);
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public Long getDomainId() {
return domainId;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
@Override
public String getCommandName() {
return s_name;
}
public Boolean getListAll() {
return listAll == null ? false: listAll;
}
public void setListAll(Boolean listAll) {
this.listAll = listAll;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,95 @@
//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.api.command;
import com.cloud.user.Account;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.api.response.QuotaTariffResponse;
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
import org.apache.log4j.Logger;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@APICommand(name = "quotaTariffList", responseObject = QuotaTariffResponse.class, description = "Lists all quota tariff plans", since = "4.6.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class QuotaTariffListCmd extends BaseListCmd {
public static final Logger s_logger = Logger.getLogger(QuotaTariffListCmd.class);
private static final String s_name = "quotatarifflistresponse";
@Inject
QuotaResponseBuilder _responseBuilder;
@Parameter(name = ApiConstants.USAGE_TYPE, type = CommandType.INTEGER, required = false, description = "Usage type of the resource")
private Integer usageType;
@Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, required = false, description = "The effective start date on/after which the quota tariff is effective and older tariffs are no longer used for the usage type. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.")
private Date effectiveDate;
public QuotaTariffListCmd() {
super();
}
@Override
public void execute() {
final List<QuotaTariffVO> result = _responseBuilder.listQuotaTariffPlans(this);
final List<QuotaTariffResponse> responses = new ArrayList<QuotaTariffResponse>();
for (final QuotaTariffVO resource : result) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Result desc=" + resource.getDescription() + " date=" + resource.getEffectiveOn() + " val=" + resource.getCurrencyValue());
}
responses.add(_responseBuilder.createQuotaTariffResponse(resource));
}
final ListResponse<QuotaTariffResponse> response = new ListResponse<QuotaTariffResponse>();
response.setResponses(responses);
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
public Date getEffectiveDate() {
return effectiveDate ==null ? null : new Date(effectiveDate.getTime());
}
public Integer getUsageType() {
return usageType;
}
public void setUsageType(Integer usageType) {
this.usageType = usageType;
}
}

View File

@ -0,0 +1,102 @@
//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.api.command;
import com.cloud.user.Account;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.api.response.QuotaTariffResponse;
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
import org.apache.log4j.Logger;
import javax.inject.Inject;
import java.util.Date;
@APICommand(name = "quotaTariffUpdate", responseObject = QuotaTariffResponse.class, description = "Update the tariff plan for a resource", since = "4.6.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class QuotaTariffUpdateCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(QuotaTariffUpdateCmd.class);
private static final String s_name = "quotatariffupdateresponse";
@Inject
QuotaResponseBuilder _responseBuilder;
@Parameter(name = ApiConstants.USAGE_TYPE, type = CommandType.INTEGER, required = true, description = "Integer value for the usage type of the resource")
private Integer usageType;
@Parameter(name = "value", type = CommandType.DOUBLE, required = true, description = "The quota tariff value of the resource as per the default unit")
private Double value;
@Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, required = true, description = "The effective start date on/after which the quota tariff is effective and older tariffs are no longer used for the usage type. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.")
private Date startDate;
public int getUsageType() {
return usageType;
}
public void setUsageType(int usageType) {
this.usageType = usageType;
}
public Double getValue() {
return value;
}
public void setValue(Double value) {
this.value = value;
}
public Date getStartDate() {
return startDate == null ? null : new Date(startDate.getTime());
}
public void setStartDate(Date startDate) {
this.startDate = startDate == null ? null : new Date(startDate.getTime());
}
public QuotaTariffUpdateCmd() {
super();
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public void execute() {
final QuotaTariffVO result = _responseBuilder.updateQuotaTariffPlan(this);
if (result == null) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update quota tariff plan");
}
final QuotaTariffResponse response = _responseBuilder.createQuotaTariffResponse(result);
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,72 @@
//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.api.command;
import com.cloud.user.Account;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.response.QuotaUpdateResponse;
import org.apache.cloudstack.quota.QuotaAlertManager;
import org.apache.cloudstack.quota.QuotaManager;
import org.apache.cloudstack.quota.QuotaStatement;
import org.apache.log4j.Logger;
import java.util.Calendar;
import javax.inject.Inject;
@APICommand(name = "quotaUpdate", responseObject = QuotaUpdateResponse.class, description = "Update quota calculations, alerts and statements", since = "4.6.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class QuotaUpdateCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(QuotaUpdateCmd.class);
private static final String s_name = "quotaupdateresponse";
@Inject
QuotaManager _manager;
@Inject
QuotaStatement _statement;
@Inject
QuotaAlertManager _alert;
public QuotaUpdateCmd() {
super();
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public void execute() {
_manager.calculateQuotaUsage();
_statement.sendStatement();
_alert.checkAndSendQuotaAlertEmails();
QuotaUpdateResponse response = new QuotaUpdateResponse(Calendar.getInstance());
response.setResponseName(getCommandName());
response.setObjectName("quotacredits");
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,153 @@
//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.api.response;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
import com.cloud.serializer.Param;
public class QuotaBalanceResponse extends BaseResponse {
@SerializedName("accountid")
@Param(description = "account id")
private Long accountId;
@SerializedName("account")
@Param(description = "account name")
private String accountName;
@SerializedName("domain")
@Param(description = "domain id")
private Long domainId;
@SerializedName("startquota")
@Param(description = "quota started with")
private BigDecimal startQuota;
@SerializedName("endquota")
@Param(description = "quota by end of this period")
private BigDecimal endQuota;
@SerializedName("credits")
@Param(description = "list of credits made during this period")
private List<QuotaCreditsResponse> credits = null;
@SerializedName("startdate")
@Param(description = "start date")
private Date startDate = null;
@SerializedName("enddate")
@Param(description = "end date")
private Date endDate = null;
@SerializedName("currency")
@Param(description = "currency")
private String currency;
public QuotaBalanceResponse() {
super();
credits = new ArrayList<QuotaCreditsResponse>();
}
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public Long getDomainId() {
return domainId;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public BigDecimal getStartQuota() {
return startQuota;
}
public void setStartQuota(BigDecimal startQuota) {
this.startQuota = startQuota.setScale(2, RoundingMode.HALF_EVEN);
}
public BigDecimal getEndQuota() {
return endQuota;
}
public void setEndQuota(BigDecimal endQuota) {
this.endQuota = endQuota.setScale(2, RoundingMode.HALF_EVEN);
}
public List<QuotaCreditsResponse> getCredits() {
return credits;
}
public void setCredits(List<QuotaCreditsResponse> credits) {
this.credits = credits;
}
public void addCredits(QuotaBalanceVO credit) {
QuotaCreditsResponse cr = new QuotaCreditsResponse();
cr.setCredits(credit.getCreditBalance());
cr.setUpdatedOn(credit.getUpdatedOn() == null ? null : new Date(credit.getUpdatedOn().getTime()));
credits.add(0, cr);
}
public Date getStartDate() {
return startDate == null ? null : new Date(startDate.getTime());
}
public void setStartDate(Date startDate) {
this.startDate = startDate == null ? null : new Date(startDate.getTime());
}
public Date getEndDate() {
return endDate == null ? null : new Date(endDate.getTime());
}
public void setEndDate(Date endDate) {
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
}

View File

@ -0,0 +1,91 @@
//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.api.response;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.quota.vo.QuotaCreditsVO;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
public class QuotaCreditsResponse extends BaseResponse {
@SerializedName("credits")
@Param(description = "the credit deposited")
private BigDecimal credits;
@SerializedName("updated_by")
@Param(description = "the user name of the admin who updated the credits")
private String updatedBy;
@SerializedName("updated_on")
@Param(description = "the account name of the admin who updated the credits")
private Date updatedOn;
@SerializedName("currency")
@Param(description = "currency")
private String currency;
public QuotaCreditsResponse() {
super();
}
public QuotaCreditsResponse(QuotaCreditsVO result, String updatedBy) {
super();
if (result != null) {
setCredits(result.getCredit());
setUpdatedBy(updatedBy);
setUpdatedOn(new Date());
}
}
public BigDecimal getCredits() {
return credits;
}
public void setCredits(BigDecimal credits) {
this.credits = credits.setScale(2, RoundingMode.HALF_EVEN);
}
public String getUpdatedBy() {
return updatedBy;
}
public void setUpdatedBy(String updatedBy) {
this.updatedBy = updatedBy;
}
public Date getUpdatedOn() {
return updatedOn;
}
public void setUpdatedOn(Date updatedOn) {
this.updatedOn = updatedOn;
}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
}

View File

@ -0,0 +1,90 @@
//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.api.response;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.BaseResponse;
import java.util.Date;
public class QuotaEmailTemplateResponse extends BaseResponse {
@SerializedName("templatetype")
@Param(description = "Template type")
private String templateType;
@SerializedName("templatesubject")
@Param(description = "The quota email template subject")
private String templateSubject;
@SerializedName("templatebody")
@Param(description = "The quota email template content")
private String templateText;
@SerializedName("locale")
@Param(description = "The quota email template locale")
private String locale;
@SerializedName("last_updated")
@Param(description = "Last date/time when template was updated")
private Date lastUpdatedOn;
public QuotaEmailTemplateResponse() {
super();
this.setObjectName("quotaemailtemplate");
}
public String getTemplateType() {
return templateType;
}
public void setTemplateType(String templateType) {
this.templateType = templateType;
}
public String getTemplateSubject() {
return templateSubject;
}
public void setTemplateSubject(String templateSubject) {
this.templateSubject = templateSubject;
}
public String getTemplateText() {
return templateText;
}
public void setTemplateText(String templateText) {
this.templateText = templateText;
}
public String getLocale() {
return locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public Date getLastUpdatedOn() {
return lastUpdatedOn;
}
public void setLastUpdatedOn(Date lastUpdatedOn) {
this.lastUpdatedOn = lastUpdatedOn;
}
}

View File

@ -0,0 +1,65 @@
//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.api.response;
import org.apache.cloudstack.api.command.QuotaBalanceCmd;
import org.apache.cloudstack.api.command.QuotaEmailTemplateListCmd;
import org.apache.cloudstack.api.command.QuotaEmailTemplateUpdateCmd;
import org.apache.cloudstack.api.command.QuotaStatementCmd;
import org.apache.cloudstack.api.command.QuotaTariffListCmd;
import org.apache.cloudstack.api.command.QuotaTariffUpdateCmd;
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
import java.util.Date;
import java.util.List;
public interface QuotaResponseBuilder {
QuotaTariffVO updateQuotaTariffPlan(QuotaTariffUpdateCmd cmd);
List<QuotaTariffVO> listQuotaTariffPlans(QuotaTariffListCmd cmd);
QuotaTariffResponse createQuotaTariffResponse(QuotaTariffVO configuration);
QuotaStatementResponse createQuotaStatementResponse(List<QuotaUsageVO> quotaUsage);
QuotaBalanceResponse createQuotaBalanceResponse(List<QuotaBalanceVO> quotaUsage, Date startDate, Date endDate);
List<QuotaSummaryResponse> createQuotaSummaryResponse(Boolean listAll);
List<QuotaSummaryResponse> createQuotaSummaryResponse(String accountName, Long domainId);
QuotaBalanceResponse createQuotaLastBalanceResponse(List<QuotaBalanceVO> quotaBalance, Date startDate);
QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy, Date despositedOn);
List<QuotaUsageVO> getQuotaUsage(QuotaStatementCmd cmd);
List<QuotaBalanceVO> getQuotaBalance(QuotaBalanceCmd cmd);
QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy);
List<QuotaEmailTemplateResponse> listQuotaEmailTemplates(QuotaEmailTemplateListCmd cmd);
boolean updateQuotaEmailTemplate(QuotaEmailTemplateUpdateCmd cmd);
Date startOfNextDay(Date dt);
Date startOfNextDay();
}

View File

@ -0,0 +1,516 @@
//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.api.response;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
import com.cloud.user.AccountVO;
import com.cloud.user.User;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import org.apache.cloudstack.api.command.QuotaBalanceCmd;
import org.apache.cloudstack.api.command.QuotaEmailTemplateListCmd;
import org.apache.cloudstack.api.command.QuotaEmailTemplateUpdateCmd;
import org.apache.cloudstack.api.command.QuotaStatementCmd;
import org.apache.cloudstack.api.command.QuotaTariffListCmd;
import org.apache.cloudstack.api.command.QuotaTariffUpdateCmd;
import org.apache.cloudstack.quota.QuotaService;
import org.apache.cloudstack.quota.QuotaStatement;
import org.apache.cloudstack.quota.constant.QuotaConfig;
import org.apache.cloudstack.quota.constant.QuotaTypes;
import org.apache.cloudstack.quota.dao.QuotaAccountDao;
import org.apache.cloudstack.quota.dao.QuotaBalanceDao;
import org.apache.cloudstack.quota.dao.QuotaCreditsDao;
import org.apache.cloudstack.quota.dao.QuotaEmailTemplatesDao;
import org.apache.cloudstack.quota.dao.QuotaTariffDao;
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.QuotaCreditsVO;
import org.apache.cloudstack.quota.vo.QuotaEmailTemplatesVO;
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
import org.apache.cloudstack.region.RegionManager;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.ejb.Local;
import javax.inject.Inject;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
@Component
@Local(value = QuotaResponseBuilderImpl.class)
public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
private static final Logger s_logger = Logger.getLogger(QuotaResponseBuilderImpl.class);
@Inject
private QuotaTariffDao _quotaTariffDao;
@Inject
private QuotaBalanceDao _quotaBalanceDao;
@Inject
private QuotaCreditsDao _quotaCreditsDao;
@Inject
private QuotaUsageDao _quotaUsageDao;
@Inject
private QuotaEmailTemplatesDao _quotaEmailTemplateDao;
@Inject
private UserDao _userDao;
@Inject
private QuotaService _quotaService;
@Inject
private AccountDao _accountDao;
@Inject
private QuotaAccountDao _quotaAccountDao;
@Inject
private DomainDao _domainDao;
@Inject
private RegionManager _regionMgr;
@Inject
private QuotaStatement _statement;
@Override
public QuotaTariffResponse createQuotaTariffResponse(QuotaTariffVO tariff) {
final QuotaTariffResponse response = new QuotaTariffResponse();
response.setUsageType(tariff.getUsageType());
response.setUsageName(tariff.getUsageName());
response.setUsageUnit(tariff.getUsageUnit());
response.setUsageDiscriminator(tariff.getUsageDiscriminator());
response.setTariffValue(tariff.getCurrencyValue());
response.setEffectiveOn(tariff.getEffectiveOn());
response.setDescription(tariff.getDescription());
response.setCurrency(QuotaConfig.QuotaCurrencySymbol.value());
return response;
}
@Override
public List<QuotaSummaryResponse> createQuotaSummaryResponse(final String accountName, final Long domainId) {
List<QuotaSummaryResponse> result = new ArrayList<QuotaSummaryResponse>();
if (accountName != null && domainId != null) {
Account account = _accountDao.findActiveAccount(accountName, domainId);
QuotaSummaryResponse qr = getQuotaSummaryResponse(account);
result.add(qr);
}
return result;
}
@Override
public List<QuotaSummaryResponse> createQuotaSummaryResponse(Boolean listAll) {
List<QuotaSummaryResponse> result = new ArrayList<QuotaSummaryResponse>();
if (listAll) {
for (final AccountVO account : _accountDao.listAll()) {
QuotaSummaryResponse qr = getQuotaSummaryResponse(account);
result.add(qr);
}
} else {
for (final QuotaAccountVO quotaAccount : _quotaAccountDao.listAllQuotaAccount()) {
AccountVO account = _accountDao.findById(quotaAccount.getId());
QuotaSummaryResponse qr = getQuotaSummaryResponse(account);
result.add(qr);
}
}
return result;
}
private QuotaSummaryResponse getQuotaSummaryResponse(final Account account) {
Calendar[] period = _statement.getCurrentStatementTime();
if (account != null) {
QuotaSummaryResponse qr = new QuotaSummaryResponse();
DomainVO domain = _domainDao.findById(account.getDomainId());
BigDecimal curBalance = _quotaBalanceDao.lastQuotaBalance(account.getAccountId(), account.getDomainId(), period[1].getTime());
BigDecimal quotaUsage = _quotaUsageDao.findTotalQuotaUsage(account.getAccountId(), account.getDomainId(), null, period[0].getTime(), period[1].getTime());
qr.setAccountId(account.getAccountId());
qr.setAccountName(account.getAccountName());
qr.setDomainId(account.getDomainId());
qr.setDomainName(domain.getName());
qr.setBalance(curBalance);
qr.setQuotaUsage(quotaUsage);
qr.setState(account.getState());
qr.setStartDate(period[0].getTime());
qr.setEndDate(period[1].getTime());
qr.setCurrency(QuotaConfig.QuotaCurrencySymbol.value());
qr.setObjectName("summary");
return qr;
} else {
throw new InvalidParameterValueException("Quota summary response for an account requires a valid account.");
}
}
@Override
public QuotaBalanceResponse createQuotaBalanceResponse(List<QuotaBalanceVO> quotaBalance, Date startDate, Date endDate) {
if (quotaBalance == null || quotaBalance.isEmpty()) {
new InvalidParameterValueException("The request period does not contain balance entries.");
}
Collections.sort(quotaBalance, new Comparator<QuotaBalanceVO>() {
public int compare(QuotaBalanceVO o1, QuotaBalanceVO o2) {
return o2.getUpdatedOn().compareTo(o1.getUpdatedOn()); // desc
}
});
boolean have_balance_entries = false;
//check that there is at least one balance entry
for (Iterator<QuotaBalanceVO> it = quotaBalance.iterator(); it.hasNext();) {
QuotaBalanceVO entry = it.next();
if (entry.getCreditsId() > 0) {
have_balance_entries = true;
break;
}
}
//if last entry is a credit deposit then remove that as that is already
//accounted for in the starting balance after that entry, note the sort is desc
if (have_balance_entries) {
ListIterator<QuotaBalanceVO> li = quotaBalance.listIterator(quotaBalance.size());
// Iterate in reverse.
while (li.hasPrevious()) {
QuotaBalanceVO entry = li.previous();
if (s_logger.isDebugEnabled()) {
s_logger.debug("createQuotaBalanceResponse: Entry=" + entry);
}
if (entry.getCreditsId() > 0) {
li.remove();
} else {
break;
}
}
}
int quota_activity = quotaBalance.size();
QuotaBalanceResponse resp = new QuotaBalanceResponse();
BigDecimal lastCredits = new BigDecimal(0);
boolean consecutive = true;
for (Iterator<QuotaBalanceVO> it = quotaBalance.iterator(); it.hasNext();) {
QuotaBalanceVO entry = it.next();
if (s_logger.isDebugEnabled()) {
s_logger.debug("createQuotaBalanceResponse: All Credit Entry=" + entry);
}
if (entry.getCreditsId() > 0) {
if (consecutive) {
lastCredits = lastCredits.add(entry.getCreditBalance());
}
resp.addCredits(entry);
it.remove();
} else {
consecutive = false;
}
}
if (quota_activity > 0 && quotaBalance.size() > 0) {
// order is desc last item is the start item
QuotaBalanceVO startItem = quotaBalance.get(quotaBalance.size() - 1);
QuotaBalanceVO endItem = quotaBalance.get(0);
resp.setStartDate(startItem.getUpdatedOn());
resp.setStartQuota(startItem.getCreditBalance());
resp.setEndDate(endItem.getUpdatedOn());
if (s_logger.isDebugEnabled()) {
s_logger.debug("createQuotaBalanceResponse: Start Entry=" + startItem);
s_logger.debug("createQuotaBalanceResponse: End Entry=" + endItem);
}
resp.setEndQuota(endItem.getCreditBalance().add(lastCredits));
} else if (quota_activity > 0) {
// order is desc last item is the start item
resp.setStartDate(startDate);
resp.setStartQuota(new BigDecimal(0));
resp.setEndDate(endDate);
resp.setEndQuota(new BigDecimal(0).add(lastCredits));
} else {
resp.setStartDate(startDate);
resp.setEndDate(endDate);
resp.setStartQuota(new BigDecimal(0));
resp.setEndQuota(new BigDecimal(0));
}
resp.setCurrency(QuotaConfig.QuotaCurrencySymbol.value());
resp.setObjectName("balance");
return resp;
}
@Override
public QuotaStatementResponse createQuotaStatementResponse(final List<QuotaUsageVO> quotaUsage) {
if (quotaUsage == null || quotaUsage.isEmpty()) {
throw new InvalidParameterValueException("There is no usage data found for period mentioned.");
}
QuotaStatementResponse statement = new QuotaStatementResponse();
HashMap<Integer, QuotaTypes> quotaTariffMap = new HashMap<Integer, QuotaTypes>();
Collection<QuotaTypes> result = QuotaTypes.listQuotaTypes().values();
for (QuotaTypes quotaTariff : result) {
quotaTariffMap.put(quotaTariff.getQuotaType(), quotaTariff);
// add dummy record for each usage type
QuotaUsageVO dummy = new QuotaUsageVO(quotaUsage.get(0));
dummy.setUsageType(quotaTariff.getQuotaType());
dummy.setQuotaUsed(new BigDecimal(0));
quotaUsage.add(dummy);
}
if (s_logger.isDebugEnabled()) {
s_logger.debug(
"createQuotaStatementResponse Type=" + quotaUsage.get(0).getUsageType() + " usage=" + quotaUsage.get(0).getQuotaUsed().setScale(2, RoundingMode.HALF_EVEN)
+ " rec.id=" + quotaUsage.get(0).getUsageItemId() + " SD=" + quotaUsage.get(0).getStartDate() + " ED=" + quotaUsage.get(0).getEndDate());
}
Collections.sort(quotaUsage, new Comparator<QuotaUsageVO>() {
public int compare(QuotaUsageVO o1, QuotaUsageVO o2) {
if (o1.getUsageType() == o2.getUsageType())
return 0;
return o1.getUsageType() < o2.getUsageType() ? -1 : 1;
}
});
List<QuotaStatementItemResponse> items = new ArrayList<QuotaStatementItemResponse>();
QuotaStatementItemResponse lineitem;
int type = -1;
BigDecimal usage = new BigDecimal(0);
BigDecimal totalUsage = new BigDecimal(0);
quotaUsage.add(new QuotaUsageVO());// boundary
QuotaUsageVO prev = quotaUsage.get(0);
if (s_logger.isDebugEnabled()) {
s_logger.debug("createQuotaStatementResponse record count=" + quotaUsage.size());
}
for (final QuotaUsageVO quotaRecord : quotaUsage) {
if (type != quotaRecord.getUsageType()) {
if (type != -1) {
lineitem = new QuotaStatementItemResponse(type);
lineitem.setQuotaUsed(usage);
lineitem.setAccountId(prev.getAccountId());
lineitem.setDomainId(prev.getDomainId());
lineitem.setUsageUnit(quotaTariffMap.get(type).getQuotaUnit());
lineitem.setUsageName(quotaTariffMap.get(type).getQuotaName());
lineitem.setObjectName("quotausage");
items.add(lineitem);
totalUsage = totalUsage.add(usage);
usage = new BigDecimal(0);
}
type = quotaRecord.getUsageType();
}
prev = quotaRecord;
usage = usage.add(quotaRecord.getQuotaUsed());
}
statement.setLineItem(items);
statement.setTotalQuota(totalUsage);
statement.setCurrency(QuotaConfig.QuotaCurrencySymbol.value());
statement.setObjectName("statement");
return statement;
}
@Override
public List<QuotaTariffVO> listQuotaTariffPlans(final QuotaTariffListCmd cmd) {
List<QuotaTariffVO> result = new ArrayList<QuotaTariffVO>();
Date effectiveDate = cmd.getEffectiveDate() == null ? new Date() : cmd.getEffectiveDate();
Date adjustedEffectiveDate = _quotaService.computeAdjustedTime(effectiveDate);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Effective datec=" + effectiveDate + " quotatype=" + cmd.getUsageType() + " Adjusted date=" + adjustedEffectiveDate);
}
if (cmd.getUsageType() != null) {
QuotaTariffVO tariffPlan = _quotaTariffDao.findTariffPlanByUsageType(cmd.getUsageType(), adjustedEffectiveDate);
if (tariffPlan != null) {
result.add(tariffPlan);
}
} else {
result = _quotaTariffDao.listAllTariffPlans(adjustedEffectiveDate);
}
return result;
}
@Override
public QuotaTariffVO updateQuotaTariffPlan(QuotaTariffUpdateCmd cmd) {
final int quotaType = cmd.getUsageType();
final BigDecimal quotaCost = new BigDecimal(cmd.getValue());
final Date effectiveDate = _quotaService.computeAdjustedTime(cmd.getStartDate());
final Date now = _quotaService.computeAdjustedTime(new Date());
// if effective date is in the past return error
if (effectiveDate.compareTo(now) < 0) {
throw new InvalidParameterValueException("Incorrect effective date for tariff " + effectiveDate + " is less than now " + now);
}
QuotaTypes quotaConstant = QuotaTypes.listQuotaTypes().get(quotaType);
if (quotaConstant == null) {
throw new InvalidParameterValueException("Quota type does not exists " + quotaType);
}
QuotaTariffVO result = null;
result = new QuotaTariffVO(quotaType);
result.setUsageName(quotaConstant.getQuotaName());
result.setUsageUnit(quotaConstant.getQuotaUnit());
result.setUsageDiscriminator(quotaConstant.getDiscriminator());
result.setCurrencyValue(quotaCost);
result.setEffectiveOn(effectiveDate);
result.setUpdatedOn(now);
result.setUpdatedBy(cmd.getEntityOwnerId());
if (s_logger.isDebugEnabled()) {
s_logger.debug(String.format("Updating Quota Tariff Plan: New value=%s for resource type=%d effective on date=%s", quotaCost, quotaType, effectiveDate));
}
_quotaTariffDao.addQuotaTariff(result);
return result;
}
@Override
public QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy) {
Date depositDate = new Date();
Date adjustedStartDate = _quotaService.computeAdjustedTime(depositDate);
QuotaBalanceVO qb = _quotaBalanceDao.findLaterBalanceEntry(accountId, domainId, adjustedStartDate);
if (qb != null) {
throw new InvalidParameterValueException("Incorrect deposit date: " + adjustedStartDate + " there are balance entries after this date");
}
return addQuotaCredits(accountId, domainId, amount, updatedBy, adjustedStartDate);
}
@Override
public QuotaCreditsResponse addQuotaCredits(final Long accountId, final Long domainId, final Double amount, final Long updatedBy, final Date despositedOn) {
QuotaCreditsVO credits = new QuotaCreditsVO(accountId, domainId, new BigDecimal(amount), updatedBy);
s_logger.debug("AddQuotaCredits: Depositing " + amount + " on adjusted date " + despositedOn);
credits.setUpdatedOn(despositedOn);
QuotaCreditsVO result = _quotaCreditsDao.saveCredits(credits);
final AccountVO account = _accountDao.findById(accountId);
final boolean lockAccountEnforcement = "true".equalsIgnoreCase(QuotaConfig.QuotaEnableEnforcement.value());
final BigDecimal currentAccountBalance = _quotaBalanceDao.lastQuotaBalance(accountId, domainId, startOfNextDay(despositedOn));
if (lockAccountEnforcement && (currentAccountBalance.compareTo(new BigDecimal(0)) >= 0)) {
if (account.getState() == Account.State.locked) {
_regionMgr.enableAccount(account.getAccountName(), domainId, accountId);
}
}
String creditor = String.valueOf(Account.ACCOUNT_ID_SYSTEM);
User creditorUser = _userDao.getUser(updatedBy);
if (creditorUser != null) {
creditor = creditorUser.getUsername();
}
QuotaCreditsResponse response = new QuotaCreditsResponse(result, creditor);
response.setCurrency(QuotaConfig.QuotaCurrencySymbol.value());
return response;
}
private QuotaEmailTemplateResponse createQuotaEmailResponse(QuotaEmailTemplatesVO template) {
QuotaEmailTemplateResponse response = new QuotaEmailTemplateResponse();
response.setTemplateType(template.getTemplateName());
response.setTemplateSubject(template.getTemplateSubject());
response.setTemplateText(template.getTemplateBody());
response.setLocale(template.getLocale());
response.setLastUpdatedOn(template.getLastUpdated());
return response;
}
@Override
public List<QuotaEmailTemplateResponse> listQuotaEmailTemplates(QuotaEmailTemplateListCmd cmd) {
final String templateName = cmd.getTemplateName();
List<QuotaEmailTemplatesVO> templates = _quotaEmailTemplateDao.listAllQuotaEmailTemplates(templateName);
final List<QuotaEmailTemplateResponse> responses = new ArrayList<QuotaEmailTemplateResponse>();
for (final QuotaEmailTemplatesVO template : templates) {
responses.add(createQuotaEmailResponse(template));
}
return responses;
}
@Override
public boolean updateQuotaEmailTemplate(QuotaEmailTemplateUpdateCmd cmd) {
final String templateName = cmd.getTemplateName();
final String templateSubject = StringEscapeUtils.escapeJavaScript(cmd.getTemplateSubject());
final String templateBody = StringEscapeUtils.escapeJavaScript(cmd.getTemplateBody());
final String locale = cmd.getLocale();
final List<QuotaEmailTemplatesVO> templates = _quotaEmailTemplateDao.listAllQuotaEmailTemplates(templateName);
if (templates.size() == 1) {
final QuotaEmailTemplatesVO template = templates.get(0);
template.setTemplateSubject(templateSubject);
template.setTemplateBody(templateBody);
if (locale != null) {
template.setLocale(locale);
}
return _quotaEmailTemplateDao.updateQuotaEmailTemplate(template);
}
return false;
}
@Override
public QuotaBalanceResponse createQuotaLastBalanceResponse(List<QuotaBalanceVO> quotaBalance, Date startDate) {
if (quotaBalance == null) {
throw new InvalidParameterValueException("There are no balance entries on or before the requested date.");
}
if (startDate == null) {
startDate = new Date();
}
QuotaBalanceResponse resp = new QuotaBalanceResponse();
BigDecimal lastCredits = new BigDecimal(0);
for (QuotaBalanceVO entry : quotaBalance) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("createQuotaLastBalanceResponse Date=" + entry.getUpdatedOn() + " balance=" + entry.getCreditBalance() + " credit=" + entry.getCreditsId());
}
lastCredits = lastCredits.add(entry.getCreditBalance());
}
resp.setStartQuota(lastCredits);
resp.setStartDate(_quotaService.computeAdjustedTime(startDate));
resp.setCurrency(QuotaConfig.QuotaCurrencySymbol.value());
resp.setObjectName("balance");
return resp;
}
@Override
public List<QuotaUsageVO> getQuotaUsage(QuotaStatementCmd cmd) {
return _quotaService.getQuotaUsage(cmd.getAccountId(), cmd.getAccountName(), cmd.getDomainId(), cmd.getUsageType(), cmd.getStartDate(), cmd.getEndDate());
}
@Override
public List<QuotaBalanceVO> getQuotaBalance(QuotaBalanceCmd cmd) {
return _quotaService.findQuotaBalanceVO(cmd.getAccountId(), cmd.getAccountName(), cmd.getDomainId(), cmd.getStartDate(), cmd.getEndDate());
}
@Override
public Date startOfNextDay(Date dt) {
Calendar c = Calendar.getInstance();
c.setTime(dt);
c.add(Calendar.DATE, 1);
dt = c.getTime();
return dt;
}
@Override
public Date startOfNextDay() {
Calendar c = Calendar.getInstance();
c.setTime(new Date());
c.add(Calendar.DATE, 1);
Date dt = c.getTime();
return dt;
}
}

View File

@ -0,0 +1,118 @@
//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.api.response;
import java.math.BigDecimal;
import java.math.RoundingMode;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
public class QuotaStatementItemResponse extends BaseResponse {
@SerializedName("type")
@Param(description = "usage type")
private int usageType;
@SerializedName("accountid")
@Param(description = "account id")
private Long accountId;
@SerializedName("account")
@Param(description = "account name")
private String accountName;
@SerializedName("domain")
@Param(description = "domain id")
private Long domainId;
@SerializedName("name")
@Param(description = "usage type name")
private String usageName;
@SerializedName("unit")
@Param(description = "usage unit")
private String usageUnit;
@SerializedName("quota")
@Param(description = "quota consumed")
private BigDecimal quotaUsed;
public QuotaStatementItemResponse(final int usageType) {
this.usageType = usageType;
}
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public Long getDomainId() {
return domainId;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public String getUsageName() {
return usageName;
}
public void setUsageName(String usageName) {
this.usageName = usageName;
}
public int getUsageType() {
return usageType;
}
public void setUsageType(int usageType) {
this.usageType = usageType;
}
public String getUsageUnit() {
return usageUnit;
}
public void setUsageUnit(String usageUnit) {
this.usageUnit = usageUnit;
}
public BigDecimal getQuotaUsed() {
return quotaUsed;
}
public void setQuotaUsed(BigDecimal quotaUsed) {
this.quotaUsed = quotaUsed.setScale(2, RoundingMode.HALF_EVEN);
}
}

View File

@ -0,0 +1,130 @@
//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.api.response;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.BaseResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
public class QuotaStatementResponse extends BaseResponse {
@SerializedName("accountid")
@Param(description = "account id")
private Long accountId;
@SerializedName("account")
@Param(description = "account name")
private String accountName;
@SerializedName("domain")
@Param(description = "domain id")
private Long domainId;
@SerializedName("quotausage")
@Param(description = "list of quota usage under various types", responseObject = QuotaStatementItemResponse.class)
private List<QuotaStatementItemResponse> lineItem;
@SerializedName("totalquota")
@Param(description = "total quota used during this period")
private BigDecimal totalQuota;
@SerializedName("startdate")
@Param(description = "start date")
private Date startDate = null;
@SerializedName("enddate")
@Param(description = "end date")
private Date endDate = null;
@SerializedName("currency")
@Param(description = "currency")
private String currency;
public QuotaStatementResponse() {
super();
}
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public Long getDomainId() {
return domainId;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public List<QuotaStatementItemResponse> getLineItem() {
return lineItem;
}
public void setLineItem(List<QuotaStatementItemResponse> lineItem) {
this.lineItem = lineItem;
}
public Date getStartDate() {
return startDate == null ? null : new Date(startDate.getTime());
}
public void setStartDate(Date startDate) {
this.startDate = startDate == null ? null : new Date(startDate.getTime());
}
public Date getEndDate() {
return endDate == null ? null : new Date(endDate.getTime());
}
public void setEndDate(Date endDate) {
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public BigDecimal getTotalQuota() {
return totalQuota;
}
public void setTotalQuota(BigDecimal totalQuota) {
this.totalQuota = totalQuota.setScale(2, RoundingMode.HALF_EVEN);
}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
}

View File

@ -0,0 +1,155 @@
//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.api.response;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
import com.cloud.user.Account.State;
public class QuotaSummaryResponse extends BaseResponse {
@SerializedName("accountid")
@Param(description = "account id")
private Long accountId;
@SerializedName("account")
@Param(description = "account name")
private String accountName;
@SerializedName("domainid")
@Param(description = "domain id")
private Long domainId;
@SerializedName("domain")
@Param(description = "domain name")
private String domainName;
@SerializedName("balance")
@Param(description = "account balance")
private BigDecimal balance;
@SerializedName("state")
@Param(description = "account state")
private State state;
@SerializedName("quota")
@Param(description = "quota usage of this period")
private BigDecimal quotaUsage;
@SerializedName("startdate")
@Param(description = "start date")
private Date startDate = null;
@SerializedName("enddate")
@Param(description = "end date")
private Date endDate = null;
@SerializedName("currency")
@Param(description = "currency")
private String currency;
public QuotaSummaryResponse() {
super();
}
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public Long getDomainId() {
return domainId;
}
public void setDomainId(Long domainId) {
this.domainId = domainId;
}
public String getDomainName() {
return domainName;
}
public void setDomainName(String domainName) {
this.domainName = domainName;
}
public BigDecimal getQuotaUsage() {
return quotaUsage;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void setQuotaUsage(BigDecimal startQuota) {
this.quotaUsage = startQuota.setScale(2, RoundingMode.HALF_EVEN);
}
public BigDecimal getBalance() {
return balance;
}
public void setBalance(BigDecimal balance) {
this.balance = balance.setScale(2, RoundingMode.HALF_EVEN);
}
public Date getStartDate() {
return startDate == null ? null : new Date(startDate.getTime());
}
public void setStartDate(Date startDate) {
this.startDate = startDate == null ? null : new Date(startDate.getTime());
}
public Date getEndDate() {
return endDate == null ? null : new Date(endDate.getTime());
}
public void setEndDate(Date endDate) {
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
}

View File

@ -0,0 +1,134 @@
//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.api.response;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.BaseResponse;
import java.math.BigDecimal;
import java.util.Date;
public class QuotaTariffResponse extends BaseResponse {
@SerializedName("usageType")
@Param(description = "usageType")
private int usageType;
@SerializedName("usageName")
@Param(description = "usageName")
private String usageName;
@SerializedName("usageUnit")
@Param(description = "usageUnit")
private String usageUnit;
@SerializedName("usageDiscriminator")
@Param(description = "usageDiscriminator")
private String usageDiscriminator;
@SerializedName("tariffValue")
@Param(description = "tariffValue")
private BigDecimal tariffValue;
@SerializedName("effectiveDate")
@Param(description = "the date on/after which this quota value will be effective")
private Date effectiveOn = null;
@SerializedName("description")
@Param(description = "description")
private String description;
@SerializedName("currency")
@Param(description = "currency")
private String currency;
public QuotaTariffResponse() {
super();
this.setObjectName("quotatariff");
}
public QuotaTariffResponse(final int usageType) {
super();
this.usageType = usageType;
}
public String getUsageName() {
return usageName;
}
public void setUsageName(String usageName) {
this.usageName = usageName;
}
public int getUsageType() {
return usageType;
}
public void setUsageType(int usageType) {
this.usageType = usageType;
}
public String getUsageUnit() {
return usageUnit;
}
public void setUsageUnit(String usageUnit) {
this.usageUnit = usageUnit;
}
public String getUsageDiscriminator() {
return usageDiscriminator;
}
public void setUsageDiscriminator(String usageDiscriminator) {
this.usageDiscriminator = usageDiscriminator;
}
public BigDecimal getTariffValue() {
return tariffValue;
}
public void setTariffValue(BigDecimal tariffValue) {
this.tariffValue = tariffValue;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getEffectiveOn() {
return effectiveOn;
}
public void setEffectiveOn(Date effectiveOn) {
this.effectiveOn = effectiveOn;
}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
}

View File

@ -0,0 +1,58 @@
// 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.api.response;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
public class QuotaTypeResponse extends BaseResponse {
@SerializedName("quotatypeid")
@Param(description = "quota type")
private Integer quotaType;
@SerializedName(ApiConstants.DESCRIPTION)
@Param(description = "description of usage type")
private String description;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getQuotaType() {
return quotaType;
}
public void setQuotaType(Integer quotaType) {
this.quotaType = quotaType;
}
public QuotaTypeResponse(Integer quotaType, String description) {
this.quotaType = quotaType;
this.description = description;
setObjectName(ApiConstants.USAGE_TYPE);
}
}

View File

@ -0,0 +1,38 @@
//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.api.response;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.BaseResponse;
import java.util.Calendar;
import java.util.Date;
public class QuotaUpdateResponse extends BaseResponse {
@SerializedName("updated_on")
@Param(description = "timestamp when the run got over")
private Date updatedOn;
public QuotaUpdateResponse(Calendar now) {
super();
updatedOn=now.getTime();
}
}

View File

@ -0,0 +1,39 @@
//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;
import com.cloud.utils.component.PluggableService;
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
import java.util.Date;
import java.util.List;
public interface QuotaService extends PluggableService {
List<QuotaUsageVO> getQuotaUsage(Long accountId, String accountName, Long domainId, Integer usageType, Date startDate, Date endDate);
List<QuotaBalanceVO> findQuotaBalanceVO(Long accountId, String accountName, Long domainId, Date startDate, Date endDate);
Date computeAdjustedTime(Date date);
void setLockAccount(Long accountId, Boolean state);
void setMinBalance(Long accountId, Double balance);
}

View File

@ -0,0 +1,299 @@
//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;
import com.cloud.configuration.Config;
import com.cloud.domain.dao.DomainDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.user.Account;
import com.cloud.user.AccountVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.Filter;
import org.apache.cloudstack.api.command.QuotaBalanceCmd;
import org.apache.cloudstack.api.command.QuotaCreditsCmd;
import org.apache.cloudstack.api.command.QuotaEmailTemplateUpdateCmd;
import org.apache.cloudstack.api.command.QuotaEmailTemplateListCmd;
import org.apache.cloudstack.api.command.QuotaStatementCmd;
import org.apache.cloudstack.api.command.QuotaSummaryCmd;
import org.apache.cloudstack.api.command.QuotaTariffListCmd;
import org.apache.cloudstack.api.command.QuotaTariffUpdateCmd;
import org.apache.cloudstack.api.command.QuotaUpdateCmd;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.quota.constant.QuotaConfig;
import org.apache.cloudstack.quota.dao.QuotaAccountDao;
import org.apache.cloudstack.quota.dao.QuotaBalanceDao;
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.QuotaUsageVO;
import org.apache.cloudstack.utils.usage.UsageUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.ejb.Local;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
@Component
@Local(value = QuotaService.class)
public class QuotaServiceImpl extends ManagerBase implements QuotaService, Configurable, QuotaConfig {
private static final Logger s_logger = Logger.getLogger(QuotaServiceImpl.class);
@Inject
private AccountDao _accountDao;
@Inject
private QuotaAccountDao _quotaAcc;
@Inject
private QuotaUsageDao _quotaUsageDao;
@Inject
private DomainDao _domainDao;
@Inject
private ConfigurationDao _configDao;
@Inject
private QuotaBalanceDao _quotaBalanceDao;
@Inject
private QuotaResponseBuilder _respBldr;
private TimeZone _usageTimezone;
private int _aggregationDuration = 0;
public QuotaServiceImpl() {
super();
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params);
String timeZoneStr = _configDao.getValue(Config.UsageAggregationTimezone.toString());
String aggregationRange = _configDao.getValue(Config.UsageStatsJobAggregationRange.toString());
if (timeZoneStr == null) {
timeZoneStr = "GMT";
}
_usageTimezone = TimeZone.getTimeZone(timeZoneStr);
_aggregationDuration = Integer.parseInt(aggregationRange);
if (_aggregationDuration < UsageUtils.USAGE_AGGREGATION_RANGE_MIN) {
s_logger.warn("Usage stats job aggregation range is to small, using the minimum value of " + UsageUtils.USAGE_AGGREGATION_RANGE_MIN);
_aggregationDuration = UsageUtils.USAGE_AGGREGATION_RANGE_MIN;
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Usage timezone = " + _usageTimezone + " AggregationDuration=" + _aggregationDuration);
}
return true;
}
@Override
public List<Class<?>> getCommands() {
final List<Class<?>> cmdList = new ArrayList<Class<?>>();
if (!isQuotaServiceEnabled()) {
return cmdList;
}
cmdList.add(QuotaStatementCmd.class);
cmdList.add(QuotaBalanceCmd.class);
cmdList.add(QuotaSummaryCmd.class);
cmdList.add(QuotaUpdateCmd.class);
cmdList.add(QuotaTariffListCmd.class);
cmdList.add(QuotaTariffUpdateCmd.class);
cmdList.add(QuotaCreditsCmd.class);
cmdList.add(QuotaEmailTemplateListCmd.class);
cmdList.add(QuotaEmailTemplateUpdateCmd.class);
return cmdList;
}
@Override
public String getConfigComponentName() {
return "QUOTA-PLUGIN";
}
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] { QuotaPluginEnabled, QuotaEnableEnforcement, QuotaCurrencySymbol, QuotaStatementPeriod, QuotaSmtpHost, QuotaSmtpPort, QuotaSmtpTimeout, QuotaSmtpUser, QuotaSmtpPassword,
QuotaSmtpAuthType, QuotaSmtpSender };
}
public Boolean isQuotaServiceEnabled() {
return QuotaPluginEnabled.value();
}
@Override
public List<QuotaBalanceVO> findQuotaBalanceVO(Long accountId, String accountName, Long domainId, Date startDate, Date endDate) {
if ((accountId == null) && (accountName != null) && (domainId != null)) {
Account userAccount = null;
Account caller = CallContext.current().getCallingAccount();
if (_domainDao.isChildDomain(caller.getDomainId(), domainId)) {
Filter filter = new Filter(AccountVO.class, "id", Boolean.FALSE, null, null);
List<AccountVO> accounts = _accountDao.listAccounts(accountName, domainId, filter);
if (!accounts.isEmpty()) {
userAccount = accounts.get(0);
}
if (userAccount != null) {
accountId = userAccount.getId();
} else {
throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId);
}
} else {
throw new PermissionDeniedException("Invalid Domain Id or Account");
}
}
startDate = startDate == null ? new Date() : startDate;
if (endDate == null) {
// adjust start date to end of day as there is no end date
Date adjustedStartDate = computeAdjustedTime(_respBldr.startOfNextDay(startDate));
if (s_logger.isDebugEnabled()) {
s_logger.debug("getQuotaBalance1: Getting quota balance records for account: " + accountId + ", domainId: " + domainId + ", on or before " + adjustedStartDate);
}
List<QuotaBalanceVO> qbrecords = _quotaBalanceDao.lastQuotaBalanceVO(accountId, domainId, adjustedStartDate);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Found records size=" + qbrecords.size());
}
if (qbrecords.isEmpty()) {
s_logger.info("Incorrect Date there are no quota records before this date " + adjustedStartDate);
return qbrecords;
} else {
return qbrecords;
}
} else {
Date adjustedStartDate = computeAdjustedTime(startDate);
if (endDate.after(_respBldr.startOfNextDay())) {
throw new InvalidParameterValueException("Incorrect Date Range. End date:" + endDate + " should not be in future. ");
} else if (startDate.before(endDate)) {
Date adjustedEndDate = computeAdjustedTime(endDate);
if (s_logger.isDebugEnabled()) {
s_logger.debug("getQuotaBalance2: Getting quota balance records for account: " + accountId + ", domainId: " + domainId + ", between " + adjustedStartDate + " and "
+ adjustedEndDate);
}
List<QuotaBalanceVO> qbrecords = _quotaBalanceDao.findQuotaBalance(accountId, domainId, adjustedStartDate, adjustedEndDate);
if (s_logger.isDebugEnabled()) {
s_logger.debug("getQuotaBalance3: Found records size=" + qbrecords.size());
}
if (qbrecords.isEmpty()) {
s_logger.info("There are no quota records between these dates start date " + adjustedStartDate + " and end date:" + endDate);
return qbrecords;
} else {
return qbrecords;
}
} else {
throw new InvalidParameterValueException("Incorrect Date Range. Start date: " + startDate + " is after end date:" + endDate);
}
}
}
@Override
public List<QuotaUsageVO> getQuotaUsage(Long accountId, String accountName, Long domainId, Integer usageType, Date startDate, Date endDate) {
// if accountId is not specified, use accountName and domainId
if ((accountId == null) && (accountName != null) && (domainId != null)) {
Account userAccount = null;
Account caller = CallContext.current().getCallingAccount();
if (_domainDao.isChildDomain(caller.getDomainId(), domainId)) {
Filter filter = new Filter(AccountVO.class, "id", Boolean.FALSE, null, null);
List<AccountVO> accounts = _accountDao.listAccounts(accountName, domainId, filter);
if (!accounts.isEmpty()) {
userAccount = accounts.get(0);
}
if (userAccount != null) {
accountId = userAccount.getId();
} else {
throw new InvalidParameterValueException("Unable to find account " + accountName + " in domain " + domainId);
}
} else {
throw new PermissionDeniedException("Invalid Domain Id or Account");
}
}
if (startDate.after(endDate)) {
throw new InvalidParameterValueException("Incorrect Date Range. Start date: " + startDate + " is after end date:" + endDate);
}
if (endDate.after(_respBldr.startOfNextDay())) {
throw new InvalidParameterValueException("Incorrect Date Range. End date:" + endDate + " should not be in future. ");
}
Date adjustedEndDate = computeAdjustedTime(endDate);
Date adjustedStartDate = computeAdjustedTime(startDate);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Getting quota records for account: " + accountId + ", domainId: " + domainId + ", between " + startDate + " and " + endDate);
}
return _quotaUsageDao.findQuotaUsage(accountId, domainId, usageType, adjustedStartDate, adjustedEndDate);
}
@Override
public Date computeAdjustedTime(final Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
TimeZone localTZ = cal.getTimeZone();
int timezoneOffset = cal.get(Calendar.ZONE_OFFSET);
if (localTZ.inDaylightTime(date)) {
timezoneOffset += (60 * 60 * 1000);
}
cal.add(Calendar.MILLISECOND, timezoneOffset);
Date newTime = cal.getTime();
Calendar calTS = Calendar.getInstance(_usageTimezone);
calTS.setTime(newTime);
timezoneOffset = calTS.get(Calendar.ZONE_OFFSET);
if (_usageTimezone.inDaylightTime(date)) {
timezoneOffset += (60 * 60 * 1000);
}
calTS.add(Calendar.MILLISECOND, -1 * timezoneOffset);
return calTS.getTime();
}
@Override
public void setLockAccount(Long accountId, Boolean state) {
QuotaAccountVO acc = _quotaAcc.findByIdQuotaAccount(accountId);
if (acc == null) {
acc = new QuotaAccountVO(accountId);
acc.setQuotaEnforce(state ? 1 : 0);
_quotaAcc.persistQuotaAccount(acc);
} else {
acc.setQuotaEnforce(state ? 1 : 0);
_quotaAcc.updateQuotaAccount(accountId, acc);
}
}
@Override
public void setMinBalance(Long accountId, Double balance) {
QuotaAccountVO acc = _quotaAcc.findByIdQuotaAccount(accountId);
if (acc == null) {
acc = new QuotaAccountVO(accountId);
acc.setQuotaMinBalance(new BigDecimal(balance));
_quotaAcc.persistQuotaAccount(acc);
} else {
acc.setQuotaMinBalance(new BigDecimal(balance));
_quotaAcc.updateQuotaAccount(accountId, acc);
}
}
}

View File

@ -0,0 +1,65 @@
// 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.api.command;
import junit.framework.TestCase;
import org.apache.cloudstack.api.response.QuotaBalanceResponse;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class QuotaBalanceCmdTest extends TestCase {
@Mock
QuotaResponseBuilder responseBuilder;
@Test
public void testQuotaBalanceCmd() throws NoSuchFieldException, IllegalAccessException {
QuotaBalanceCmd cmd = new QuotaBalanceCmd();
Field rbField = QuotaBalanceCmd.class.getDeclaredField("_responseBuilder");
rbField.setAccessible(true);
rbField.set(cmd, responseBuilder);
List<QuotaBalanceVO> quotaBalanceVOList = new ArrayList<QuotaBalanceVO>();
Mockito.when(responseBuilder.getQuotaBalance(Mockito.any(cmd.getClass()))).thenReturn(quotaBalanceVOList);
Mockito.when(responseBuilder.createQuotaLastBalanceResponse(Mockito.eq(quotaBalanceVOList), Mockito.any(Date.class))).thenReturn(new QuotaBalanceResponse());
Mockito.when(responseBuilder.createQuotaBalanceResponse(Mockito.eq(quotaBalanceVOList), Mockito.any(Date.class), Mockito.any(Date.class))).thenReturn(new QuotaBalanceResponse());
Mockito.when(responseBuilder.startOfNextDay(Mockito.any(Date.class))).thenReturn(new Date());
// end date not specified
cmd.setStartDate(new Date());
cmd.setEndDate(null);
cmd.execute();
Mockito.verify(responseBuilder, Mockito.times(1)).createQuotaLastBalanceResponse(Mockito.eq(quotaBalanceVOList), Mockito.any(Date.class));
Mockito.verify(responseBuilder, Mockito.times(0)).createQuotaBalanceResponse(Mockito.eq(quotaBalanceVOList), Mockito.any(Date.class), Mockito.any(Date.class));
// end date specified
cmd.setEndDate(new Date());
cmd.execute();
Mockito.verify(responseBuilder, Mockito.times(1)).createQuotaBalanceResponse(Mockito.eq(quotaBalanceVOList), Mockito.any(Date.class), Mockito.any(Date.class));
}
}

View File

@ -0,0 +1,87 @@
// 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.api.command;
import com.cloud.user.AccountService;
import com.cloud.user.AccountVO;
import junit.framework.TestCase;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.QuotaCreditsResponse;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.quota.QuotaService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.lang.reflect.Field;
@RunWith(MockitoJUnitRunner.class)
public class QuotaCreditsCmdTest extends TestCase {
@Mock
QuotaResponseBuilder responseBuilder;
@Mock
QuotaService quotaService;
@Mock
AccountService accountService;
@Test
public void testQuotaCreditsCmd() throws NoSuchFieldException, IllegalAccessException {
QuotaCreditsCmd cmd = new QuotaCreditsCmd();
cmd.setAccountName("admin");
cmd.setMinBalance(200.0);
Field rbField = QuotaCreditsCmd.class.getDeclaredField("_responseBuilder");
rbField.setAccessible(true);
rbField.set(cmd, responseBuilder);
Field qsbField = QuotaCreditsCmd.class.getDeclaredField("_quotaService");
qsbField.setAccessible(true);
qsbField.set(cmd, quotaService);
Field asField = BaseCmd.class.getDeclaredField("_accountService");
asField.setAccessible(true);
asField.set(cmd, accountService);
AccountVO acc = new AccountVO();
acc.setId(2L);
Mockito.when(accountService.getActiveAccountByName(Mockito.anyString(), Mockito.anyLong())).thenReturn(acc);
Mockito.when(responseBuilder.addQuotaCredits(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyDouble(), Mockito.anyLong())).thenReturn(new QuotaCreditsResponse());
// No value provided test
try {
cmd.execute();
} catch (ServerApiException e) {
assertTrue(e.getErrorCode().equals(ApiErrorCode.PARAM_ERROR));
}
// With value provided test
cmd.setValue(11.80);
cmd.execute();
Mockito.verify(quotaService, Mockito.times(0)).setLockAccount(Mockito.anyLong(), Mockito.anyBoolean());
Mockito.verify(quotaService, Mockito.times(1)).setMinBalance(Mockito.anyLong(), Mockito.anyDouble());
Mockito.verify(responseBuilder, Mockito.times(1)).addQuotaCredits(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyDouble(), Mockito.anyLong());
}
}

View File

@ -0,0 +1,50 @@
// 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.api.command;
import junit.framework.TestCase;
import org.apache.cloudstack.api.response.QuotaEmailTemplateResponse;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class QuotaEmailTemplateListCmdTest extends TestCase {
@Mock
QuotaResponseBuilder responseBuilder;
@Test
public void testQuotaEmailTemplateListCmd() throws NoSuchFieldException, IllegalAccessException {
QuotaEmailTemplateListCmd cmd = new QuotaEmailTemplateListCmd();
Field rbField = QuotaEmailTemplateListCmd.class.getDeclaredField("_quotaResponseBuilder");
rbField.setAccessible(true);
rbField.set(cmd, responseBuilder);
List<QuotaEmailTemplateResponse> responses = new ArrayList<QuotaEmailTemplateResponse>();
Mockito.when(responseBuilder.listQuotaEmailTemplates(Mockito.eq(cmd))).thenReturn(responses);
cmd.execute();
Mockito.verify(responseBuilder, Mockito.times(1)).listQuotaEmailTemplates(cmd);
}
}

View File

@ -0,0 +1,68 @@
// 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.api.command;
import junit.framework.TestCase;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.quota.constant.QuotaConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.lang.reflect.Field;
@RunWith(MockitoJUnitRunner.class)
public class QuotaEmailTemplateUpdateCmdTest extends TestCase {
@Mock
QuotaResponseBuilder responseBuilder;
@Test
public void testQuotaEmailTemplateUpdateCmd () throws NoSuchFieldException, IllegalAccessException {
QuotaEmailTemplateUpdateCmd cmd = new QuotaEmailTemplateUpdateCmd();
Field rbField = QuotaEmailTemplateUpdateCmd.class.getDeclaredField("_quotaResponseBuilder");
rbField.setAccessible(true);
rbField.set(cmd, responseBuilder);
// templatename parameter check
try {
cmd.execute();
} catch (ServerApiException e) {
assertTrue(e.getErrorCode().equals(ApiErrorCode.PARAM_ERROR));
}
// invalid template name test
cmd.setTemplateName("randomTemplate");
cmd.setTemplateBody("some body");
cmd.setTemplateSubject("some subject");
try {
cmd.execute();
} catch (ServerApiException e) {
assertTrue(e.getErrorCode().equals(ApiErrorCode.PARAM_ERROR));
}
// valid template test
cmd.setTemplateName(QuotaConfig.QuotaEmailTemplateTypes.QUOTA_EMPTY.toString());
Mockito.when(responseBuilder.updateQuotaEmailTemplate(Mockito.eq(cmd))).thenReturn(true);
cmd.execute();
Mockito.verify(responseBuilder, Mockito.times(1)).updateQuotaEmailTemplate(Mockito.eq(cmd));
}
}

View File

@ -0,0 +1,53 @@
// 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.api.command;
import junit.framework.TestCase;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.api.response.QuotaStatementResponse;
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class QuotaStatementCmdTest extends TestCase {
@Mock
QuotaResponseBuilder responseBuilder;
@Test
public void testQuotaStatementCmd() throws NoSuchFieldException, IllegalAccessException {
QuotaStatementCmd cmd = new QuotaStatementCmd();
cmd.setAccountName("admin");
Field rbField = QuotaStatementCmd.class.getDeclaredField("_responseBuilder");
rbField.setAccessible(true);
rbField.set(cmd, responseBuilder);
List<QuotaUsageVO> quotaUsageVOList = new ArrayList<QuotaUsageVO>();
Mockito.when(responseBuilder.getQuotaUsage(Mockito.eq(cmd))).thenReturn(quotaUsageVOList);
Mockito.when(responseBuilder.createQuotaStatementResponse(Mockito.eq(quotaUsageVOList))).thenReturn(new QuotaStatementResponse());
cmd.execute();
Mockito.verify(responseBuilder, Mockito.times(1)).getQuotaUsage(Mockito.eq(cmd));
}
}

View File

@ -0,0 +1,62 @@
// 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.api.command;
import junit.framework.TestCase;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.api.response.QuotaTariffResponse;
import org.apache.cloudstack.quota.constant.QuotaTypes;
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class QuotaTariffListCmdTest extends TestCase {
@Mock
QuotaResponseBuilder responseBuilder;
@Test
public void testQuotaTariffListCmd() throws NoSuchFieldException, IllegalAccessException {
QuotaTariffListCmd cmd = new QuotaTariffListCmd();
Field rbField = QuotaTariffListCmd.class.getDeclaredField("_responseBuilder");
rbField.setAccessible(true);
rbField.set(cmd, responseBuilder);
List<QuotaTariffVO> quotaTariffVOList = new ArrayList<QuotaTariffVO>();
QuotaTariffVO tariff = new QuotaTariffVO();
tariff.setEffectiveOn(new Date());
tariff.setCurrencyValue(new BigDecimal(100));
tariff.setUsageType(QuotaTypes.MEMORY);
quotaTariffVOList.add(new QuotaTariffVO());
Mockito.when(responseBuilder.listQuotaTariffPlans(Mockito.eq(cmd))).thenReturn(quotaTariffVOList);
Mockito.when(responseBuilder.createQuotaTariffResponse(Mockito.any(QuotaTariffVO.class))).thenReturn(new QuotaTariffResponse());
cmd.execute();
Mockito.verify(responseBuilder, Mockito.times(1)).createQuotaTariffResponse(Mockito.any(QuotaTariffVO.class));
}
}

View File

@ -0,0 +1,67 @@
// 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.api.command;
import junit.framework.TestCase;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.api.response.QuotaTariffResponse;
import org.apache.cloudstack.quota.constant.QuotaTypes;
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Date;
@RunWith(MockitoJUnitRunner.class)
public class QuotaTariffUpdateCmdTest extends TestCase {
@Mock
QuotaResponseBuilder responseBuilder;
@Test
public void testQuotaTariffUpdateCmd() throws NoSuchFieldException, IllegalAccessException {
QuotaTariffUpdateCmd cmd = new QuotaTariffUpdateCmd();
Field rbField = QuotaTariffUpdateCmd.class.getDeclaredField("_responseBuilder");
rbField.setAccessible(true);
rbField.set(cmd, responseBuilder);
QuotaTariffVO tariff = new QuotaTariffVO();
tariff.setEffectiveOn(new Date());
tariff.setCurrencyValue(new BigDecimal(100));
tariff.setUsageType(QuotaTypes.MEMORY);
Mockito.when(responseBuilder.updateQuotaTariffPlan(Mockito.eq(cmd))).thenReturn(null);
try {
cmd.execute();
} catch (ServerApiException e) {
assertTrue(e.getErrorCode().equals(ApiErrorCode.INTERNAL_ERROR));
}
Mockito.when(responseBuilder.updateQuotaTariffPlan(Mockito.eq(cmd))).thenReturn(tariff);
Mockito.when(responseBuilder.createQuotaTariffResponse(Mockito.eq(tariff))).thenReturn(new QuotaTariffResponse());
cmd.execute();
Mockito.verify(responseBuilder, Mockito.times(1)).createQuotaTariffResponse(Mockito.eq(tariff));
}
}

View File

@ -0,0 +1,228 @@
// 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.api.response;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
import com.cloud.user.AccountVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.db.TransactionLegacy;
import junit.framework.TestCase;
import org.apache.cloudstack.api.command.QuotaEmailTemplateListCmd;
import org.apache.cloudstack.api.command.QuotaEmailTemplateUpdateCmd;
import org.apache.cloudstack.quota.QuotaService;
import org.apache.cloudstack.quota.constant.QuotaTypes;
import org.apache.cloudstack.quota.dao.QuotaBalanceDao;
import org.apache.cloudstack.quota.dao.QuotaCreditsDao;
import org.apache.cloudstack.quota.dao.QuotaEmailTemplatesDao;
import org.apache.cloudstack.quota.dao.QuotaTariffDao;
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
import org.apache.cloudstack.quota.vo.QuotaCreditsVO;
import org.apache.cloudstack.quota.vo.QuotaEmailTemplatesVO;
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
import org.apache.cloudstack.region.RegionManager;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class QuotaResponseBuilderImplTest extends TestCase {
@Mock
QuotaTariffDao quotaTariffDao;
@Mock
QuotaBalanceDao quotaBalanceDao;
@Mock
QuotaCreditsDao quotaCreditsDao;
@Mock
QuotaEmailTemplatesDao quotaEmailTemplateDao;
@Mock
UserDao userDao;
@Mock
QuotaService quotaService;
@Mock
AccountDao accountDao;
@Mock
RegionManager regionMgr;
QuotaResponseBuilderImpl quotaResponseBuilder = new QuotaResponseBuilderImpl();
@Before
public void setup() throws IllegalAccessException, NoSuchFieldException {
// Dummy transaction stack setup
TransactionLegacy.open("QuotaResponseBuilderImplTest");
Field tariffDaoField = QuotaResponseBuilderImpl.class.getDeclaredField("_quotaTariffDao");
tariffDaoField.setAccessible(true);
tariffDaoField.set(quotaResponseBuilder, quotaTariffDao);
Field balanceDaoField = QuotaResponseBuilderImpl.class.getDeclaredField("_quotaBalanceDao");
balanceDaoField.setAccessible(true);
balanceDaoField.set(quotaResponseBuilder, quotaBalanceDao);
Field quotaCreditsDaoField = QuotaResponseBuilderImpl.class.getDeclaredField("_quotaCreditsDao");
quotaCreditsDaoField.setAccessible(true);
quotaCreditsDaoField.set(quotaResponseBuilder, quotaCreditsDao);
Field quotaEmailTemplateDaoField = QuotaResponseBuilderImpl.class.getDeclaredField("_quotaEmailTemplateDao");
quotaEmailTemplateDaoField.setAccessible(true);
quotaEmailTemplateDaoField.set(quotaResponseBuilder, quotaEmailTemplateDao);
Field userDaoField = QuotaResponseBuilderImpl.class.getDeclaredField("_userDao");
userDaoField.setAccessible(true);
userDaoField.set(quotaResponseBuilder, userDao);
Field quotaServiceField = QuotaResponseBuilderImpl.class.getDeclaredField("_quotaService");
quotaServiceField.setAccessible(true);
quotaServiceField.set(quotaResponseBuilder, quotaService);
Field accountDaoField = QuotaResponseBuilderImpl.class.getDeclaredField("_accountDao");
accountDaoField.setAccessible(true);
accountDaoField.set(quotaResponseBuilder, accountDao);
Field regionMgrField = QuotaResponseBuilderImpl.class.getDeclaredField("_regionMgr");
regionMgrField.setAccessible(true);
regionMgrField.set(quotaResponseBuilder, regionMgr);
}
private QuotaTariffVO makeTariffTestData() {
QuotaTariffVO tariffVO = new QuotaTariffVO();
tariffVO.setUsageType(QuotaTypes.IP_ADDRESS);
tariffVO.setUsageName("ip address");
tariffVO.setUsageUnit("IP-Month");
tariffVO.setCurrencyValue(new BigDecimal(100.19));
tariffVO.setEffectiveOn(new Date());
tariffVO.setUsageDiscriminator("");
return tariffVO;
}
@Test
public void testQuotaResponse() {
QuotaTariffVO tariffVO = makeTariffTestData();
QuotaTariffResponse response = quotaResponseBuilder.createQuotaTariffResponse(tariffVO);
assertTrue(tariffVO.getUsageType() == response.getUsageType());
assertTrue(tariffVO.getCurrencyValue().equals(response.getTariffValue()));
}
@Test
public void testAddQuotaCredits() {
final long accountId = 2L;
final long domainId = 2L;
final double amount = 11.0;
final long updatedBy = 2L;
final Date now = new Date();
QuotaCreditsVO credit = new QuotaCreditsVO();
credit.setCredit(new BigDecimal(amount));
Mockito.when(quotaCreditsDao.saveCredits(Mockito.any(QuotaCreditsVO.class))).thenReturn(credit);
Mockito.when(quotaBalanceDao.lastQuotaBalance(Mockito.anyLong(), Mockito.anyLong(), Mockito.any(Date.class))).thenReturn(new BigDecimal(111));
AccountVO account = new AccountVO();
account.setState(Account.State.locked);
Mockito.when(accountDao.findById(Mockito.anyLong())).thenReturn(account);
QuotaCreditsResponse resp = quotaResponseBuilder.addQuotaCredits(accountId, domainId, amount, updatedBy, now);
assertTrue(resp.getCredits().compareTo(credit.getCredit()) == 0);
}
@Test
public void testListQuotaEmailTemplates() {
QuotaEmailTemplateListCmd cmd = new QuotaEmailTemplateListCmd();
cmd.setTemplateName("some name");
List<QuotaEmailTemplatesVO> templates = new ArrayList<>();
QuotaEmailTemplatesVO template = new QuotaEmailTemplatesVO();
template.setTemplateName("template");
templates.add(template);
Mockito.when(quotaEmailTemplateDao.listAllQuotaEmailTemplates(Mockito.anyString())).thenReturn(templates);
assertTrue(quotaResponseBuilder.listQuotaEmailTemplates(cmd).size() == 1);
}
@Test
public void testUpdateQuotaEmailTemplate() {
QuotaEmailTemplateUpdateCmd cmd = new QuotaEmailTemplateUpdateCmd();
cmd.setTemplateBody("some body");
cmd.setTemplateName("some name");
cmd.setTemplateSubject("some subject");
List<QuotaEmailTemplatesVO> templates = new ArrayList<>();
Mockito.when(quotaEmailTemplateDao.listAllQuotaEmailTemplates(Mockito.anyString())).thenReturn(templates);
Mockito.when(quotaEmailTemplateDao.updateQuotaEmailTemplate(Mockito.any(QuotaEmailTemplatesVO.class))).thenReturn(true);
// invalid template test
assertFalse(quotaResponseBuilder.updateQuotaEmailTemplate(cmd));
// valid template test
QuotaEmailTemplatesVO template = new QuotaEmailTemplatesVO();
template.setTemplateName("template");
templates.add(template);
assertTrue(quotaResponseBuilder.updateQuotaEmailTemplate(cmd));
}
@Test
public void testCreateQuotaLastBalanceResponse() {
List<QuotaBalanceVO> quotaBalance = new ArrayList<>();
// null balance test
try {
quotaResponseBuilder.createQuotaLastBalanceResponse(null, new Date());
} catch (InvalidParameterValueException e) {
assertTrue(e.getMessage().equals("There are no balance entries on or before the requested date."));
}
// empty balance test
try {
quotaResponseBuilder.createQuotaLastBalanceResponse(quotaBalance, new Date());
} catch (InvalidParameterValueException e) {
assertTrue(e.getMessage().equals("There are no balance entries on or before the requested date."));
}
// valid balance test
QuotaBalanceVO entry = new QuotaBalanceVO();
entry.setAccountId(2L);
entry.setCreditBalance(new BigDecimal(100));
quotaBalance.add(entry);
quotaBalance.add(entry);
Mockito.when(quotaService.computeAdjustedTime(Mockito.any(Date.class))).thenReturn(new Date());
QuotaBalanceResponse resp = quotaResponseBuilder.createQuotaLastBalanceResponse(quotaBalance, null);
assertTrue(resp.getStartQuota().compareTo(new BigDecimal(200)) == 0);
}
@Test
public void testStartOfNextDay() {
DateTime now = new DateTime();
DateTime nextDay = new DateTime(quotaResponseBuilder.startOfNextDay(now.toDate()));
DateTime nextDay2 = new DateTime(quotaResponseBuilder.startOfNextDay());
assertTrue(now.toLocalDate().equals(nextDay.minusDays(1).toLocalDate()));
assertTrue(now.toLocalDate().equals(nextDay2.minusDays(1).toLocalDate()));
}
}

View File

@ -0,0 +1,183 @@
// 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;
import com.cloud.configuration.Config;
import com.cloud.domain.dao.DomainDao;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.db.TransactionLegacy;
import junit.framework.TestCase;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.quota.constant.QuotaTypes;
import org.apache.cloudstack.quota.dao.QuotaAccountDao;
import org.apache.cloudstack.quota.dao.QuotaBalanceDao;
import org.apache.cloudstack.quota.dao.QuotaUsageDao;
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import javax.naming.ConfigurationException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public class QuotaServiceImplTest extends TestCase {
@Mock
AccountDao accountDao;
@Mock
QuotaAccountDao quotaAcc;
@Mock
QuotaUsageDao quotaUsageDao;
@Mock
DomainDao domainDao;
@Mock
ConfigurationDao configDao;
@Mock
QuotaBalanceDao quotaBalanceDao;
@Mock
QuotaResponseBuilder respBldr;
QuotaServiceImpl quotaService = new QuotaServiceImpl();
@Before
public void setup() throws IllegalAccessException, NoSuchFieldException, ConfigurationException {
// Dummy transaction stack setup
TransactionLegacy.open("QuotaServiceImplTest");
Field accountDaoField = QuotaServiceImpl.class.getDeclaredField("_accountDao");
accountDaoField.setAccessible(true);
accountDaoField.set(quotaService, accountDao);
Field quotaAccountDaoField = QuotaServiceImpl.class.getDeclaredField("_quotaAcc");
quotaAccountDaoField.setAccessible(true);
quotaAccountDaoField.set(quotaService, quotaAcc);
Field quotaUsageDaoField = QuotaServiceImpl.class.getDeclaredField("_quotaUsageDao");
quotaUsageDaoField.setAccessible(true);
quotaUsageDaoField.set(quotaService, quotaUsageDao);
Field domainDaoField = QuotaServiceImpl.class.getDeclaredField("_domainDao");
domainDaoField.setAccessible(true);
domainDaoField.set(quotaService, domainDao);
Field configDaoField = QuotaServiceImpl.class.getDeclaredField("_configDao");
configDaoField.setAccessible(true);
configDaoField.set(quotaService, configDao);
Field balanceDaoField = QuotaServiceImpl.class.getDeclaredField("_quotaBalanceDao");
balanceDaoField.setAccessible(true);
balanceDaoField.set(quotaService, quotaBalanceDao);
Field QuotaResponseBuilderField = QuotaServiceImpl.class.getDeclaredField("_respBldr");
QuotaResponseBuilderField.setAccessible(true);
QuotaResponseBuilderField.set(quotaService, respBldr);
Mockito.when(configDao.getValue(Mockito.eq(Config.UsageAggregationTimezone.toString()))).thenReturn("IST");
Mockito.when(configDao.getValue(Mockito.eq(Config.UsageStatsJobAggregationRange.toString()))).thenReturn("1");
quotaService.configure("randomName", null);
}
@Test
public void testComputeAdjustedTime() {
DateTime now = new DateTime(DateTimeZone.UTC);
DateTime result = new DateTime(quotaService.computeAdjustedTime(now.toDate()));
// FIXME: fix this test
}
@Test
public void testFindQuotaBalanceVO() {
final long accountId = 2L;
final String accountName = "admin123";
final long domainId = 1L;
final Date startDate = new DateTime().minusDays(2).toDate();
final Date endDate = new Date();
List<QuotaBalanceVO> records = new ArrayList<>();
QuotaBalanceVO qb = new QuotaBalanceVO();
qb.setCreditBalance(new BigDecimal(100));
qb.setAccountId(accountId);
records.add(qb);
Mockito.when(respBldr.startOfNextDay()).thenReturn(endDate);
Mockito.when(respBldr.startOfNextDay(Mockito.any(Date.class))).thenReturn(startDate);
Mockito.when(quotaBalanceDao.findQuotaBalance(Mockito.eq(accountId), Mockito.eq(domainId), Mockito.any(Date.class), Mockito.any(Date.class))).thenReturn(records);
Mockito.when(quotaBalanceDao.lastQuotaBalanceVO(Mockito.eq(accountId), Mockito.eq(domainId), Mockito.any(Date.class))).thenReturn(records);
// with enddate
assertTrue(quotaService.findQuotaBalanceVO(accountId, accountName, domainId, startDate, endDate).get(0).equals(qb));
// without enddate
assertTrue(quotaService.findQuotaBalanceVO(accountId, accountName, domainId, startDate, null).get(0).equals(qb));
}
@Test
public void testGetQuotaUsage() {
final long accountId = 2L;
final String accountName = "admin123";
final long domainId = 1L;
final Date startDate = new DateTime().minusDays(2).toDate();
final Date endDate = new Date();
Mockito.when(respBldr.startOfNextDay()).thenReturn(endDate);
quotaService.getQuotaUsage(accountId, accountName, domainId, QuotaTypes.IP_ADDRESS, startDate, endDate);
Mockito.verify(quotaUsageDao, Mockito.times(1)).findQuotaUsage(Mockito.eq(accountId), Mockito.eq(domainId), Mockito.eq(QuotaTypes.IP_ADDRESS), Mockito.any(Date.class), Mockito.any(Date.class));
}
@Test
public void testSetLockAccount() {
// existing account
QuotaAccountVO quotaAccountVO = new QuotaAccountVO();
Mockito.when(quotaAcc.findByIdQuotaAccount(Mockito.anyLong())).thenReturn(quotaAccountVO);
quotaService.setLockAccount(2L, true);
Mockito.verify(quotaAcc, Mockito.times(0)).persistQuotaAccount(Mockito.any(QuotaAccountVO.class));
Mockito.verify(quotaAcc, Mockito.times(1)).updateQuotaAccount(Mockito.anyLong(), Mockito.any(QuotaAccountVO.class));
// new account
Mockito.when(quotaAcc.findByIdQuotaAccount(Mockito.anyLong())).thenReturn(null);
quotaService.setLockAccount(2L, true);
Mockito.verify(quotaAcc, Mockito.times(1)).persistQuotaAccount(Mockito.any(QuotaAccountVO.class));
}
@Test
public void testSetMinBalance() {
final long accountId = 2L;
final double balance = 10.3F;
// existing account setting
QuotaAccountVO quotaAccountVO = new QuotaAccountVO();
Mockito.when(quotaAcc.findByIdQuotaAccount(Mockito.anyLong())).thenReturn(quotaAccountVO);
quotaService.setMinBalance(accountId, balance);
Mockito.verify(quotaAcc, Mockito.times(0)).persistQuotaAccount(Mockito.any(QuotaAccountVO.class));
Mockito.verify(quotaAcc, Mockito.times(1)).updateQuotaAccount(Mockito.anyLong(), Mockito.any(QuotaAccountVO.class));
// no account with limit set
Mockito.when(quotaAcc.findByIdQuotaAccount(Mockito.anyLong())).thenReturn(null);
quotaService.setMinBalance(accountId, balance);
Mockito.verify(quotaAcc, Mockito.times(1)).persistQuotaAccount(Mockito.any(QuotaAccountVO.class));
}
}

View File

@ -45,7 +45,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${cs.lang3.version}</version>
<version>${cs.commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>

View File

@ -32,7 +32,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${cs.lang3.version}</version>
<version>${cs.commons-lang3.version}</version>
</dependency>
</dependencies>
<build>

View File

@ -101,6 +101,7 @@
<module>network-elements/internal-loadbalancer</module>
<module>network-elements/vxlan</module>
<module>network-elements/globodns</module>
<module>database/quota</module>
</modules>
<dependencies>

16
pom.xml
View File

@ -99,7 +99,7 @@
<cs.aws.sdk.version>1.10.34</cs.aws.sdk.version>
<cs.jackson.version>2.6.3</cs.jackson.version>
<cs.lang.version>2.6</cs.lang.version>
<cs.lang3.version>3.4</cs.lang3.version>
<cs.commons-lang3.version>3.4</cs.commons-lang3.version>
<cs.commons-io.version>2.4</cs.commons-io.version>
<cs.commons-validator.version>1.4.0</cs.commons-validator.version>
<cs.reflections.version>0.9.9</cs.reflections.version>
@ -116,6 +116,7 @@
<cs.javadoc.version>2.10.1</cs.javadoc.version>
<cs.opensaml.version>2.6.1</cs.opensaml.version>
<cs.xml-apis.version>1.4.01</cs.xml-apis.version>
<cs.joda-time.version>2.8.1</cs.joda-time.version>
</properties>
<distributionManagement>
@ -714,6 +715,19 @@
<ignore></ignore>
</action>
</pluginExecution>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<versionRange>[2.11,)</versionRange>
<goals>
<goal>check</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>

View File

@ -294,6 +294,14 @@ public class ParamProcessWorker implements DispatchWorker {
field.set(cmdObj, Float.valueOf(paramObj.toString()));
}
break;
case DOUBLE:
// Assuming that the parameters have been checked for required before now,
// we ignore blank or null values and defer to the command to set a default
// value for optional parameters ...
if (paramObj != null && isNotBlank(paramObj.toString())) {
field.set(cmdObj, Double.valueOf(paramObj.toString()));
}
break;
case INTEGER:
// Assuming that the parameters have been checked for required before now,
// we ignore blank or null values and defer to the command to set a default

View File

@ -2184,8 +2184,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
if (s_logger.isInfoEnabled()) {
s_logger.info("User " + username + " in domain " + domainName + " is disabled/locked (or account is disabled/locked)");
}
throw new CloudAuthenticationException("User " + username + " in domain " + domainName + " is disabled/locked (or account is disabled/locked)");
// return null;
throw new CloudAuthenticationException("User " + username + " (or their account) in domain " + domainName + " is disabled/locked. Please contact the administrator.");
}
// Whenever the user is able to log in successfully, reset the login attempts to zero
if (!isInternalAccount(userAccount.getId()))

View File

@ -62,6 +62,9 @@ public class ParamProcessWorkerTest {
@Parameter(name = "boolparam1", type = CommandType.BOOLEAN)
boolean boolparam1;
@Parameter(name = "doubleparam1", type = CommandType.DOUBLE)
double doubleparam1;
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
ResourceAllocationException, NetworkRuleConflictException {
@ -98,10 +101,12 @@ public class ParamProcessWorkerTest {
params.put("strparam1", "foo");
params.put("intparam1", "100");
params.put("boolparam1", "true");
params.put("doubleparam1", "11.89");
final TestCmd cmd = new TestCmd();
paramProcessWorker.processParameters(cmd, params);
Assert.assertEquals("foo", cmd.strparam1);
Assert.assertEquals(100, cmd.intparam1);
Assert.assertTrue(Double.compare(cmd.doubleparam1, 11.89) == 0);
}
}

View File

@ -19,4 +19,3 @@
-- Schema cleanup from 4.2.0 to 4.3.0;
--;

View File

@ -30,3 +30,113 @@ CREATE TABLE IF NOT EXISTS `cloud`.`domain_vlan_map` (
INDEX `i_account_vlan_map__vlan_id`(`vlan_db_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Quota
CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_account` (
`account_id` int(11) NOT NULL,
`quota_balance` decimal(15,2) NULL,
`quota_balance_date` datetime NULL,
`quota_enforce` int(1) DEFAULT NULL,
`quota_min_balance` decimal(15,2) DEFAULT NULL,
`quota_alert_date` datetime DEFAULT NULL,
`quota_alert_type` int(11) DEFAULT NULL,
`last_statement_date` datetime DEFAULT NULL,
PRIMARY KEY (`account_id`),
CONSTRAINT `account_id` FOREIGN KEY (`account_id`) REFERENCES `cloud_usage`.`account` (`quota_enforce`)
ON DELETE NO ACTION
ON UPDATE NO ACTION
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_tariff` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`usage_type` int(2) unsigned DEFAULT NULL,
`usage_name` varchar(255) NOT NULL COMMENT 'usage type',
`usage_unit` varchar(255) NOT NULL COMMENT 'usage type',
`usage_discriminator` varchar(255) NOT NULL COMMENT 'usage type',
`currency_value` decimal(15,2) NOT NULL COMMENT 'usage type',
`effective_on` datetime NOT NULL COMMENT 'date time on which this quota values will become effective',
`updated_on` datetime NOT NULL COMMENT 'date this entry was updated on',
`updated_by` bigint unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
LOCK TABLES `cloud_usage`.`quota_tariff` WRITE;
INSERT IGNORE INTO `cloud_usage`.`quota_tariff` (`usage_type`, `usage_name`, `usage_unit`, `usage_discriminator`, `currency_value`, `effective_on`, `updated_on`, `updated_by`) VALUES
(1,'RUNNING_VM','Compute-Month','',0.00,'2010-05-04', '2010-05-04',1),
(2,'ALLOCATED_VM','Compute-Month','',0.00,'2010-05-04', '2010-05-04',1),
(3,'IP_ADDRESS','IP-Month','',0.00,'2010-05-04', '2010-05-04',1),
(4,'NETWORK_BYTES_SENT','GB','',0.00,'2010-05-04', '2010-05-04',1),
(5,'NETWORK_BYTES_RECEIVED','GB','',0.00,'2010-05-04', '2010-05-04',1),
(6,'VOLUME','GB-Month','',0.00,'2010-05-04', '2010-05-04',1),
(7,'TEMPLATE','GB-Month','',0.00,'2010-05-04', '2010-05-04',1),
(8,'ISO','GB-Month','',0.00,'2010-05-04', '2010-05-04',1),
(9,'SNAPSHOT','GB-Month','',0.00,'2010-05-04', '2010-05-04',1),
(10,'SECURITY_GROUP','Policy-Month','',0.00,'2010-05-04', '2010-05-04',1),
(11,'LOAD_BALANCER_POLICY','Policy-Month','',0.00,'2010-05-04', '2010-05-04',1),
(12,'PORT_FORWARDING_RULE','Policy-Month','',0.00,'2010-05-04', '2010-05-04',1),
(13,'NETWORK_OFFERING','Policy-Month','',0.00,'2010-05-04', '2010-05-04',1),
(14,'VPN_USERS','Policy-Month','',0.00,'2010-05-04', '2010-05-04',1),
(15,'CPU_SPEED','Compute-Month','100MHz',0.00,'2010-05-04', '2010-05-04',1),
(16,'vCPU','Compute-Month','1VCPU',0.00,'2010-05-04', '2010-05-04',1),
(17,'MEMORY','Compute-Month','1MB',0.00,'2010-05-04', '2010-05-04',1),
(21,'VM_DISK_IO_READ','GB','1',0.00,'2010-05-04', '2010-05-04',1),
(22,'VM_DISK_IO_WRITE','GB','1',0.00,'2010-05-04', '2010-05-04',1),
(23,'VM_DISK_BYTES_READ','GB','1',0.00,'2010-05-04', '2010-05-04',1),
(24,'VM_DISK_BYTES_WRITE','GB','1',0.00,'2010-05-04', '2010-05-04',1),
(25,'VM_SNAPSHOT','GB-Month','',0.00,'2010-05-04', '2010-05-04',1);
UNLOCK TABLES;
CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_credits` (
`id` bigint unsigned NOT NULL auto_increment COMMENT 'id',
`account_id` bigint unsigned NOT NULL,
`domain_id` bigint(20) unsigned NOT NULL,
`credit` decimal(15,4) COMMENT 'amount credited',
`updated_on` datetime NOT NULL COMMENT 'date created',
`updated_by` bigint unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_usage` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`usage_item_id` bigint(20) unsigned NOT NULL,
`zone_id` bigint(20) unsigned NOT NULL,
`account_id` bigint(20) unsigned NOT NULL,
`domain_id` bigint(20) unsigned NOT NULL,
`usage_type` varchar(64) DEFAULT NULL,
`quota_used` decimal(15,8) unsigned NOT NULL,
`start_date` datetime NOT NULL COMMENT 'start time for this usage item',
`end_date` datetime NOT NULL COMMENT 'end time for this usage item',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_balance` (
`id` bigint unsigned NOT NULL auto_increment COMMENT 'id',
`account_id` bigint unsigned NOT NULL,
`domain_id` bigint(20) unsigned NOT NULL,
`credit_balance` decimal(15,8) COMMENT 'amount of credits remaining',
`credits_id` bigint unsigned COMMENT 'if not null then this entry corresponds to credit change quota_credits',
`updated_on` datetime NOT NULL COMMENT 'date updated on',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_email_templates` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`template_name` varchar(64) NOT NULL UNIQUE,
`template_subject` longtext,
`template_body` longtext,
`locale` varchar(25) DEFAULT 'en_US',
`updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
LOCK TABLES `cloud_usage`.`quota_email_templates` WRITE;
INSERT IGNORE INTO `cloud_usage`.`quota_email_templates` (`template_name`, `template_subject`, `template_body`) VALUES
('QUOTA_LOW', 'Quota Usage Threshold crossed by your account ${accountName}', 'Your account ${accountName} in the domain ${domainName} has reached quota usage threshold, your current quota balance is ${quotaBalance}.'),
('QUOTA_EMPTY', 'Quota Exhausted, account ${accountName} has no quota left.', 'Your account ${accountName} in the domain ${domainName} has exhausted allocated quota, please contact the administrator.'),
('QUOTA_UNLOCK_ACCOUNT', 'Quota credits added, account ${accountName} is unlocked now, if it was locked', 'Your account ${accountName} in the domain ${domainName} has enough quota credits now with the current balance of ${quotaBalance}.'),
('QUOTA_STATEMENT', 'Quota Statement for your account ${accountName}', 'Monthly quota statement of your account ${accountName} in the domain ${domainName}:<br>Balance = ${quotaBalance}<br>Total Usage = ${quotaUsage}.');
UNLOCK TABLES;

View File

@ -0,0 +1,204 @@
# 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.
""" Test cases for checking quota API
"""
#Import Local Modules
import marvin
from marvin.cloudstackTestCase import *
from marvin.cloudstackAPI import *
from marvin.lib.utils import *
from marvin.lib.base import *
from marvin.lib.common import *
from marvin.lib.utils import (random_gen)
from nose.plugins.attrib import attr
#Import System modules
import time
#ENABLE THE QUOTA PLUGIN AND RESTART THE MANAGEMENT SERVER TO RUN QUOTA TESTS
class TestQuota(cloudstackTestCase):
def setUp(self):
self.apiclient = self.testClient.getApiClient()
self.hypervisor = self.testClient.getHypervisorInfo()
self.dbclient = self.testClient.getDbConnection()
self.services = self.testClient.getParsedTestDataConfig()
self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests())
self.pod = get_pod(self.apiclient, self.zone.id)
self.cleanup = []
return
def tearDown(self):
try:
#Clean up, terminate the created templates
cleanup_resources(self.apiclient, self.cleanup)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
return
#Check quotaTariffList API returning 22 items
@attr(tags=["smoke", "advanced"], required_hardware="false")
def test_01_quota(self):
cmd = quotaTariffList.quotaTariffListCmd()
response = self.apiclient.quotaTariffList(cmd)
self.debug("Number of quota usage types: %s" % len(response))
self.assertEqual(
len(response), 22
)
for quota in response:
self.debug("Usage Name: %s" % quota.usageName)
self.assertEqual(
hasattr(quota, 'usageName'),
True,
"Check whether usgaeName field is there"
)
return
#Check quota tariff on a particualr day
@attr(tags=["smoke", "advanced"], required_hardware="false")
def test_02_quota(self):
cmd = quotaTariffList.quotaTariffListCmd()
cmd.startdate='2015-07-06'
response = self.apiclient.quotaTariffList(cmd)
self.debug("Number of quota usage types: %s" % len(response))
self.assertEqual(
len(response), 22
)
return
#check quota tariff of a particular item
@attr(tags=["smoke", "advanced"], required_hardware="false")
def test_03_quota(self):
cmd = quotaTariffList.quotaTariffListCmd()
cmd.startdate='2015-07-06'
cmd.usagetype='10'
response = self.apiclient.quotaTariffList(cmd)
self.debug("Number of quota usage types: %s" % len(response))
self.assertEqual(
len(response), 1
)
return
#check quota tariff
#Change it
#Check on affective date the new tariff should be applicable
#check the old tariff it should be same
@attr(tags=["smoke", "advanced"], required_hardware="false")
def test_04_quota(self):
cmd = quotaTariffList.quotaTariffListCmd()
cmd.startdate='2015-07-06'
cmd.usagetype='10'
response = self.apiclient.quotaTariffList(cmd)
self.debug("Number of quota usage types: %s" % len(response))
self.assertEqual(
len(response), 1
)
quota = response[0]
self.debug("Tariff Value for 10: %s" % quota.tariffValue)
cmd = quotaTariffUpdate.quotaTariffUpdateCmd()
tomorrow = datetime.date.today() + datetime.timedelta(days=1)
cmd.startdate=tomorrow
cmd.usagetype='10'
cmd.value='2.9'
response = self.apiclient.quotaTariffUpdate(cmd)
cmd = quotaTariffList.quotaTariffListCmd()
cmd.startdate=tomorrow
cmd.usagetype='10'
response = self.apiclient.quotaTariffList(cmd)
self.assertEqual(
len(response), 1
)
quota = response[0]
self.debug("Tariff Value for 10: %s" % quota.tariffValue)
self.assertEqual( quota.tariffValue, 2.9)
cmd = quotaTariffList.quotaTariffListCmd()
cmd.startdate='2015-07-07'
cmd.usagetype='10'
response = self.apiclient.quotaTariffList(cmd)
self.assertEqual(
len(response), 1
)
quota = response[0]
self.debug("Tariff Value for 10: %s" % quota.tariffValue)
self.assertEqual( quota.tariffValue, 0)
return
#Make credit deposit
@attr(tags=["smoke", "advanced"], required_hardware="false")
def test_05_quota(self):
cmd = quotaCredits.quotaCreditsCmd()
cmd.domainid = '1'
cmd.account = 'admin'
cmd.value = '10'
cmd.quota_enforce = '1'
cmd.min_balance = '9'
response = self.apiclient.quotaCredits(cmd)
self.debug("Credit response update on: %s" % response.updated_on)
return
#Make credit deposit and check today balance
@attr(tags=["smoke", "advanced"], required_hardware="false")
def test_06_quota(self):
cmd = quotaBalance.quotaBalanceCmd()
today = datetime.date.today()
cmd.domainid = '1'
cmd.account = 'admin'
cmd.startdate = today
response = self.apiclient.quotaBalance(cmd)
self.debug("Quota Balance on: %s" % response.startdate)
self.debug("is: %s" % response.startquota)
self.assertGreater( response.startquota, 9)
return
#make credit deposit and check start and end date balances
@attr(tags=["smoke", "advanced"], required_hardware="false")
def test_07_quota(self):
cmd = quotaBalance.quotaBalanceCmd()
today = datetime.date.today()
cmd.domainid = '1'
cmd.account = 'admin'
cmd.startdate = today - datetime.timedelta(days=2)
cmd.enddate = today
response = self.apiclient.quotaBalance(cmd)
self.debug("Quota Balance on: %s" % response.startdate)
self.debug("is: %s" % response.startquota)
self.assertGreater( response.endquota, 9)
return

View File

@ -118,6 +118,8 @@ known_categories = {
'listIdps': 'Authentication',
'authorizeSamlSso': 'Authentication',
'listSamlAuthorization': 'Authentication',
'quota': 'Quota',
'emailTemplate': 'Quota',
'Capacity': 'System Capacity',
'NetworkDevice': 'Network Device',
'ExternalLoadBalancer': 'Ext Load Balancer',

View File

@ -1024,6 +1024,50 @@ dictionary = {
'label.purpose': '<fmt:message key="label.purpose" />',
'label.Pxe.server.type': '<fmt:message key="label.Pxe.server.type" />',
'label.quickview': '<fmt:message key="label.quickview" />',
'label.usage.type': '<fmt:message key="label.usage.type" />',
'label.usage.unit': '<fmt:message key="label.usage.unit" />',
'label.quota.value': '<fmt:message key="label.quota.value" />',
'label.quota.description': '<fmt:message key="label.quota.description" />',
'label.quota.configuration': '<fmt:message key="label.quota.configuration" />',
'label.quota.configure': '<fmt:message key="label.quota.configure" />',
'label.quota.remove': '<fmt:message key="label.quota.remove" />',
'label.quota.totalusage': '<fmt:message key="label.quota.totalusage" />',
'label.quota.balance': '<fmt:message key="label.quota.balance" />',
'label.quota.summary': '<fmt:message key="label.quota.summary" />',
'label.quota.fullsummary': '<fmt:message key="label.quota.fullsummary" />',
'label.quota.minbalance': '<fmt:message key="label.quota.minbalance" />',
'label.quota.enforcequota': '<fmt:message key="label.quota.enforcequota" />',
'label.quota.tariff': '<fmt:message key="label.quota.tariff" />',
'label.quota.state': '<fmt:message key="label.quota.state" />',
'label.quota.startdate': '<fmt:message key="label.quota.startdate" />',
'label.quota.enddate': '<fmt:message key="label.quota.enddate" />',
'label.quota.total': '<fmt:message key="label.quota.total" />',
'label.quota.type.name': '<fmt:message key="label.quota.type.name" />',
'label.quota.type.unit': '<fmt:message key="label.quota.type.unit" />',
'label.quota.usage': '<fmt:message key="label.quota.usage" />',
'label.quota.startquota': '<fmt:message key="label.quota.startquota" />',
'label.quota.endquota': '<fmt:message key="label.quota.endquota" />',
'label.quota.statement.quota': '<fmt:message key="label.quota.statement.quota" />',
'label.quota.add.credits': '<fmt:message key="label.quota.add.credits" />',
'label.quota.date': '<fmt:message key="label.quota.date" />',
'label.quota.dates': '<fmt:message key="label.quota.dates" />',
'label.quota.credit': '<fmt:message key="label.quota.credit" />',
'label.quota.credits': '<fmt:message key="label.quota.credits" />',
'label.quota.value': '<fmt:message key="label.quota.value" />',
'label.quota.statement.bydates': '<fmt:message key="label.quota.statement.bydates" />',
'label.quota.email.template': '<fmt:message key="label.quota.email.template" />',
'label.quota.statement': '<fmt:message key="label.quota.statement" />',
'label.quota.statement.balance': '<fmt:message key="label.quota.statement.balance" />',
'label.quota.statement.tariff': '<fmt:message key="label.quota.statement.tariff" />',
'label.quota.statement.balance': '<fmt:message key="label.quota.statement.balance" />',
'label.quota.statement.tariff': '<fmt:message key="label.quota.statement.tariff" />',
'label.quota.tariff.edit': '<fmt:message key="label.quota.tariff.edit" />',
'label.quota.tariff.effectivedate': '<fmt:message key="label.quota.tariff.effectivedate" />',
'label.quota.email.subject': '<fmt:message key="label.quota.email.subject" />',
'label.quota.tariff.value': '<fmt:message key="label.quota.tariff.value" />',
'label.quota.email.subject': '<fmt:message key="label.quota.email.subject" />',
'label.quota.email.body': '<fmt:message key="label.quota.email.body" />',
'label.quota.email.lastupdated': '<fmt:message key="label.quota.email.lastupdated" />',
'label.rbd': '<fmt:message key="label.rbd" />',
'label.rbd.monitor': '<fmt:message key="label.rbd.monitor" />',
'label.rbd.pool': '<fmt:message key="label.rbd.pool" />',

View File

@ -16,6 +16,7 @@
// under the License.
(function($, cloudStack) {
cloudStack.plugins = [
// 'testPlugin'
'quota',
//'testPlugin'
];
}(jQuery, cloudStack));

Some files were not shown because too many files have changed in this diff Show More