diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 2471e0889578..d774c1498ab2 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -269,6 +269,7 @@ public class ApiConstants { public static final String VIRTUAL_MACHINE_IDS = "virtualmachineids"; public static final String VIRTUAL_MACHINE_ID_IP = "vmidipmap"; 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"; diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java index 12265665d30f..0f790cac264e 100644 --- a/api/src/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseCmd.java @@ -97,7 +97,7 @@ public static enum HTTPMethod { 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; diff --git a/api/src/org/apache/cloudstack/api/command/admin/usage/GetUsageRecordsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/usage/GetUsageRecordsCmd.java index fd8173d416da..76af050d2ca0 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/usage/GetUsageRecordsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/usage/GetUsageRecordsCmd.java @@ -38,6 +38,7 @@ @APICommand(name = "listUsageRecords", description = "Lists usage records for accounts", responseObject = UsageRecordResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class GetUsageRecordsCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(GetUsageRecordsCmd.class.getName()); private static final String s_name = "listusagerecordsresponse"; @@ -111,6 +112,30 @@ public Long getProjectId() { 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; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public void setAccountId(Long accountId) { + this.accountId = accountId; + } + + public void setUsageId(String usageId) { + this.usageId = usageId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/org/apache/cloudstack/usage/UsageTypes.java b/api/src/org/apache/cloudstack/usage/UsageTypes.java index 3edfd0b66aad..2163df7efc5d 100644 --- a/api/src/org/apache/cloudstack/usage/UsageTypes.java +++ b/api/src/org/apache/cloudstack/usage/UsageTypes.java @@ -22,6 +22,8 @@ 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; diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index c7f02600ac2a..d4dc46ac7c2d 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -1355,6 +1355,13 @@ 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.destroy.vm.graceperiod=Destroy VM Grace Period label.SNMP.community=SNMP Community label.SNMP.port=SNMP Port diff --git a/client/pom.xml b/client/pom.xml index 13e1411b9719..462af5bfd751 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -246,6 +246,11 @@ cloud-framework-ipc ${project.version} + + org.apache.cloudstack + cloud-framework-quota + ${project.version} + org.apache.cloudstack cloud-framework-rest @@ -356,6 +361,11 @@ cloud-plugin-network-globodns ${project.version} + + org.apache.cloudstack + cloud-plugin-database-quota + ${project.version} + diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index a66a3dce4863..2801fe38236e 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -781,3 +781,13 @@ listOpenDaylightControllers=1 ### GloboDNS commands addGloboDnsHost=1 + +### Quota Service +quotaStatement=15 +quotaBalance=15 +quotaTariffList=15 +quotaTariffUpdate=1 +quotaCredits=1 +quotaEmailTemplateList=1 +quotaEmailTemplateUpdate=1 + diff --git a/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java index a3ff45ca3ad3..7263057c6c9c 100644 --- a/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java +++ b/engine/schema/src/com/cloud/service/dao/ServiceOfferingDaoImpl.java @@ -238,4 +238,5 @@ public ServiceOfferingVO getcomputeOffering(ServiceOfferingVO serviceOffering, M return dummyoffering; } + } diff --git a/engine/schema/src/com/cloud/upgrade/dao/Upgrade451to452.java b/engine/schema/src/com/cloud/upgrade/dao/Upgrade451to452.java index 870e534fb7f4..16b8a0dd7993 100644 --- a/engine/schema/src/com/cloud/upgrade/dao/Upgrade451to452.java +++ b/engine/schema/src/com/cloud/upgrade/dao/Upgrade451to452.java @@ -19,17 +19,20 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; + import org.apache.log4j.Logger; import java.io.File; import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; public class Upgrade451to452 implements DbUpgrade { final static Logger s_logger = Logger.getLogger(Upgrade451to452.class); @Override public String[] getUpgradableVersionRange() { - return new String[] {"4.5.1", "4.5.2"}; + return new String[] { "4.5.1", "4.5.2" }; } @Override @@ -48,11 +51,24 @@ public File[] getPrepareScripts() { if (script == null) { throw new CloudRuntimeException("Unable to find db/schema-451to452.sql"); } - return new File[] {new File(script)}; + return new File[] { new File(script) }; } @Override public void performDataMigration(Connection conn) { + PreparedStatement pstmt = null; + try { + pstmt = conn.prepareStatement("ALTER TABLE `cloud_usage`.`cloud_usage` ADD COLUMN `quota_calculated` tinyint(1) DEFAULT 0 NOT NULL COMMENT 'quota calculation status'"); + pstmt.executeUpdate(); + pstmt.close(); + s_logger.debug("Altered usage table and added column quota_calculated"); + } catch (SQLException e) { + if (e.getMessage().contains("quota_calculated")) { + s_logger.debug("Usage table already has a column called quota_calculated"); + } else { + throw new CloudRuntimeException("Unable to create column quota_calculated", e); + } + } } @Override @@ -62,6 +78,7 @@ public File[] getCleanupScripts() { throw new CloudRuntimeException("Unable to find db/schema-451to452-cleanup.sql"); } - return new File[] {new File(script)}; + return new File[] { new File(script) }; } + } diff --git a/engine/schema/src/com/cloud/usage/UsageVO.java b/engine/schema/src/com/cloud/usage/UsageVO.java index c46abb3a9b5a..bf5f551d2485 100644 --- a/engine/schema/src/com/cloud/usage/UsageVO.java +++ b/engine/schema/src/com/cloud/usage/UsageVO.java @@ -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 = null; + + public Integer getQuotaCalculated() { + return quotaCalculated; + } + + public void setQuotaCalculated(Integer quotaCalculated) { + this.quotaCalculated = quotaCalculated; + } + public UsageVO() { } diff --git a/engine/schema/src/com/cloud/usage/dao/UsageDao.java b/engine/schema/src/com/cloud/usage/dao/UsageDao.java index 334c9d046a51..4062a63a18f7 100644 --- a/engine/schema/src/com/cloud/usage/dao/UsageDao.java +++ b/engine/schema/src/com/cloud/usage/dao/UsageDao.java @@ -53,4 +53,6 @@ public interface UsageDao extends GenericDao { void saveVmDiskStats(List vmDiskStats); void saveUsageRecords(List usageRecords); + + Pair, Integer> getUsageRecordsPendingQuotaAggregation(long accountId, long domainId); } diff --git a/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java b/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java index a2d38e24532a..200e5e8aa51f 100644 --- a/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java +++ b/engine/schema/src/com/cloud/usage/dao/UsageDaoImpl.java @@ -42,35 +42,30 @@ import com.cloud.utils.exception.CloudRuntimeException; @Component -@Local(value = {UsageDao.class}) +@Local(value = { UsageDao.class }) public class UsageDaoImpl extends GenericDaoBase implements UsageDao { public static final Logger s_logger = Logger.getLogger(UsageDaoImpl.class.getName()); private static final String DELETE_ALL = "DELETE FROM cloud_usage"; private static final String DELETE_ALL_BY_ACCOUNTID = "DELETE FROM cloud_usage WHERE account_id = ?"; 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"); @@ -111,7 +106,9 @@ public void saveAccounts(List accounts) { txn.start(); String sql = INSERT_ACCOUNT; 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 (AccountVO acct : accounts) { pstmt.setLong(1, acct.getId()); pstmt.setString(2, acct.getAccountName()); @@ -145,7 +142,9 @@ public void updateAccounts(List accounts) { txn.start(); String sql = UPDATE_ACCOUNT; 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 (AccountVO acct : accounts) { pstmt.setString(1, acct.getAccountName()); @@ -175,7 +174,9 @@ public void saveUserStats(List userStats) { txn.start(); String sql = INSERT_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.getId()); pstmt.setLong(2, userStat.getDataCenterId()); @@ -216,7 +217,9 @@ public void updateUserStats(List userStats) { 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()); @@ -313,7 +316,9 @@ public void updateVmDiskStats(List vmDiskStats) { 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()); @@ -347,7 +352,9 @@ public void saveVmDiskStats(List vmDiskStats) { txn.start(); String sql = INSERT_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.getId()); pstmt.setLong(2, vmDiskStat.getDataCenterId()); @@ -393,7 +400,9 @@ public void saveUsageRecords(List usageRecords) { txn.start(); String sql = INSERT_USAGE_RECORDS; 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 (UsageVO usageRecord : usageRecords) { pstmt.setLong(1, usageRecord.getZoneId()); pstmt.setLong(2, usageRecord.getAccountId()); @@ -451,4 +460,26 @@ public void saveUsageRecords(List usageRecords) { throw new CloudRuntimeException(ex.getMessage()); } } + + @Override + @SuppressWarnings("deprecation") + public Pair, Integer> getUsageRecordsPendingQuotaAggregation(final long accountId, final long domainId) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB).close(); + s_logger.debug("getting usage records for account: " + accountId + ", domainId: " + domainId); + Filter usageFilter = new Filter(UsageVO.class, "startDate", true, 0L, 10000L); + SearchCriteria sc = createSearchCriteria(); + if (accountId != -1) { + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + } + if (domainId != -1) { + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + } + sc.addAnd("quotaCalculated", SearchCriteria.Op.NULL); + sc.addOr("quotaCalculated", SearchCriteria.Op.EQ, 0); + s_logger.debug("Getting usage records" + usageFilter.getOrderBy()); + Pair, Integer> usageRecords = searchAndCountAllRecords(sc, usageFilter); + TransactionLegacy.open(opendb).close(); + return new Pair, Integer>(usageRecords.first(), usageRecords.second()); + } } diff --git a/framework/pom.xml b/framework/pom.xml index 84a4469daa7f..546ecf5aa93c 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -47,6 +47,7 @@ rest events jobs + quota cluster db config diff --git a/framework/quota/pom.xml b/framework/quota/pom.xml new file mode 100644 index 000000000000..0ed8f8bd5a68 --- /dev/null +++ b/framework/quota/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + cloud-framework-quota + Apache CloudStack Framework - Quota + + org.apache.cloudstack + cloudstack-framework + 4.5.2 + ../pom.xml + + + + org.apache.cloudstack + cloud-utils + ${project.version} + + + org.apache.cloudstack + cloud-engine-schema + ${project.version} + + + diff --git a/framework/quota/resources/META-INF/cloudstack/quota/spring-framework-quota-context.xml b/framework/quota/resources/META-INF/cloudstack/quota/spring-framework-quota-context.xml new file mode 100644 index 000000000000..5f3076437687 --- /dev/null +++ b/framework/quota/resources/META-INF/cloudstack/quota/spring-framework-quota-context.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + diff --git a/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaConfig.java b/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaConfig.java new file mode 100644 index 000000000000..518310ce0ef5 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaConfig.java @@ -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.quota.constant; + +import org.apache.cloudstack.framework.config.ConfigKey; + +public interface QuotaConfig { + + public static final ConfigKey QuotaPluginEnabled = new ConfigKey("Advanced", Boolean.class, "quota.enable.service", "false", "Indicates whether Quota plugin is enabled or not", + true); + + public static final ConfigKey QuotaEnableEnforcement = new ConfigKey("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 QuotaCurrencySymbol = new ConfigKey("Advanced", String.class, "quota.currency.symbol", "R", "The symbol for the currency in use to measure usage.", + true); + + public static final ConfigKey QuotaSmtpHost = new ConfigKey("Advanced", String.class, "quota.usage.smtp.host", "", "Quota SMTP host for quota related emails", true); + + public static final ConfigKey QuotaSmtpTimeout = new ConfigKey("Advanced", String.class, "quota.usage.smtp.connection.timeout", "60", + "Quota SMTP server connection timeout duration", true); + + public static final ConfigKey QuotaSmtpUser = new ConfigKey("Advanced", String.class, "quota.usage.smtp.user", "", "Quota SMTP server username", true); + + public static final ConfigKey QuotaSmtpPassword = new ConfigKey("Advanced", String.class, "quota.usage.smtp.password", "", "Quota SMTP server password", true); + + public static final ConfigKey QuotaSmtpPort = new ConfigKey("Advanced", String.class, "quota.usage.smtp.port", "", "Quota SMTP port", true); + + public static final ConfigKey QuotaSmtpAuthType = new ConfigKey("Advanced", String.class, "quota.usage.smtp.useAuth", "", + "If true, use secure SMTP authentication when sending emails.", true); + + public static final ConfigKey QuotaSmtpSender = new ConfigKey("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 + } +} \ No newline at end of file diff --git a/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaTypes.java b/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaTypes.java new file mode 100644 index 000000000000..483ecef278d9 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/constant/QuotaTypes.java @@ -0,0 +1,92 @@ +// 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.HashMap; + +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 Integer quotaType; + private String quotaName; + private String quotaUnit; + private String description; + private String discriminator; + + public 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 HashMap listQuotaTypes() { + final HashMap quotaTypeList = new HashMap(); + quotaTypeList.put(new Integer(RUNNING_VM), new QuotaTypes(new Integer(RUNNING_VM), "RUNNING_VM", "Compute-Month", "Running Vm Usage")); + quotaTypeList.put(new Integer(ALLOCATED_VM), new QuotaTypes(new Integer(ALLOCATED_VM), "ALLOCATED_VM", "Compute-Month", "Allocated Vm Usage")); + quotaTypeList.put(new Integer(IP_ADDRESS), new QuotaTypes(new Integer(IP_ADDRESS), "IP_ADDRESS", "IP-Month", "IP Address Usage")); + quotaTypeList.put(new Integer(NETWORK_BYTES_SENT), new QuotaTypes(new Integer(NETWORK_BYTES_SENT), "NETWORK_BYTES_SENT", "GB", "Network Usage (Bytes Sent)")); + quotaTypeList.put(new Integer(NETWORK_BYTES_RECEIVED), new QuotaTypes(new Integer(NETWORK_BYTES_RECEIVED), "NETWORK_BYTES_RECEIVED", "GB", "Network Usage (Bytes Received)")); + quotaTypeList.put(new Integer(VOLUME), new QuotaTypes(new Integer(VOLUME), "VOLUME", "GB-Month", "Volume Usage")); + quotaTypeList.put(new Integer(TEMPLATE), new QuotaTypes(new Integer(TEMPLATE), "TEMPLATE", "GB-Month", "Template Usage")); + quotaTypeList.put(new Integer(ISO), new QuotaTypes(new Integer(ISO), "ISO", "GB-Month", "ISO Usage")); + quotaTypeList.put(new Integer(SNAPSHOT), new QuotaTypes(new Integer(SNAPSHOT), "SNAPSHOT", "GB-Month", "Snapshot Usage")); + quotaTypeList.put(new Integer(SECURITY_GROUP), new QuotaTypes(new Integer(SECURITY_GROUP), "SECURITY_GROUP", "Policy-Month", "Security Group Usage")); + quotaTypeList.put(new Integer(LOAD_BALANCER_POLICY), new QuotaTypes(new Integer(LOAD_BALANCER_POLICY), "LOAD_BALANCER_POLICY", "Policy-Month", "Load Balancer Usage")); + quotaTypeList.put(new Integer(PORT_FORWARDING_RULE), new QuotaTypes(new Integer(PORT_FORWARDING_RULE), "PORT_FORWARDING_RULE", "Policy-Month", "Port Forwarding Usage")); + quotaTypeList.put(new Integer(NETWORK_OFFERING), new QuotaTypes(new Integer(NETWORK_OFFERING), "NETWORK_OFFERING", "Policy-Month", "Network Offering Usage")); + quotaTypeList.put(new Integer(VPN_USERS), new QuotaTypes(new Integer(VPN_USERS), "VPN_USERS", "Policy-Month", "VPN users usage")); + quotaTypeList.put(new Integer(VM_DISK_IO_READ), new QuotaTypes(new Integer(VM_DISK_IO_READ), "VM_DISK_IO_READ", "GB", "VM Disk usage(I/O Read)")); + quotaTypeList.put(new Integer(VM_DISK_IO_WRITE), new QuotaTypes(new Integer(VM_DISK_IO_WRITE), "VM_DISK_IO_WRITE", "GB", "VM Disk usage(I/O Write)")); + quotaTypeList.put(new Integer(VM_DISK_BYTES_READ), new QuotaTypes(new Integer(VM_DISK_BYTES_READ), "VM_DISK_BYTES_READ", "GB", "VM Disk usage(Bytes Read)")); + quotaTypeList.put(new Integer(VM_DISK_BYTES_WRITE), new QuotaTypes(new Integer(VM_DISK_BYTES_WRITE), "VPN_USERS", "GB", "VM Disk usage(Bytes Write)")); + quotaTypeList.put(new Integer(VM_SNAPSHOT), new QuotaTypes(new Integer(VM_SNAPSHOT), "VM_SNAPSHOT", "GB-Month", "VM Snapshot storage usage")); + quotaTypeList.put(new Integer(CPU_CLOCK_RATE), new QuotaTypes(new Integer(CPU_CLOCK_RATE), "CPU_CLOCK_RATE", "Compute-Month", "Quota tariff for using 1 CPU of clock rate 100MHz")); + quotaTypeList.put(new Integer(CPU_NUMBER), new QuotaTypes(new Integer(CPU_NUMBER), "CPU_NUMBER", "Compute-Month", "Quota tariff for running VM that has 1vCPU")); + quotaTypeList.put(new Integer(MEMORY), new QuotaTypes(new Integer(MEMORY), "MEMORY", "Compute-Month", "Quota tariff for using 1MB or RAM for 1 hour")); + return quotaTypeList; + } + + 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) { + return listQuotaTypes().get(quotaType).getDescription(); + } +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDao.java new file mode 100644 index 000000000000..06df664cb8ee --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDao.java @@ -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 { + + List listAll(); + + QuotaAccountVO findById(Long id); + + QuotaAccountVO persist(QuotaAccountVO entity); + + boolean update(Long id, QuotaAccountVO entity); + +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDaoImpl.java new file mode 100644 index 000000000000..e2c5e5acfddd --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaAccountDaoImpl.java @@ -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. +package org.apache.cloudstack.quota.dao; + +import java.util.List; + +import javax.ejb.Local; + +import org.apache.cloudstack.quota.vo.QuotaAccountVO; +import org.springframework.stereotype.Component; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.TransactionLegacy; + +@Component +@Local(value = { QuotaAccountDao.class }) +public class QuotaAccountDaoImpl extends GenericDaoBase implements QuotaAccountDao { + + @Override + public List listAll() { + List result = null; + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB).close(); + result = super.listAll(); + TransactionLegacy.open(opendb).close(); + return result; + } + + @Override + public QuotaAccountVO findById(Long id) { + QuotaAccountVO result = null; + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB).close(); + result = super.findById(id); + TransactionLegacy.open(opendb).close(); + return result; + } + + @Override + public QuotaAccountVO persist(QuotaAccountVO entity) { + QuotaAccountVO result = null; + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB).close(); + result = super.persist(entity); + TransactionLegacy.open(opendb).close(); + return result; + } + + @Override + public boolean update(Long id, QuotaAccountVO entity) { + boolean result = false; + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB).close(); + result = super.update(id, entity); + TransactionLegacy.open(opendb).close(); + return result; + } + +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDao.java new file mode 100644 index 000000000000..8bf07ecfe9ea --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDao.java @@ -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 { + + void saveQuotaBalance(List credits); + + List 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 findQuotaBalance(Long accountId, Long domainId, Date startDate, Date endDate); + + List lastQuotaBalanceVO(Long accountId, Long domainId, Date startDate); + + BigDecimal lastQuotaBalance(Long accountId, Long domainId, Date startDate); + +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java new file mode 100644 index 000000000000..628777eda817 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaBalanceDaoImpl.java @@ -0,0 +1,201 @@ +//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.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import javax.ejb.Local; + +import org.springframework.stereotype.Component; +import org.apache.cloudstack.quota.vo.QuotaBalanceVO; +import org.apache.log4j.Logger; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.TransactionLegacy; + +@Component +@Local(value = { QuotaBalanceDao.class }) +public class QuotaBalanceDaoImpl extends GenericDaoBase implements QuotaBalanceDao { + private static final Logger s_logger = Logger.getLogger(QuotaBalanceDaoImpl.class.getName()); + + @SuppressWarnings("deprecation") + @Override + public QuotaBalanceVO findLastBalanceEntry(final long accountId, final long domainId, final Date beforeThis) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB).close(); + Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", false, 0L, 1L); + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + sc.addAnd("creditsId", SearchCriteria.Op.EQ, 0); + sc.addAnd("updatedOn", SearchCriteria.Op.LT, beforeThis); + List quotab = this.search(sc, filter); + TransactionLegacy.open(opendb).close(); + return quotab.size() > 0 ? quotab.get(0) : null; + } + + @SuppressWarnings("deprecation") + @Override + public QuotaBalanceVO findLaterBalanceEntry(final long accountId, final long domainId, final Date afterThis) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB).close(); + Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", true, 0L, 1L); + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + sc.addAnd("creditsId", SearchCriteria.Op.EQ, 0); + sc.addAnd("updatedOn", SearchCriteria.Op.GT, afterThis); + List quotab = this.search(sc, filter); + TransactionLegacy.open(opendb).close(); + return quotab.size() > 0 ? quotab.get(0) : null; + } + + @Override + public void saveQuotaBalance(final List credits) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); + try { + for (QuotaBalanceVO credit : credits) { + persist(credit); + } + } finally { + txn.close(); + } + TransactionLegacy.open(opendb).close(); + } + + @SuppressWarnings("deprecation") + @Override + public List findCreditBalance(final long accountId, final long domainId, final Date lastbalancedate, final Date beforeThis) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB).close(); + Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", true, 0L, Long.MAX_VALUE); + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + sc.addAnd("creditsId", SearchCriteria.Op.GT, 0); + if ((lastbalancedate != null) && (beforeThis != null) && lastbalancedate.before(beforeThis)) { + sc.addAnd("updatedOn", SearchCriteria.Op.BETWEEN, lastbalancedate, beforeThis); + } else { + return new ArrayList(); + } + List qb = search(sc, filter); + TransactionLegacy.open(opendb).close(); + return qb; + } + + @SuppressWarnings("deprecation") + @Override + public List findQuotaBalance(final Long accountId, final Long domainId, final Date startDate, final Date endDate) { + // TODO account for series of credits around boundaries + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); + List quotaUsageRecords = null; + try { + SearchCriteria sc = createSearchCriteria(); + if (accountId != null) { + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + } + if (domainId != null) { + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + } + if ((startDate != null) && (endDate != null) && startDate.before(endDate)) { + sc.addAnd("updatedOn", SearchCriteria.Op.BETWEEN, startDate, endDate); + } else { + return new ArrayList(); + } + quotaUsageRecords = listBy(sc); + if (quotaUsageRecords.size() == 0) { + quotaUsageRecords.addAll(lastQuotaBalanceVO(accountId, domainId, startDate)); + } + } finally { + txn.close(); + } + + TransactionLegacy.open(opendb).close(); + return quotaUsageRecords; + } + + + @SuppressWarnings("deprecation") + @Override + public List lastQuotaBalanceVO(final Long accountId, final Long domainId, final Date pivotDate) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); + List quotaUsageRecords = null; + List trimmedRecords = new ArrayList(); + try { + Filter filter = new Filter(QuotaBalanceVO.class, "updatedOn", false, 0L, 100L); + // ASSUMPTION there will be less than 100 continuous credit + // transactions + SearchCriteria sc = createSearchCriteria(); + if (accountId != null) { + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + } + if (domainId != null) { + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + } + if ((pivotDate != null)) { + sc.addAnd("updatedOn", SearchCriteria.Op.LTEQ, pivotDate); + } + quotaUsageRecords = search(sc, filter); + + // get records before startDate to find start balance + for (Iterator it = quotaUsageRecords.iterator(); it.hasNext();) { + QuotaBalanceVO entry = it.next(); + s_logger.info("findQuotaBalance Date=" + entry.getUpdatedOn().toGMTString() + " balance=" + entry.getCreditBalance() + " credit=" + entry.getCreditsId()); + if (entry.getCreditsId() > 0) { + trimmedRecords.add(entry); + } else { + trimmedRecords.add(entry); + break; // add only consecutive credit entries and last balance entry + } + } + + } finally { + txn.close(); + } + + TransactionLegacy.open(opendb).close(); + return trimmedRecords; + } + + @Override + public BigDecimal lastQuotaBalance(final Long accountId, final Long domainId, Date startDate) { + List quotaBalance = lastQuotaBalanceVO(accountId, domainId, startDate); + if (quotaBalance.size() == 0) { + new InvalidParameterValueException("There are no balance entries on or before the requested date."); + } + BigDecimal finalBalance = new BigDecimal(0); + for (Iterator it = quotaBalance.iterator(); it.hasNext();) { + QuotaBalanceVO entry = it.next(); + s_logger.info("lastQuotaBalance Date=" + entry.getUpdatedOn().toGMTString() + " balance=" + entry.getCreditBalance() + " credit=" + entry.getCreditsId()); + finalBalance.add(entry.getCreditBalance()); + } + return finalBalance; + } + +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDao.java new file mode 100644 index 000000000000..f08d8f96ca85 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDao.java @@ -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 { + + List findCredits(long accountId, long domainId, Date startDate, Date endDate); + + QuotaCreditsVO saveCredits(QuotaCreditsVO credits); + +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDaoImpl.java new file mode 100644 index 000000000000..05e48b0f7487 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaCreditsDaoImpl.java @@ -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.quota.dao; + +import java.util.ArrayList; +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.SearchCriteria; +import com.cloud.utils.db.TransactionLegacy; + +@Component +@Local(value = { QuotaCreditsDao.class }) +public class QuotaCreditsDaoImpl extends GenericDaoBase implements QuotaCreditsDao { + @Inject + QuotaBalanceDao _quotaBalanceDao; + + @SuppressWarnings("deprecation") + @Override + public List findCredits(final long accountId, final long domainId, final Date startDate, final Date endDate) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB); + Filter filter = new Filter(QuotaCreditsVO.class, "updatedOn", true, 0L, Long.MAX_VALUE); + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + if ((startDate != null) && (endDate != null) && startDate.before(endDate)) { + sc.addAnd("updatedOn", SearchCriteria.Op.BETWEEN, startDate, endDate); + } else { + return new ArrayList(); + } + List qc = search(sc, filter); + TransactionLegacy.open(opendb).close(); + return qc; + } + + @Override + public QuotaCreditsVO saveCredits(final QuotaCreditsVO credits) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB); + persist(credits); + // make an entry in the balance table + QuotaBalanceVO bal = new QuotaBalanceVO(credits); + _quotaBalanceDao.persist(bal); + TransactionLegacy.open(opendb).close(); + return credits; + } + +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDao.java new file mode 100644 index 000000000000..573a75397442 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDao.java @@ -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 { + List listAllQuotaEmailTemplates(String templateName); + boolean updateQuotaEmailTemplate(QuotaEmailTemplatesVO template); +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDaoImpl.java new file mode 100644 index 000000000000..c7b4908a1813 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaEmailTemplatesDaoImpl.java @@ -0,0 +1,64 @@ +//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.TransactionLegacy; +import org.apache.cloudstack.quota.vo.QuotaEmailTemplatesVO; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import java.util.List; + +@Component +@Local(value = { QuotaEmailTemplatesDao.class }) +public class QuotaEmailTemplatesDaoImpl extends GenericDaoBase implements QuotaEmailTemplatesDao { + + protected SearchBuilder QuotaEmailTemplateSearch; + + public QuotaEmailTemplatesDaoImpl() { + super(); + + QuotaEmailTemplateSearch = createSearchBuilder(); + QuotaEmailTemplateSearch.and("template_name", QuotaEmailTemplateSearch.entity().getTemplateName(), SearchCriteria.Op.EQ); + QuotaEmailTemplateSearch.done(); + } + + @Override + public List listAllQuotaEmailTemplates(String templateName) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB); + SearchCriteria sc = QuotaEmailTemplateSearch.create(); + if (templateName != null) { + sc.setParameters("template_name", templateName); + } + List result = this.listBy(sc); + TransactionLegacy.open(opendb).close(); + return result; + } + + @Override + public boolean updateQuotaEmailTemplate(QuotaEmailTemplatesVO template) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB); + final boolean result = this.update(template.getId(), template); + TransactionLegacy.open(opendb).close(); + return result; + } +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDao.java new file mode 100644 index 000000000000..7977f28942d7 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDao.java @@ -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.QuotaTariffVO; + +import java.util.Date; +import java.util.List; + +public interface QuotaTariffDao extends GenericDao { + + QuotaTariffVO findTariffPlanByUsageType(int quotaType, Date onOrBefore); + + List listAllTariffPlans(Date onOrBefore); + + boolean updateQuotaTariff(QuotaTariffVO plan); + + QuotaTariffVO addQuotaTariff(QuotaTariffVO plan); +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java new file mode 100644 index 000000000000..38aad156d0cd --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaTariffDaoImpl.java @@ -0,0 +1,138 @@ +//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.TransactionLegacy; + +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 implements QuotaTariffDao { + private static final Logger s_logger = Logger.getLogger(QuotaTariffDaoImpl.class.getName()); + + private final SearchBuilder searchUsageType; + private final SearchBuilder 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(); + } + + @Override + public QuotaTariffVO findTariffPlanByUsageType(final int quotaType, final Date effectiveDate) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + List result = null; + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); + try { + final Filter filter = new Filter(QuotaTariffVO.class, "effectiveOn", false, 0L, 1L); + final SearchCriteria sc = listAllIncludedUsageType.create(); + sc.setParameters("onorbefore", effectiveDate); + sc.setParameters("quotatype", quotaType); + result = search(sc, filter); + } finally { + txn.close(); + } + // Switch back + TransactionLegacy.open(opendb).close(); + if (result.size() > 0) { + //s_logger.info("findTariffPlanByUsageType: " + effectiveDate + "quota type " + quotaType + " val=" + result.get(0).getCurrencyValue()); + return result.get(0); + } else { + //s_logger.info("Missing quota type " + quotaType); + return null; + } + } + + @Override + public List listAllTariffPlans(final Date effectiveDate) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + List tariffs = new ArrayList(); + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); + try { + final Filter filter = new Filter(QuotaTariffVO.class, "effectiveOn", false, 0L, 1L); + final SearchCriteria sc = listAllIncludedUsageType.create(); + sc.setParameters("onorbefore", effectiveDate); + for (Integer quotaType : QuotaTypes.listQuotaTypes().keySet()) { + sc.setParameters("quotatype", quotaType); + List result = search(sc, filter); + if (result.size() > 0) { + tariffs.add(result.get(0)); + s_logger.info("listAllTariffPlans onorbefore" + effectiveDate + "quota type " + result.get(0).getDescription() + " , effective Date=" + result.get(0).getEffectiveOn() + " val=" + result.get(0).getCurrencyValue()); + } + } + } finally { + txn.close(); + } + // Switch back + TransactionLegacy.open(opendb).close(); + return tariffs; + } + + @Override + public boolean updateQuotaTariff(QuotaTariffVO plan) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); // Switch + // to + boolean result = false; + try { + // Usage DB + result = this.update(plan.getId(), plan); + } finally { + txn.close(); + } + TransactionLegacy.open(opendb).close(); // Switch back + return result; + } + + @Override + public QuotaTariffVO addQuotaTariff(QuotaTariffVO plan) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); // Switch + // to + QuotaTariffVO result = null; + try { + // Usage DB + plan.setId(null); + result = this.persist(plan); + } finally { + txn.close(); + } + TransactionLegacy.open(opendb).close(); // Switch back + return result; + } +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDao.java new file mode 100644 index 000000000000..79c55cea23eb --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDao.java @@ -0,0 +1,40 @@ +//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.QuotaUsageVO; + +import com.cloud.utils.Pair; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericDao; +import com.cloud.utils.db.SearchCriteria; + +public interface QuotaUsageDao extends GenericDao { + + List findQuotaUsage(Long accountId, Long domainId, Integer usageType, Date startDate, Date endDate); + + Pair, Integer> searchAndCountAllRecords(SearchCriteria sc, Filter filter); + + void saveQuotaUsage(List credits); + + BigDecimal findTotalQuotaUsage(Long accountId, Long domainId, Integer usageType, Date startDate, Date endDate); + +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDaoImpl.java new file mode 100644 index 000000000000..bff43d042391 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/QuotaUsageDaoImpl.java @@ -0,0 +1,106 @@ +//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.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.ejb.Local; + +import org.springframework.stereotype.Component; +import org.apache.cloudstack.quota.vo.QuotaUsageVO; + +import com.cloud.utils.Pair; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.TransactionLegacy; + +@Component +@Local(value = { QuotaUsageDao.class }) +public class QuotaUsageDaoImpl extends GenericDaoBase implements QuotaUsageDao { + + @Override + public Pair, Integer> searchAndCountAllRecords(SearchCriteria sc, Filter filter) { + return listAndCountIncludingRemovedBy(sc, filter); + } + + @Override + public void saveQuotaUsage(List records) { + for (QuotaUsageVO usageRecord : records) { + persist(usageRecord); + } + } + + @Override + public BigDecimal findTotalQuotaUsage(final Long accountId, final Long domainId, final Integer usageType, final Date startDate, final Date endDate) { + List quotaUsage = findQuotaUsage(accountId, domainId, null, startDate, endDate); + BigDecimal total = new BigDecimal(0); + for (final QuotaUsageVO quotaRecord : quotaUsage) { + total = total.add(quotaRecord.getQuotaUsed()); + } + return total; + } + + @SuppressWarnings("deprecation") + @Override + public List findQuotaUsage(final Long accountId, final Long domainId, final Integer usageType, final Date startDate, final Date endDate) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); + List quotaUsageRecords = null; + try { + // TODO instead of max value query with reasonable number and + // iterate + SearchCriteria sc = createSearchCriteria(); + if (accountId != null) { + sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); + } + /* + * if (isDomainAdmin) { SearchCriteria sdc = + * _domainDao.createSearchCriteria(); sdc.addOr("path", + * SearchCriteria.Op.LIKE, + * _domainDao.findById(caller.getDomainId()).getPath() + "%"); + * List domains = _domainDao.search(sdc, null); List + * domainIds = new ArrayList(); for (DomainVO domain : + * domains) domainIds.add(domain.getId()); sc.addAnd("domainId", + * SearchCriteria.Op.IN, domainIds.toArray()); + * s_logger.debug("Account ID=" + accountId); } + */ + if (domainId != null) { + sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); + } + if (usageType != null) { + sc.addAnd("usageType", SearchCriteria.Op.EQ, usageType); + } + if ((startDate != null) && (endDate != null) && startDate.before(endDate)) { + sc.addAnd("startDate", SearchCriteria.Op.BETWEEN, startDate, endDate); + sc.addAnd("endDate", SearchCriteria.Op.BETWEEN, startDate, endDate); + } else { + return new ArrayList(); + } + quotaUsageRecords = listBy(sc); + } finally { + txn.close(); + } + + TransactionLegacy.open(opendb).close(); + return quotaUsageRecords; + } + +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/ServiceOfferingDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/ServiceOfferingDao.java new file mode 100644 index 000000000000..5d340e384f18 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/ServiceOfferingDao.java @@ -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 org.apache.cloudstack.quota.vo.ServiceOfferingVO; + +import com.cloud.utils.db.GenericDao; + +public interface ServiceOfferingDao extends GenericDao { + + ServiceOfferingVO findServiceOffering(Long vmId, long serviceOfferingId); + +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/ServiceOfferingDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/ServiceOfferingDaoImpl.java new file mode 100644 index 000000000000..82d4af6b6e81 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/ServiceOfferingDaoImpl.java @@ -0,0 +1,85 @@ +// 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.TransactionLegacy; +import com.cloud.utils.exception.CloudRuntimeException; + +@Component +@Local(value = { ServiceOfferingDao.class }) +@DB() +public class ServiceOfferingDaoImpl extends GenericDaoBase implements ServiceOfferingDao { + protected static final Logger s_logger = Logger.getLogger(ServiceOfferingDaoImpl.class); + + @Inject + UserVmDetailsDao userVmDetailsDao; + + @Override + public ServiceOfferingVO findServiceOffering(final Long vmId, final long serviceOfferingId) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.CLOUD_DB); + ServiceOfferingVO result; + try { + result = findById(vmId, serviceOfferingId); + } finally { + txn.close(); + } + TransactionLegacy.open(opendb).close(); + return result; + } + + public ServiceOfferingVO findById(Long vmId, long serviceOfferingId) { + ServiceOfferingVO offering = super.findById(serviceOfferingId); + if (offering.isDynamic()) { + offering.setDynamicFlag(true); + if (vmId == null) { + throw new CloudRuntimeException("missing argument vmId"); + } + Map dynamicOffering = userVmDetailsDao.listDetailsKeyPairs(vmId); + return getcomputeOffering(offering, dynamicOffering); + } + return offering; + } + + public ServiceOfferingVO getcomputeOffering(ServiceOfferingVO serviceOffering, Map customParameters) { + 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; + } + +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/UserVmDetailsDao.java b/framework/quota/src/org/apache/cloudstack/quota/dao/UserVmDetailsDao.java new file mode 100644 index 000000000000..f14ecf48dfd2 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/UserVmDetailsDao.java @@ -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. +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 { + + Map listDetailsKeyPairs(long resourceId); + + +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/dao/UserVmDetailsDaoImpl.java b/framework/quota/src/org/apache/cloudstack/quota/dao/UserVmDetailsDaoImpl.java new file mode 100644 index 000000000000..7cc42e724355 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/dao/UserVmDetailsDaoImpl.java @@ -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.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 implements UserVmDetailsDao { + private SearchBuilder 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); + // FIXME SnapshotDetailsVO doesn't have a display field + if (_allAttributes.containsKey("display")) { + AllFieldsSearch.and("display", AllFieldsSearch.entity().isDisplay(), SearchCriteria.Op.EQ); + } + AllFieldsSearch.done(); + } + + @Override + public Map listDetailsKeyPairs(long resourceId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("resourceId", resourceId); + + List results = search(sc, null); + Map details = new HashMap(results.size()); + for (UserVmDetailVO result : results) { + details.put(result.getName(), result.getValue()); + } + return details; + } + +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaAccountVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaAccountVO.java new file mode 100644 index 000000000000..eee790d5c1bf --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaAccountVO.java @@ -0,0 +1,142 @@ +//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 = null; + + @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; + } + + public void setQuotaAlertDate(Date quotaAlertDate) { + this.quotaAlertDate = quotaAlertDate; + } + + public Date getQuotaBalanceDate() { + return quotaBalanceDate; + } + + public void setQuotaBalanceDate(Date quotaBalanceDate) { + this.quotaBalanceDate = quotaBalanceDate; + } + + public Date getLastStatementDate() { + return lastStatementDate; + } + + public void setLastStatementDate(Date lastStatementDate) { + this.lastStatementDate = lastStatementDate; + } + +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaBalanceVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaBalanceVO.java new file mode 100644 index 000000000000..d46b949f8267 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaBalanceVO.java @@ -0,0 +1,127 @@ +//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() { + super(); + } + + public QuotaBalanceVO(QuotaCreditsVO credit) { + super(); + this.accountId = credit.getAccountId(); + this.domainId = credit.getDomainId(); + this.creditBalance = credit.getCredit(); + this.updatedOn = credit.getUpdatedOn(); + this.creditsId = credit.getId(); + } + + public QuotaBalanceVO(Long accountId, Long domainId, BigDecimal creditBalance, Date updatedOn) { + super(); + this.accountId = accountId; + this.domainId = domainId; + this.creditBalance = creditBalance; + this.creditsId=0L; + this.updatedOn = updatedOn; + } + + @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; + } + + public void setUpdatedOn(Date updatedOn) { + this.updatedOn = updatedOn; + } +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaCreditsVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaCreditsVO.java new file mode 100644 index 000000000000..55205bd2e418 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaCreditsVO.java @@ -0,0 +1,117 @@ +//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; + } + + public void setUpdatedOn(Date updatedOn) { + this.updatedOn = updatedOn; + } + + 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() { + // TODO Auto-generated method stub + return this.id; + } +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaEmailTemplatesVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaEmailTemplatesVO.java new file mode 100644 index 000000000000..54013fc96ebd --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaEmailTemplatesVO.java @@ -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; + } + + public void setLastUpdated(Date lastUpdated) { + this.lastUpdated = lastUpdated; + } + + public String getLocale() { + return locale; + } + + public void setLocale(String locale) { + this.locale = locale; + } +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaTariffVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaTariffVO.java new file mode 100644 index 000000000000..38a26b7c7092 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaTariffVO.java @@ -0,0 +1,162 @@ +//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, 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; + this.updatedBy = updatedBy; + } + + + public void setId(Long id) { + this.id = id; + } + + public Date getEffectiveOn() { + return effectiveOn; + } + + public void setEffectiveOn(Date effectiveOn) { + this.effectiveOn = effectiveOn; + } + + public Date getUpdatedOn() { + return updatedOn; + } + + public void setUpdatedOn(Date updatedOn) { + this.updatedOn = updatedOn; + } + + 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); + } + + @Override + public long getId() { + return this.id; + } +} \ No newline at end of file diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaUsageVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaUsageVO.java new file mode 100644 index 000000000000..a82b309aaa58 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/QuotaUsageVO.java @@ -0,0 +1,172 @@ +//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; + this.endDate = endDate; + } + + 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 = toclone.startDate; + this.endDate = toclone.endDate; + } + + 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() { + // TODO Auto-generated method stub + 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; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public Date getEndDate() { + return endDate; + } + + public void setEndDate(Date endDate) { + this.endDate = endDate; + } + + public void setId(Long id) { + this.id = id; + } + +} diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java new file mode 100644 index 000000000000..6415f24fa670 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/ServiceOfferingVO.java @@ -0,0 +1,337 @@ +//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 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 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 details) { + this.details = details; + } + + @Override + public boolean isDynamic() { + return cpu == null || speed == null || ramSize == null || isDynamic; + } + + public void setDynamicFlag(boolean isdynamic) { + isDynamic = isdynamic; + } +} + diff --git a/framework/quota/src/org/apache/cloudstack/quota/vo/UserVmDetailVO.java b/framework/quota/src/org/apache/cloudstack/quota/vo/UserVmDetailVO.java new file mode 100644 index 000000000000..daaed90d3224 --- /dev/null +++ b/framework/quota/src/org/apache/cloudstack/quota/vo/UserVmDetailVO.java @@ -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.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; + } + +} + diff --git a/plugins/database/quota/pom.xml b/plugins/database/quota/pom.xml new file mode 100644 index 000000000000..ae2c85317ddf --- /dev/null +++ b/plugins/database/quota/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + cloud-plugin-database-quota + Apache CloudStack Plugin - Quota Service + + org.apache.cloudstack + cloudstack-plugins + 4.5.2 + ../../pom.xml + + + + org.apache.cloudstack + cloud-api + ${project.version} + + + org.apache.cloudstack + cloud-engine-schema + ${project.version} + + + org.apache.cloudstack + cloud-utils + ${project.version} + + + org.apache.cloudstack + cloud-framework-quota + ${project.version} + + + mysql + mysql-connector-java + provided + + + org.apache.commons + commons-lang3 + ${cs.commons-lang3.version} + + + joda-time + joda-time + ${cs.joda-time.version} + + + diff --git a/plugins/database/quota/resources/META-INF/cloudstack/quota/module.properties b/plugins/database/quota/resources/META-INF/cloudstack/quota/module.properties new file mode 100644 index 000000000000..7332f1518283 --- /dev/null +++ b/plugins/database/quota/resources/META-INF/cloudstack/quota/module.properties @@ -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 diff --git a/plugins/database/quota/resources/META-INF/cloudstack/quota/spring-quota-context.xml b/plugins/database/quota/resources/META-INF/cloudstack/quota/spring-quota-context.xml new file mode 100644 index 000000000000..15bc144e31a7 --- /dev/null +++ b/plugins/database/quota/resources/META-INF/cloudstack/quota/spring-quota-context.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaBalanceCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaBalanceCmd.java new file mode 100644 index 000000000000..ddf6f054a01c --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaBalanceCmd.java @@ -0,0 +1,136 @@ +//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.context.CallContext; +import org.apache.cloudstack.quota.vo.QuotaBalanceVO; +import org.apache.cloudstack.api.response.QuotaStatementItemResponse; + +import com.cloud.user.Account; + +@APICommand(name = "quotaBalance", responseObject = QuotaStatementItemResponse.class, description = "Create a quota balance statement", since = "4.2.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class QuotaBalanceCmd extends BaseCmd { + + public static final Logger s_logger = Logger.getLogger(QuotaBalanceCmd.class.getName()); + + private static final String s_name = "quotabalanceresponse"; + + @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, 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); + } + + public void setEndDate(Date endDate) { + this.endDate = endDate; + } + + public Date getStartDate() { + return startDate; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public QuotaBalanceCmd() { + super(); + } + + @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 quotaUsage = _responseBuilder.getQuotaBalance(this); + + QuotaBalanceResponse response; + if (getEndDate() == null) { + response = _responseBuilder.createQuotaLastBalanceResponse(quotaUsage, startDate); + } else { + response = _responseBuilder.createQuotaBalanceResponse(quotaUsage, startDate, endDate); + } + response.setResponseName(getCommandName()); + setResponseObject(response); + } + +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaCreditsCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaCreditsCmd.java new file mode 100644 index 000000000000..1a7db81fce1a --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaCreditsCmd.java @@ -0,0 +1,143 @@ +//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.2.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.getName()); + + 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 = _accountService.getActiveAccountByName(accountName, domainId).getAccountId(); + if (accountId == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "The account does not exists or has been removed/disabled"); + } + if (value == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Please send a valid non-empty quota value"); + } + if (getQuotaEnforce() != null) { + _quotaService.setLockAccount(accountId, getQuotaEnforce()); + } + if (getMinBalance() != null) { + _quotaService.setMinBalance(accountId, getMinBalance()); + } + else { + _quotaService.setMinBalance(accountId, 0.2 * value); + } + + final QuotaCreditsResponse response = _responseBuilder.addQuotaCredits(accountId, domainId, value, CallContext.current().getCallingUserId()); + response.setResponseName(getCommandName()); + response.setObjectName("quotacredits"); + setResponseObject(response); + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaEmailTemplateListCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaEmailTemplateListCmd.java new file mode 100644 index 000000000000..e2985febe21f --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaEmailTemplateListCmd.java @@ -0,0 +1,56 @@ +//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.getName()); + 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; + } + + @Override + public void execute() { + final ListResponse response = new ListResponse(); + response.setResponses(_quotaResponseBuilder.listQuotaEmailTemplates(this)); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return s_name; + } +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaEmailTemplateUpdateCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaEmailTemplateUpdateCmd.java new file mode 100644 index 000000000000..df08d91698b8 --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaEmailTemplateUpdateCmd.java @@ -0,0 +1,111 @@ +//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.2.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class QuotaEmailTemplateUpdateCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(QuotaEmailTemplateUpdateCmd.class.getName()); + 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; + } + + private 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; + } + +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaStatementCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaStatementCmd.java new file mode 100644 index 000000000000..5d38d3dfff7b --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaStatementCmd.java @@ -0,0 +1,143 @@ +//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.2.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class QuotaStatementCmd extends BaseCmd { + + public static final Logger s_logger = Logger.getLogger(QuotaStatementCmd.class.getName()); + + 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() : endDate); + } + + public void setEndDate(Date endDate) { + this.endDate = endDate; + } + + public Date getStartDate() { + return startDate; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public QuotaStatementCmd() { + super(); + } + + @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 quotaUsage = _responseBuilder.getQuotaUsage(this); + + QuotaStatementResponse response = _responseBuilder.createQuotaStatementResponse(quotaUsage); + + response.setResponseName(getCommandName()); + setResponseObject(response); + } + +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaTariffListCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaTariffListCmd.java new file mode 100644 index 000000000000..121873f8a007 --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaTariffListCmd.java @@ -0,0 +1,93 @@ +//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.getName()); + 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 result = _responseBuilder.listQuotaTariffPlans(this); + + final List responses = new ArrayList(); + for (final QuotaTariffVO resource : result) { + s_logger.info("Result desc=" + resource.getDescription() + " date=" + resource.getEffectiveOn() + " val=" + resource.getCurrencyValue()); + responses.add(_responseBuilder.createQuotaTariffResponse(resource)); + } + + final ListResponse response = new ListResponse(); + 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; + } + + public Integer getUsageType() { + return usageType; + } + + public void setUsageType(Integer usageType) { + this.usageType = usageType; + } + +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaTariffUpdateCmd.java b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaTariffUpdateCmd.java new file mode 100644 index 000000000000..0af3ab877559 --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/command/QuotaTariffUpdateCmd.java @@ -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.getName()); + 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; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + 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; + } + +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaBalanceResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaBalanceResponse.java new file mode 100644 index 000000000000..2e0c23f21eca --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaBalanceResponse.java @@ -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 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(); + } + + 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 getCredits() { + return credits; + } + + public void setCredits(List credits) { + this.credits = credits; + } + + public void addCredits(QuotaBalanceVO credit) { + QuotaCreditsResponse cr = new QuotaCreditsResponse(); + cr.setCredits(credit.getCreditBalance()); + cr.setUpdatedOn(credit.getUpdatedOn()); + credits.add(0, cr); + } + + public Date getStartDate() { + return startDate; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public Date getEndDate() { + return endDate; + } + + public void setEndDate(Date endDate) { + this.endDate = endDate; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaCreditsResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaCreditsResponse.java new file mode 100644 index 000000000000..2c16cf44b7cf --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaCreditsResponse.java @@ -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; + } +} \ No newline at end of file diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaEmailTemplateResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaEmailTemplateResponse.java new file mode 100644 index 000000000000..c4a2b7c3a605 --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaEmailTemplateResponse.java @@ -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; + } +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java new file mode 100644 index 000000000000..e9bb61105907 --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilder.java @@ -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.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 listQuotaTariffPlans(QuotaTariffListCmd cmd); + + QuotaTariffResponse createQuotaTariffResponse(QuotaTariffVO configuration); + + QuotaStatementResponse createQuotaStatementResponse(List quotaUsage); + + QuotaBalanceResponse createQuotaBalanceResponse(List quotaUsage, Date startDate, Date endDate); + + QuotaBalanceResponse createQuotaLastBalanceResponse(List quotaBalance, Date startDate); + + QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy, Date despositedOn); + + public List getQuotaUsage(QuotaStatementCmd cmd); + + List getQuotaBalance(QuotaBalanceCmd cmd); + + QuotaCreditsResponse addQuotaCredits(Long accountId, Long domainId, Double amount, Long updatedBy); + + List listQuotaEmailTemplates(QuotaEmailTemplateListCmd cmd); + + boolean updateQuotaEmailTemplate(QuotaEmailTemplateUpdateCmd cmd); + + Date startOfNextDay(Date dt); + + Date startOfNextDay(); +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java new file mode 100644 index 000000000000..de082eeaeb49 --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java @@ -0,0 +1,412 @@ +//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.User; +import com.cloud.user.dao.AccountDao; +import com.cloud.user.dao.UserDao; +import com.cloud.utils.db.TransactionLegacy; + +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.constant.QuotaConfig; +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.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.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +@Component +@Local(value = QuotaResponseBuilderImpl.class) +public class QuotaResponseBuilderImpl implements QuotaResponseBuilder { + private static final Logger s_logger = Logger.getLogger(QuotaResponseBuilderImpl.class.getName()); + + @Inject + private QuotaTariffDao _quotaTariffDao; + @Inject + private QuotaBalanceDao _quotaBalanceDao; + @Inject + private QuotaCreditsDao _quotaCreditsDao; + @Inject + private QuotaEmailTemplatesDao _quotaEmailTemplateDao; + + @Inject + private UserDao _userDao; + @Inject + private QuotaService _quotaService; + @Inject + AccountDao _accountDao; + @Inject + private RegionManager _regionMgr; + + @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 QuotaBalanceResponse createQuotaBalanceResponse(List quotaBalance, Date startDate, Date endDate) { + if (quotaBalance.size() == 0) { + new InvalidParameterValueException("The request period does not contain balance entries."); + } + Collections.sort(quotaBalance, new Comparator() { + public int compare(QuotaBalanceVO o1, QuotaBalanceVO o2) { + return o2.getUpdatedOn().compareTo(o1.getUpdatedOn()); // desc + } + }); + + QuotaBalanceResponse resp = new QuotaBalanceResponse(); + BigDecimal lastCredits = new BigDecimal(0); + boolean consecutive = true; + for (Iterator it = quotaBalance.iterator(); it.hasNext();) { + QuotaBalanceVO entry = it.next(); + s_logger.info("createQuotaBalanceResponse: Date=" + entry.getUpdatedOn().toGMTString() + " balance=" + entry.getCreditBalance() + " credit=" + entry.getCreditsId()); + if (entry.getCreditsId() > 0) { + if (consecutive) { + lastCredits = lastCredits.add(entry.getCreditBalance()); + } + resp.addCredits(entry); + it.remove(); + } else { + consecutive = false; + } + } + + if (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(startDate); + resp.setStartQuota(startItem.getCreditBalance()); + resp.setEndDate(endDate); + resp.setEndQuota(endItem.getCreditBalance().add(lastCredits)); + } else { + 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 quotaUsage) { + if (quotaUsage == null || quotaUsage.size() == 0) { + throw new InvalidParameterValueException("There is no usage data found for period mentioned."); + } + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB).close(); + QuotaStatementResponse statement = new QuotaStatementResponse(); + + HashMap quotaTariffMap = new HashMap(); + List result = _quotaTariffDao.listAll(); + + for (QuotaTariffVO quotaTariff : result) { + quotaTariffMap.put(quotaTariff.getUsageType(), quotaTariff); + // add dummy record for each usage type + QuotaUsageVO dummy = new QuotaUsageVO(quotaUsage.get(0)); + dummy.setUsageType(quotaTariff.getUsageType()); + dummy.setQuotaUsed(new BigDecimal(0)); + quotaUsage.add(dummy); + } + + Collections.sort(quotaUsage, new Comparator() { + public int compare(QuotaUsageVO o1, QuotaUsageVO o2) { + if (o1.getUsageType() == o2.getUsageType()) + return 0; + return o1.getUsageType() < o2.getUsageType() ? -1 : 1; + } + }); + + List items = new ArrayList(); + 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); + //s_logger.info("createQuotaStatementResponse record count=" + quotaUsage.size()); + for (final QuotaUsageVO quotaRecord : quotaUsage) { + //s_logger.info("createQuotaStatementResponse Type=" + quotaRecord.getUsageType() + " usage=" + usage + " name" + quotaRecord.getUsageItemId()); + if (type != quotaRecord.getUsageType()) { + if (type != -1) { + lineitem = new QuotaStatementItemResponse(); + lineitem.setUsageType(type); + lineitem.setQuotaUsed(usage); + lineitem.setAccountId(prev.getAccountId()); + lineitem.setDomainId(prev.getDomainId()); + lineitem.setStartDate(prev.getStartDate()); + lineitem.setEndDate(prev.getEndDate()); + lineitem.setUsageUnit(quotaTariffMap.get(type).getUsageUnit()); + lineitem.setUsageName(quotaTariffMap.get(type).getUsageName()); + lineitem.setObjectName("quotausage"); + items.add(lineitem); + totalUsage = totalUsage.add(usage); + usage = new BigDecimal(0); + } + type = quotaRecord.getUsageType(); + } + prev = quotaRecord; + usage = usage.add(quotaRecord.getQuotaUsed()); + } + TransactionLegacy.open(opendb).close(); + + statement.setLineItem(items); + statement.setTotalQuota(totalUsage); + statement.setCurrency(QuotaConfig.QuotaCurrencySymbol.value()); + statement.setObjectName("statement"); + return statement; + } + + @Override + public List listQuotaTariffPlans(final QuotaTariffListCmd cmd) { + List result = new ArrayList(); + Date effectiveDate = cmd.getEffectiveDate() == null ? new Date() : cmd.getEffectiveDate(); + Date adjustedEffectiveDate = _quotaService.computeAdjustedTime(effectiveDate); + s_logger.info("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); + } + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.USAGE_DB).close(); + QuotaTariffVO result = null; + try { + result = new QuotaTariffVO(); + result.setUsageType(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()); + + 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); + } catch (Exception pokemon) { + s_logger.error("Error in update quota tariff plan: " + pokemon); + } finally { + TransactionLegacy.open(opendb).close(); + } + 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) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + QuotaCreditsVO result = null; + TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB); + try { + QuotaCreditsVO credits = new QuotaCreditsVO(accountId, domainId, new BigDecimal(amount), updatedBy); + s_logger.info("addQuotaCredits: Depositing " + amount + " on adjusted date " + despositedOn); + credits.setUpdatedOn(despositedOn); + result = _quotaCreditsDao.saveCredits(credits); + } finally { + txn.close(); + } + TransactionLegacy.open(TransactionLegacy.CLOUD_DB).close(); + final AccountVO account = _accountDao.findById(accountId); + final boolean lockAccountEnforcement = QuotaConfig.QuotaEnableEnforcement.value().equalsIgnoreCase("true"); + final BigDecimal currentAccountBalance = _quotaBalanceDao.lastQuotaBalance(accountId, domainId, startOfNextDay(despositedOn)); + if (lockAccountEnforcement && (currentAccountBalance.compareTo(new BigDecimal(0)) >= 0)) { + if (account.getState() == Account.State.locked) { + try { + _regionMgr.enableAccount(account.getAccountName(), domainId, accountId); + //_quotaMgr.sendQuotaAlert(account, currentAccountBalance, QuotaConfig.QuotaEmailTemplateTypes.QUOTA_UNLOCK_ACCOUNT); + } catch (Exception e) { + s_logger.error(String.format("Unable to unlock account %s after getting enough quota credits", account.getAccountName())); + } + } + } + + String creditor = String.valueOf(Account.ACCOUNT_ID_SYSTEM); + User creditorUser = _userDao.getUser(updatedBy); + if (creditorUser != null) { + creditor = creditorUser.getUsername(); + } + TransactionLegacy.open(opendb).close(); + 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 listQuotaEmailTemplates(QuotaEmailTemplateListCmd cmd) { + final String templateName = cmd.getTemplateName(); + List templates = _quotaEmailTemplateDao.listAllQuotaEmailTemplates(templateName); + final List responses = new ArrayList(); + 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 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 quotaBalance, Date startDate) { + if (quotaBalance.size() == 0) { + 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 (Iterator it = quotaBalance.iterator(); it.hasNext();) { + QuotaBalanceVO entry = it.next(); + s_logger.info("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 getQuotaUsage(QuotaStatementCmd cmd) { + return _quotaService.getQuotaUsage(cmd.getAccountId(), cmd.getAccountName(), cmd.getDomainId(), cmd.getUsageType(), cmd.getStartDate(), cmd.getEndDate()); + } + + @Override + public List 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; + } + +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementItemResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementItemResponse.java new file mode 100644 index 000000000000..e1b0f171e4bc --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementItemResponse.java @@ -0,0 +1,143 @@ +//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; + +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; + + @SerializedName("startdate") + @Param(description = "start date") + private Date startDate = null; + + @SerializedName("enddate") + @Param(description = "end date") + private Date endDate = null; + + public QuotaStatementItemResponse() { + 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 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); + } + + public Date getStartDate() { + return startDate; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public Date getEndDate() { + return endDate; + } + + public void setEndDate(Date endDate) { + this.endDate = endDate; + } + +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementResponse.java new file mode 100644 index 000000000000..7ea5e6cc7ce0 --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaStatementResponse.java @@ -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 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 getLineItem() { + return lineItem; + } + + public void setLineItem(List lineItem) { + this.lineItem = lineItem; + } + + public Date getStartDate() { + return startDate; + } + + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + public Date getEndDate() { + return endDate; + } + + public void setEndDate(Date endDate) { + this.endDate = endDate; + } + + + 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; + } +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaTariffResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaTariffResponse.java new file mode 100644 index 000000000000..48697fd2a822 --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaTariffResponse.java @@ -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; + } +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaTypeResponse.java b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaTypeResponse.java new file mode 100644 index 000000000000..989fba54e7f2 --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/api/response/QuotaTypeResponse.java @@ -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); + } + +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaService.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaService.java new file mode 100644 index 000000000000..8ee39b878aff --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaService.java @@ -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 getQuotaUsage(Long accountId, String accountName, Long domainId, Integer usageType, Date startDate, Date endDate); + + List 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); + +} diff --git a/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java new file mode 100644 index 000000000000..e13512a9b3ab --- /dev/null +++ b/plugins/database/quota/src/org/apache/cloudstack/quota/QuotaServiceImpl.java @@ -0,0 +1,296 @@ +//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 com.cloud.utils.db.TransactionLegacy; + +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.QuotaTariffListCmd; +import org.apache.cloudstack.api.command.QuotaTariffUpdateCmd; +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.getName()); + + @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; + + 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 QuotaServiceImpl() { + super(); + } + + @Override + public boolean configure(String name, Map 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; + } + s_logger.info("Usage timezone = " + _usageTimezone + " AggregationDuration=" + _aggregationDuration); + return true; + } + + @Override + public List> getCommands() { + final List> cmdList = new ArrayList>(); + if (!isQuotaServiceEnabled()) { + return cmdList; + } + cmdList.add(QuotaStatementCmd.class); + cmdList.add(QuotaBalanceCmd.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, QuotaSmtpHost, QuotaSmtpPort, QuotaSmtpTimeout, QuotaSmtpUser, + QuotaSmtpPassword, QuotaSmtpAuthType, QuotaSmtpSender }; + } + + public Boolean isQuotaServiceEnabled() { + return QuotaPluginEnabled.value(); + } + + @Override + public List findQuotaBalanceVO(Long accountId, String accountName, Long domainId, Date startDate, Date endDate) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.CLOUD_DB).close(); + + Account userAccount = null; + Account caller = CallContext.current().getCallingAccount(); + + // if accountId is not specified, use accountName and domainId + if ((accountId == null) && (accountName != null) && (domainId != null)) { + if (_domainDao.isChildDomain(caller.getDomainId(), domainId)) { + Filter filter = new Filter(AccountVO.class, "id", Boolean.FALSE, null, null); + List accounts = _accountDao.listAccounts(accountName, domainId, filter); + if (accounts.size() > 0) { + 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"); + } + } + TransactionLegacy.open(opendb).close(); + + 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)); + s_logger.debug("getQuotaBalance1: Getting quota balance records for account: " + accountId + ", domainId: " + domainId + ", on or before " + adjustedStartDate); + List qbrecords = _quotaBalanceDao.lastQuotaBalanceVO(accountId, domainId, adjustedStartDate); + s_logger.info("Found records size=" + qbrecords.size()); + if (qbrecords.size() == 0) { + throw new InvalidParameterValueException("Incorrect Date there are no quota records before this date " + adjustedStartDate); + } 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); + s_logger.debug("getQuotaBalance2: Getting quota balance records for account: " + accountId + ", domainId: " + domainId + ", between " + adjustedStartDate + " and " + adjustedEndDate); + List qbrecords = _quotaBalanceDao.findQuotaBalance(accountId, domainId, adjustedStartDate, adjustedEndDate); + s_logger.info("getQuotaBalance3: Found records size=" + qbrecords.size()); + if (qbrecords.size() == 0) { + throw new InvalidParameterValueException("Incorrect Date range there are no quota records between these dates start date " + adjustedStartDate + " and end date:" + endDate); + } else { + return qbrecords; + } + } else { + throw new InvalidParameterValueException("Incorrect Date Range. Start date: " + startDate + " is after end date:" + endDate); + } + } + + } + + @Override + public List getQuotaUsage(Long accountId, String accountName, Long domainId, Integer usageType, Date startDate, Date endDate) { + final short opendb = TransactionLegacy.currentTxn().getDatabaseId(); + TransactionLegacy.open(TransactionLegacy.CLOUD_DB).close(); + Account userAccount = null; + Account caller = CallContext.current().getCallingAccount(); + + // if accountId is not specified, use accountName and domainId + if ((accountId == null) && (accountName != null) && (domainId != null)) { + if (_domainDao.isChildDomain(caller.getDomainId(), domainId)) { + Filter filter = new Filter(AccountVO.class, "id", Boolean.FALSE, null, null); + List accounts = _accountDao.listAccounts(accountName, domainId, filter); + if (accounts.size() > 0) { + 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"); + } + } + TransactionLegacy.open(opendb).close(); + + 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); + 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.findById(accountId); + if (acc == null) { + acc = new QuotaAccountVO(accountId); + acc.setQuotaEnforce(state ? 1 : 0); + _quotaAcc.persist(acc); + } else { + acc.setQuotaEnforce(state ? 1 : 0); + _quotaAcc.update(accountId, acc); + } + } + + @Override + public void setMinBalance(Long accountId, Double balance) { + QuotaAccountVO acc = _quotaAcc.findById(accountId); + if (acc == null) { + acc = new QuotaAccountVO(accountId); + acc.setQuotaMinBalance(new BigDecimal(balance)); + _quotaAcc.persist(acc); + } else { + acc.setQuotaMinBalance(new BigDecimal(balance)); + _quotaAcc.update(accountId, acc); + } + } + +} diff --git a/plugins/pom.xml b/plugins/pom.xml index 6c826600c480..0c7c2fcda9ad 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -90,6 +90,7 @@ network-elements/internal-loadbalancer network-elements/vxlan network-elements/globodns + database/quota diff --git a/pom.xml b/pom.xml index 2a508b50c68d..2dfb9eb14403 100644 --- a/pom.xml +++ b/pom.xml @@ -83,6 +83,7 @@ 1.3.22 2.6 1.4 + 3.4 0.9.8 0.10 build/replace.properties @@ -96,6 +97,7 @@ 2.5.3 2.9.1 2.6.1 + 2.8.1 diff --git a/server/src/com/cloud/api/dispatch/ParamProcessWorker.java b/server/src/com/cloud/api/dispatch/ParamProcessWorker.java index b990d4aedf4c..f9c9e0f079bd 100644 --- a/server/src/com/cloud/api/dispatch/ParamProcessWorker.java +++ b/server/src/com/cloud/api/dispatch/ParamProcessWorker.java @@ -291,6 +291,14 @@ private void setFieldValue(final Field field, final BaseCmd cmdObj, final Object 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 diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 20fcbcb3bd5f..a7d4268bef65 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -2179,8 +2179,7 @@ private UserAccount getUserAccount(String username, String password, Long domain 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())) diff --git a/setup/db/db/schema-451to452.sql b/setup/db/db/schema-451to452.sql index 5c89008a83ef..90e55271f23e 100644 --- a/setup/db/db/schema-451to452.sql +++ b/setup/db/db/schema-451to452.sql @@ -19,7 +19,9 @@ -- Schema upgrade from 4.5.1 to 4.5.2; --; -DELETE FROM `cloud`.`configuration` WHERE name like 'saml%'; +-- SAML + +DELETE FROM `cloud`.`configuration` WHERE name like 'saml%' and component='management-server'; ALTER TABLE `cloud`.`user` ADD COLUMN `external_entity` text DEFAULT NULL COMMENT "reference to external federation entity"; @@ -33,3 +35,115 @@ CREATE TABLE `cloud`.`saml_token` ( PRIMARY KEY (`id`), CONSTRAINT `fk_saml_token__domain_id` FOREIGN KEY(`domain_id`) REFERENCES `domain`(`id`) ON DELETE CASCADE ) 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} is locked now', 'Your account ${accountName} in the domain ${domainName} has exhausted allocated quota and has been locked now, please contact the administrator.'), + ('QUOTA_UNLOCK_ACCOUNT', 'Quota credits added, account ${accountName} is unlocked now', 'Your account ${accountName} in the domain ${domainName} has enough quota credits now with the current balance of ${quotaBalance}. Your account has been unlocked now.'), + ('QUOTA_STATEMENT', 'Quota Statement for your account ${accountName}', 'Monthly quota statement of your account ${accountName} in the domain ${domainName}:
Balance = ${quotaBalance}
Total Usage = ${quotaUsage}.'); +UNLOCK TABLES; + diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index 4fac7ee3790c..e8a930e8dfee 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -118,6 +118,8 @@ 'listIdps': 'Authentication', 'authorizeSamlSso': 'Authentication', 'listSamlAuthorization': 'Authentication', + 'quota': 'Quota', + 'emailTemplate': 'Quota', 'Capacity': 'System Capacity', 'NetworkDevice': 'Network Device', 'ExternalLoadBalancer': 'Ext Load Balancer', diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp index 1f8aa8f875dd..df03367ba1c8 100644 --- a/ui/dictionary.jsp +++ b/ui/dictionary.jsp @@ -982,6 +982,13 @@ dictionary = { 'label.purpose': '', 'label.Pxe.server.type': '', 'label.quickview': '', +'label.usage.type': '', +'label.usage.unit': '', +'label.quota.value': '', +'label.quota.description': '', +'label.quota.configuration': '', +'label.quota.configure': '', +'label.quota.remove': '', 'label.rbd': '', 'label.rbd.monitor': '', 'label.rbd.pool': '', diff --git a/ui/plugins/plugins.js b/ui/plugins/plugins.js index 386ec062bb0d..0a6d2e74b4e1 100644 --- a/ui/plugins/plugins.js +++ b/ui/plugins/plugins.js @@ -16,6 +16,7 @@ // under the License. (function($, cloudStack) { cloudStack.plugins = [ - // 'testPlugin' + //'quota', + //'testPlugin' ]; }(jQuery, cloudStack)); diff --git a/ui/plugins/quota/config.js b/ui/plugins/quota/config.js new file mode 100644 index 000000000000..186d50778400 --- /dev/null +++ b/ui/plugins/quota/config.js @@ -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. +(function (cloudStack) { + cloudStack.plugins.quota.config = { + title: 'Quota', + desc: 'CloudStack Quota', + externalLink: 'http://www.cloudstack.org/', + authorName: 'Apache CloudStack', + authorEmail: 'dev@cloudstack.apache.org' + }; +}(cloudStack)); diff --git a/ui/plugins/quota/icon.png b/ui/plugins/quota/icon.png new file mode 100644 index 000000000000..e178ebc32dd9 Binary files /dev/null and b/ui/plugins/quota/icon.png differ diff --git a/ui/plugins/quota/quota.css b/ui/plugins/quota/quota.css new file mode 100644 index 000000000000..e9c0d8ff358c --- /dev/null +++ b/ui/plugins/quota/quota.css @@ -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. +*/ + +.quota-tariff-edit { + float: right; +} + +.quota-bold { + font-size: 12px; + font-weight: bold; + color: #6D6D6D; +} + +.quota-text { + font-size: 11px; + color: #282828; +} + +.quota-element { + margin: 5px; + margin-left: 13px; +} + +.quota-input { + background: #F6F6F6; + border: 1px solid #AFAFAF; + border-radius: 4px; +} + +.quota-button { + border:1px solid #0077c7; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; + font-size:11px; + padding: 8px; + margin-top: 12px; + text-shadow: -1px -1px 0 rgba(0,0,0,0.3);font-weight:bold; color: #FFFFFF; + background-color: #0099FF; background-image: -webkit-gradient(linear, left top, left bottom, from(#0099FF), to(#004FF7)); + background-image: -webkit-linear-gradient(top, #0099FF, #004FF7); + background-image: -moz-linear-gradient(top, #0099FF, #004FF7); + background-image: -ms-linear-gradient(top, #0099FF, #004FF7); + background-image: -o-linear-gradient(top, #0099FF, #004FF7); + background-image: linear-gradient(to bottom, #0099FF, #004FF7);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#0099FF, endColorstr=#004FF7); +} + +.quota-button:hover { + border:1px solid #005c99; + background-color: #0039B3; background-image: -webkit-gradient(linear, left top, left bottom, from(#0039B3), to(#004FF7)); + background-image: -webkit-linear-gradient(top, #0039B3, #004FF7); + background-image: -moz-linear-gradient(top, #0039B3, #004FF7); + background-image: -ms-linear-gradient(top, #0039B3, #004FF7); + background-image: -o-linear-gradient(top, #0039B3, #004FF7); + background-image: linear-gradient(to bottom, #0039B3, #004FF7);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#0039B3, endColorstr=#004FF7); +} diff --git a/ui/plugins/quota/quota.js b/ui/plugins/quota/quota.js new file mode 100644 index 000000000000..4e94b2c318c9 --- /dev/null +++ b/ui/plugins/quota/quota.js @@ -0,0 +1,726 @@ +// 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. + +var g_quotaCurrency = ''; +(function (cloudStack) { + cloudStack.plugins.quota = function(plugin) { + plugin.ui.addSection({ + id: 'quota', + title: 'Quota', + showOnNavigation: true, + preFilter: function(args) { + return true; + }, + show: function() { + var $quotaView = $('
'); + var $toolbar = $('
'); + var $tabs = $('
    '); + var $tabViews = []; + + var sections = [{'id': 'quota-statement', + 'name': 'Statement', + 'render': function ($node) { + var statementView = $('
    '); + var generatedStatement = $('
    '); + var generatedBalanceStatement = $('
    '); + + var statementForm = $('
    '); + var domainDropdown = $('
    '); + var accountDropdown = $('