From 18ef8ca3b4b21a083c2b1f6f14b9e97dee469925 Mon Sep 17 00:00:00 2001 From: kishan Date: Tue, 1 Nov 2011 17:00:44 +0530 Subject: [PATCH] bug 11173: Added usage for VPN users status 11173: resolved fixed --- .../vpn/RemoteAccessVpnManagerImpl.java | 16 +- server/src/com/cloud/usage/UsageTypes.java | 2 + .../src/com/cloud/usage/UsageVPNUserVO.java | 108 ++++++++++++ .../com/cloud/usage/dao/UsageVPNUserDao.java | 31 ++++ .../cloud/usage/dao/UsageVPNUserDaoImpl.java | 151 ++++++++++++++++ setup/db/create-schema-premium.sql | 16 ++ setup/db/db/schema-2213to30-premium.sql | 14 ++ usage/conf/usage-components.xml.in | 1 + .../src/com/cloud/usage/UsageManagerImpl.java | 49 +++++- .../usage/parser/VPNUserUsageParser.java | 163 ++++++++++++++++++ 10 files changed, 547 insertions(+), 4 deletions(-) create mode 100644 server/src/com/cloud/usage/UsageVPNUserVO.java create mode 100644 server/src/com/cloud/usage/dao/UsageVPNUserDao.java create mode 100644 server/src/com/cloud/usage/dao/UsageVPNUserDaoImpl.java create mode 100644 usage/src/com/cloud/usage/parser/VPNUserUsageParser.java diff --git a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java index 2fee27513d3..3ead349d71c 100755 --- a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java +++ b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java @@ -33,6 +33,9 @@ import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; +import com.cloud.event.EventTypes; +import com.cloud.event.UsageEventVO; +import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.AccountLimitException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.NetworkRuleConflictException; @@ -93,6 +96,7 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag @Inject DomainDao _domainDao; @Inject FirewallRulesDao _rulesDao; @Inject FirewallManager _firewallMgr; + @Inject UsageEventDao _usageEventDao; int _userLimit; int _pskLength; @@ -305,13 +309,15 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag if (userCount >= _userLimit) { throw new AccountLimitException("Cannot add more than " + _userLimit + " remote access vpn users"); } - + VpnUser user = _vpnUsersDao.persist(new VpnUserVO(vpnOwnerId, owner.getDomainId(), username, password)); + UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VPN_USER_ADD, user.getAccountId(), 0, user.getId(), user.getUsername()); + _usageEventDao.persist(usageEvent); txn.commit(); return user; } - @Override + @DB @Override public boolean removeVpnUser(long vpnOwnerId, String username) { Account caller = UserContext.current().getCaller(); @@ -320,9 +326,13 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag throw new InvalidParameterValueException("Could not find vpn user " + username); } _accountMgr.checkAccess(caller, null, user); - + Transaction txn = Transaction.currentTxn(); + txn.start(); user.setState(State.Revoke); _vpnUsersDao.update(user.getId(), user); + UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(), user.getUsername()); + _usageEventDao.persist(usageEvent); + txn.commit(); return true; } diff --git a/server/src/com/cloud/usage/UsageTypes.java b/server/src/com/cloud/usage/UsageTypes.java index 913f5491df0..bbd1bb4e702 100644 --- a/server/src/com/cloud/usage/UsageTypes.java +++ b/server/src/com/cloud/usage/UsageTypes.java @@ -38,6 +38,7 @@ public class UsageTypes { public static final int LOAD_BALANCER_POLICY = 11; public static final int PORT_FORWARDING_RULE = 12; public static final int NETWORK_OFFERING = 13; + public static final int VPN_USERS = 14; public static List listUsageTypes(){ List responseList = new ArrayList(); @@ -54,6 +55,7 @@ public class UsageTypes { responseList.add(new UsageTypeResponse(LOAD_BALANCER_POLICY, "Load Balancer Usage")); responseList.add(new UsageTypeResponse(PORT_FORWARDING_RULE, "Port Forwarding Usage")); responseList.add(new UsageTypeResponse(NETWORK_OFFERING, "Network Offering Usage")); + responseList.add(new UsageTypeResponse(VPN_USERS, "VPN users usage")); return responseList; } } diff --git a/server/src/com/cloud/usage/UsageVPNUserVO.java b/server/src/com/cloud/usage/UsageVPNUserVO.java new file mode 100644 index 00000000000..c60d9951ec4 --- /dev/null +++ b/server/src/com/cloud/usage/UsageVPNUserVO.java @@ -0,0 +1,108 @@ +/** + * * Copyright (C) 2011 Citrix Systems, Inc. All rights reserved +* + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.cloud.usage; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +@Entity +@Table(name="usage_vpn_user") +public class UsageVPNUserVO { + + @Column(name="zone_id") + private long zoneId; + + @Column(name="account_id") + private long accountId; + + @Column(name="domain_id") + private long domainId; + + @Column(name="user_id") + private long userId; + + @Column(name="user_name") + private String username; + + @Column(name="created") + @Temporal(value=TemporalType.TIMESTAMP) + private Date created = null; + + @Column(name="deleted") + @Temporal(value=TemporalType.TIMESTAMP) + private Date deleted = null; + + protected UsageVPNUserVO() { + } + + public UsageVPNUserVO(long zoneId, long accountId, long domainId, long userId, String username, Date created, Date deleted) { + this.zoneId = zoneId; + this.accountId = accountId; + this.domainId = domainId; + this.userId = userId; + this.username = username; + this.created = created; + this.deleted = deleted; + } + + public long getZoneId() { + return zoneId; + } + + public long getAccountId() { + return accountId; + } + + public long getDomainId() { + return domainId; + } + + public Date getCreated() { + return created; + } + + public Date getDeleted() { + return deleted; + } + public void setDeleted(Date deleted) { + this.deleted = deleted; + } + + public long getUserId() { + return userId; + } + + public void setUserId(long userId) { + this.userId = userId; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } +} diff --git a/server/src/com/cloud/usage/dao/UsageVPNUserDao.java b/server/src/com/cloud/usage/dao/UsageVPNUserDao.java new file mode 100644 index 00000000000..8705d555ef0 --- /dev/null +++ b/server/src/com/cloud/usage/dao/UsageVPNUserDao.java @@ -0,0 +1,31 @@ +/** + * * Copyright (C) 2011 Citrix Systems, Inc. All rights reserved +* + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.cloud.usage.dao; + +import java.util.Date; +import java.util.List; + +import com.cloud.usage.UsageVPNUserVO; +import com.cloud.utils.db.GenericDao; + +public interface UsageVPNUserDao extends GenericDao { + public void update(UsageVPNUserVO usage); + public List getUsageRecords(Long accountId, Long domainId, Date startDate, Date endDate, boolean limit, int page); +} diff --git a/server/src/com/cloud/usage/dao/UsageVPNUserDaoImpl.java b/server/src/com/cloud/usage/dao/UsageVPNUserDaoImpl.java new file mode 100644 index 00000000000..bda5650d7ad --- /dev/null +++ b/server/src/com/cloud/usage/dao/UsageVPNUserDaoImpl.java @@ -0,0 +1,151 @@ +/** + * * Copyright (C) 2011 Citrix Systems, Inc. All rights reserved +* + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.cloud.usage.dao; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; + +import javax.ejb.Local; + +import org.apache.log4j.Logger; + +import com.cloud.usage.UsageVPNUserVO; +import com.cloud.utils.DateUtil; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.Transaction; + +@Local(value={UsageVPNUserDao.class}) +public class UsageVPNUserDaoImpl extends GenericDaoBase implements UsageVPNUserDao { + public static final Logger s_logger = Logger.getLogger(UsageVPNUserDaoImpl.class.getName()); + + protected static final String UPDATE_DELETED = "UPDATE usage_vpn_user SET deleted = ? WHERE account_id = ? AND user_id = ? and deleted IS NULL"; + protected static final String GET_USAGE_RECORDS_BY_ACCOUNT = "SELECT zone_id, account_id, domain_id, user_id, user_name, created, deleted " + + "FROM usage_vpn_user " + + "WHERE account_id = ? AND ((deleted IS NULL) OR (created BETWEEN ? AND ?) OR " + + " (deleted BETWEEN ? AND ?) OR ((created <= ?) AND (deleted >= ?)))"; + protected static final String GET_USAGE_RECORDS_BY_DOMAIN = "SELECT zone_id, account_id, domain_id, user_id, user_name, created, deleted " + + "FROM usage_vpn_user " + + "WHERE domain_id = ? AND ((deleted IS NULL) OR (created BETWEEN ? AND ?) OR " + + " (deleted BETWEEN ? AND ?) OR ((created <= ?) AND (deleted >= ?)))"; + protected static final String GET_ALL_USAGE_RECORDS = "SELECT zone_id, account_id, domain_id, user_id, user_name, created, deleted " + + "FROM usage_vpn_user " + + "WHERE (deleted IS NULL) OR (created BETWEEN ? AND ?) OR " + + " (deleted BETWEEN ? AND ?) OR ((created <= ?) AND (deleted >= ?))"; + + public UsageVPNUserDaoImpl() {} + + public void update(UsageVPNUserVO usage) { + Transaction txn = Transaction.open(Transaction.USAGE_DB); + PreparedStatement pstmt = null; + try { + txn.start(); + if (usage.getDeleted() != null) { + pstmt = txn.prepareAutoCloseStatement(UPDATE_DELETED); + pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), usage.getDeleted())); + pstmt.setLong(2, usage.getAccountId()); + pstmt.setLong(3, usage.getUserId()); + } + pstmt.executeUpdate(); + txn.commit(); + } catch (Exception e) { + txn.rollback(); + s_logger.warn("Error updating UsageVPNUserVO", e); + } finally { + txn.close(); + } + } + + @Override + public List getUsageRecords(Long accountId, Long domainId, Date startDate, Date endDate, boolean limit, int page) { + List usageRecords = new ArrayList(); + + Long param1 = null; + String sql = null; + if (accountId != null) { + sql = GET_USAGE_RECORDS_BY_ACCOUNT; + param1 = accountId; + } else if (domainId != null) { + sql = GET_USAGE_RECORDS_BY_DOMAIN; + param1 = domainId; + } else { + sql = GET_ALL_USAGE_RECORDS; + } + + if (limit) { + int startIndex = 0; + if (page > 0) { + startIndex = 500 * (page-1); + } + sql += " LIMIT " + startIndex + ",500"; + } + + Transaction txn = Transaction.open(Transaction.USAGE_DB); + PreparedStatement pstmt = null; + + try { + int i = 1; + pstmt = txn.prepareAutoCloseStatement(sql); + if (param1 != null) { + pstmt.setLong(i++, param1); + } + pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), startDate)); + pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate)); + pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), startDate)); + pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate)); + pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), startDate)); + pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate)); + + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + //zoneId, account_id, domain_id, user_id, user_name, created, deleted + Long zoneId = Long.valueOf(rs.getLong(1)); + Long acctId = Long.valueOf(rs.getLong(2)); + Long dId = Long.valueOf(rs.getLong(3)); + long userId = Long.valueOf(rs.getLong(4)); + String userName = rs.getString(5); + Date createdDate = null; + Date deletedDate = null; + String createdTS = rs.getString(6); + String deletedTS = rs.getString(7); + + + if (createdTS != null) { + createdDate = DateUtil.parseDateString(s_gmtTimeZone, createdTS); + } + if (deletedTS != null) { + deletedDate = DateUtil.parseDateString(s_gmtTimeZone, deletedTS); + } + + usageRecords.add(new UsageVPNUserVO(zoneId, acctId, dId, userId, userName, createdDate, deletedDate)); + } + } catch (Exception e) { + txn.rollback(); + s_logger.warn("Error getting usage records", e); + } finally { + txn.close(); + } + + return usageRecords; + } +} diff --git a/setup/db/create-schema-premium.sql b/setup/db/create-schema-premium.sql index 3fc33a2d442..a0c6fce880b 100644 --- a/setup/db/create-schema-premium.sql +++ b/setup/db/create-schema-premium.sql @@ -12,6 +12,7 @@ DROP TABLE IF EXISTS `cloud_usage`.`usage_load_balancer_policy`; DROP TABLE IF EXISTS `cloud_usage`.`usage_port_forwarding`; DROP TABLE IF EXISTS `cloud_usage`.`usage_network_offering`; DROP TABLE IF EXISTS `cloud_usage`.`usage_event`; +DROP TABLE IF EXISTS `cloud_usage`.`usage_vpn_user`; CREATE TABLE `cloud_usage`.`cloud_usage` ( `id` bigint unsigned NOT NULL auto_increment, @@ -232,6 +233,21 @@ ALTER TABLE `cloud_usage`.`usage_network_offering` ADD INDEX `i_usage_network_of ALTER TABLE `cloud_usage`.`usage_network_offering` ADD INDEX `i_usage_network_offering__created`(`created`); ALTER TABLE `cloud_usage`.`usage_network_offering` ADD INDEX `i_usage_network_offering__deleted`(`deleted`); +CREATE TABLE `cloud_usage`.`usage_vpn_user` ( + `zone_id` bigint unsigned NOT NULL, + `account_id` bigint unsigned NOT NULL, + `domain_id` bigint unsigned NOT NULL, + `user_id` bigint unsigned NOT NULL, + `user_name` varchar(32), + `created` DATETIME NOT NULL, + `deleted` DATETIME NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `cloud_usage`.`usage_vpn_user` ADD INDEX `i_usage_vpn_user__account_id`(`account_id`); +ALTER TABLE `cloud_usage`.`usage_vpn_user` ADD INDEX `i_usage_vpn_user__created`(`created`); +ALTER TABLE `cloud_usage`.`usage_vpn_user` ADD INDEX `i_usage_vpn_user__deleted`(`deleted`); + + CREATE TABLE `cloud`.`netapp_volume` ( `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id', `ip_address` varchar(255) NOT NULL COMMENT 'ip address/fqdn of the volume', diff --git a/setup/db/db/schema-2213to30-premium.sql b/setup/db/db/schema-2213to30-premium.sql index 752814a4eb9..7bfe5dd1ca8 100755 --- a/setup/db/db/schema-2213to30-premium.sql +++ b/setup/db/db/schema-2213to30-premium.sql @@ -15,3 +15,17 @@ ALTER TABLE `cloud_usage`.`usage_network` DROP COLUMN `net_bytes_sent`; ALTER TABLE `cloud_usage`.`usage_network` DROP COLUMN `current_bytes_received`; ALTER TABLE `cloud_usage`.`usage_network` DROP COLUMN `current_bytes_sent`; +CREATE TABLE `cloud_usage`.`usage_vpn_user` ( + `zone_id` bigint unsigned NOT NULL, + `account_id` bigint unsigned NOT NULL, + `domain_id` bigint unsigned NOT NULL, + `user_id` bigint unsigned NOT NULL, + `user_name` varchar(32), + `created` DATETIME NOT NULL, + `deleted` DATETIME NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `cloud_usage`.`usage_vpn_user` ADD INDEX `i_usage_vpn_user__account_id`(`account_id`); +ALTER TABLE `cloud_usage`.`usage_vpn_user` ADD INDEX `i_usage_vpn_user__created`(`created`); +ALTER TABLE `cloud_usage`.`usage_vpn_user` ADD INDEX `i_usage_vpn_user__deleted`(`deleted`); + diff --git a/usage/conf/usage-components.xml.in b/usage/conf/usage-components.xml.in index bda902fe88f..2392be0f69d 100644 --- a/usage/conf/usage-components.xml.in +++ b/usage/conf/usage-components.xml.in @@ -44,6 +44,7 @@ + diff --git a/usage/src/com/cloud/usage/UsageManagerImpl.java b/usage/src/com/cloud/usage/UsageManagerImpl.java index df77ac0f24b..473b05d2322 100644 --- a/usage/src/com/cloud/usage/UsageManagerImpl.java +++ b/usage/src/com/cloud/usage/UsageManagerImpl.java @@ -52,6 +52,7 @@ import com.cloud.usage.dao.UsageNetworkOfferingDao; import com.cloud.usage.dao.UsagePortForwardingRuleDao; import com.cloud.usage.dao.UsageStorageDao; import com.cloud.usage.dao.UsageVMInstanceDao; +import com.cloud.usage.dao.UsageVPNUserDao; import com.cloud.usage.dao.UsageVolumeDao; import com.cloud.usage.parser.IPAddressUsageParser; import com.cloud.usage.parser.LoadBalancerUsageParser; @@ -60,6 +61,7 @@ import com.cloud.usage.parser.NetworkUsageParser; import com.cloud.usage.parser.PortForwardingUsageParser; import com.cloud.usage.parser.StorageUsageParser; import com.cloud.usage.parser.VMInstanceUsageParser; +import com.cloud.usage.parser.VPNUserUsageParser; import com.cloud.usage.parser.VolumeUsageParser; import com.cloud.user.Account; import com.cloud.user.AccountVO; @@ -101,6 +103,7 @@ public class UsageManagerImpl implements UsageManager, Runnable { private final UsageLoadBalancerPolicyDao m_usageLoadBalancerPolicyDao = _locator.getDao(UsageLoadBalancerPolicyDao.class); private final UsagePortForwardingRuleDao m_usagePortForwardingRuleDao = _locator.getDao(UsagePortForwardingRuleDao.class); private final UsageNetworkOfferingDao m_usageNetworkOfferingDao = _locator.getDao(UsageNetworkOfferingDao.class); + private final UsageVPNUserDao m_usageVPNUserDao = _locator.getDao(UsageVPNUserDao.class); private final UsageJobDao m_usageJobDao = _locator.getDao(UsageJobDao.class); @Inject protected AlertManager _alertMgr; @Inject protected UsageEventDao _usageEventDao; @@ -743,7 +746,12 @@ public class UsageManagerImpl implements UsageManager, Runnable { s_logger.debug("IPAddress usage successfully parsed? " + parsed + " (for account: " + account.getAccountName() + ", id: " + account.getId() + ")"); } } - + parsed = VPNUserUsageParser.parse(account, currentStartDate, currentEndDate); + if (s_logger.isDebugEnabled()) { + if (!parsed) { + s_logger.debug("VPN user usage successfully parsed? " + parsed + " (for account: " + account.getAccountName() + ", id: " + account.getId() + ")"); + } + } return parsed; } @@ -767,6 +775,8 @@ public class UsageManagerImpl implements UsageManager, Runnable { createPortForwardingHelperEvent(event); } else if (isNetworkOfferingEvent(eventType)) { createNetworkOfferingEvent(event); + } else if (isVPNUserEvent(eventType)) { + createVPNUserEvent(event); } } @@ -824,6 +834,11 @@ public class UsageManagerImpl implements UsageManager, Runnable { eventType.equals(EventTypes.EVENT_NETWORK_OFFERING_REMOVE)); } + private boolean isVPNUserEvent(String eventType) { + if (eventType == null) return false; + return eventType.startsWith("VPN.USER"); + } + private void createVMHelperEvent(UsageEventVO event) { // One record for handling VM.START and VM.STOP @@ -1293,7 +1308,39 @@ public class UsageManagerImpl implements UsageManager, Runnable { } } } + + private void createVPNUserEvent(UsageEventVO event) { + long zoneId = 0L; + + long userId = event.getResourceId(); + + if (EventTypes.EVENT_VPN_USER_ADD.equals(event.getType())) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Creating VPN user: "+ userId + " for account: " + event.getAccountId()); + } + Account acct = m_accountDao.findByIdIncludingRemoved(event.getAccountId()); + String userName = event.getResourceName(); + UsageVPNUserVO vpnUser = new UsageVPNUserVO(zoneId, event.getAccountId(), acct.getDomainId(), userId, userName, event.getCreateDate(), null); + m_usageVPNUserDao.persist(vpnUser); + } else if (EventTypes.EVENT_VPN_USER_REMOVE.equals(event.getType())) { + SearchCriteria sc = m_usageVPNUserDao.createSearchCriteria(); + sc.addAnd("accountId", SearchCriteria.Op.EQ, event.getAccountId()); + sc.addAnd("userId", SearchCriteria.Op.EQ, userId); + sc.addAnd("deleted", SearchCriteria.Op.NULL); + List vuVOs = m_usageVPNUserDao.search(sc, null); + if (vuVOs.size() > 1) { + s_logger.warn("More that one usage entry for vpn user: "+ userId +" assigned to account: " + event.getAccountId() + "; marking them all as deleted..."); + } + for (UsageVPNUserVO vuVO : vuVOs) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("deleting vpn user: " + vuVO.getUserId()); + } + vuVO.setDeleted(event.getCreateDate()); // there really shouldn't be more than one + m_usageVPNUserDao.update(vuVO); + } + } + } private class Heartbeat implements Runnable { public void run() { diff --git a/usage/src/com/cloud/usage/parser/VPNUserUsageParser.java b/usage/src/com/cloud/usage/parser/VPNUserUsageParser.java new file mode 100644 index 00000000000..3dbfd5aa0df --- /dev/null +++ b/usage/src/com/cloud/usage/parser/VPNUserUsageParser.java @@ -0,0 +1,163 @@ + +/** + * * Copyright (C) 2011 Citrix Systems, Inc. All rights reserved +* + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.cloud.usage.parser; + +import java.text.DecimalFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; + +import com.cloud.usage.UsageVPNUserVO; +import com.cloud.usage.UsageServer; +import com.cloud.usage.UsageTypes; +import com.cloud.usage.UsageVO; +import com.cloud.usage.dao.UsageDao; +import com.cloud.usage.dao.UsageVPNUserDao; +import com.cloud.user.AccountVO; +import com.cloud.utils.Pair; +import com.cloud.utils.component.ComponentLocator; + +public class VPNUserUsageParser { + public static final Logger s_logger = Logger.getLogger(VPNUserUsageParser.class.getName()); + + private static ComponentLocator _locator = ComponentLocator.getLocator(UsageServer.Name, "usage-components.xml", "log4j-cloud_usage"); + private static UsageDao m_usageDao = _locator.getDao(UsageDao.class); + private static UsageVPNUserDao m_usageVPNUserDao = _locator.getDao(UsageVPNUserDao.class); + + public static boolean parse(AccountVO account, Date startDate, Date endDate) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Parsing all VPN user usage events for account: " + account.getId()); + } + if ((endDate == null) || endDate.after(new Date())) { + endDate = new Date(); + } + + List usageVUs = m_usageVPNUserDao.getUsageRecords(account.getId(), account.getDomainId(), startDate, endDate, false, 0); + + if(usageVUs.isEmpty()){ + s_logger.debug("No VPN user usage events for this period"); + return true; + } + + // This map has both the running time *and* the usage amount. + Map> usageMap = new HashMap>(); + Map vuMap = new HashMap(); + + // loop through all the VPN user usage, create a usage record for each + for (UsageVPNUserVO usageVU : usageVUs) { + long userId = usageVU.getUserId(); + String userName = usageVU.getUsername(); + String key = ""+userId+"VU"+userName; + + vuMap.put(key, new VUInfo(userId, usageVU.getZoneId(), userName)); + + Date vuCreateDate = usageVU.getCreated(); + Date vuDeleteDate = usageVU.getDeleted(); + + if ((vuDeleteDate == null) || vuDeleteDate.after(endDate)) { + vuDeleteDate = endDate; + } + + // clip the start date to the beginning of our aggregation range if the vm has been running for a while + if (vuCreateDate.before(startDate)) { + vuCreateDate = startDate; + } + + long currentDuration = (vuDeleteDate.getTime() - vuCreateDate.getTime()) + 1; // make sure this is an inclusive check for milliseconds (i.e. use n - m + 1 to find total number of millis to charge) + + + updateVUUsageData(usageMap, key, usageVU.getUserId(), currentDuration); + } + + for (String vuIdKey : usageMap.keySet()) { + Pair vutimeInfo = usageMap.get(vuIdKey); + long useTime = vutimeInfo.second().longValue(); + + // Only create a usage record if we have a runningTime of bigger than zero. + if (useTime > 0L) { + VUInfo info = vuMap.get(vuIdKey); + createUsageRecord(UsageTypes.VPN_USERS, useTime, startDate, endDate, account, info.getUserId(), info.getUserName(), info.getZoneId()); + } + } + + return true; + } + + private static void updateVUUsageData(Map> usageDataMap, String key, long userId, long duration) { + Pair vuUsageInfo = usageDataMap.get(key); + if (vuUsageInfo == null) { + vuUsageInfo = new Pair(new Long(userId), new Long(duration)); + } else { + Long runningTime = vuUsageInfo.second(); + runningTime = new Long(runningTime.longValue() + duration); + vuUsageInfo = new Pair(vuUsageInfo.first(), runningTime); + } + usageDataMap.put(key, vuUsageInfo); + } + + private static void createUsageRecord(int type, long runningTime, Date startDate, Date endDate, AccountVO account, long userId, String userName, long zoneId) { + // Our smallest increment is hourly for now + if (s_logger.isDebugEnabled()) { + s_logger.debug("Total running time " + runningTime + "ms"); + } + + float usage = runningTime / 1000f / 60f / 60f; + + DecimalFormat dFormat = new DecimalFormat("#.######"); + String usageDisplay = dFormat.format(usage); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Creating VPN user:" + userId + " usage record, usage: " + usageDisplay + ", startDate: " + startDate + ", endDate: " + endDate + ", for account: " + account.getId()); + } + + // Create the usage record + String usageDesc = "VPN User: " + userName + ", Id: "+ userId + " usage time"; + + UsageVO usageRecord = new UsageVO(zoneId, account.getId(), account.getDomainId(), usageDesc, usageDisplay + " Hrs", type, + new Double(usage), null, null, null, null, userId, null, startDate, endDate); + m_usageDao.persist(usageRecord); + } + + private static class VUInfo { + private long userId; + private long zoneId; + private String userName; + + public VUInfo(long userId, long zoneId, String userName) { + this.userId = userId; + this.zoneId = zoneId; + this.userName = userName; + } + public long getZoneId() { + return zoneId; + } + public long getUserId() { + return userId; + } + public String getUserName() { + return userName; + } + } + +}