| // 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 com.cloud.network; |
| |
| import java.net.URI; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.ScheduledExecutorService; |
| import java.util.concurrent.TimeUnit; |
| |
| import javax.inject.Inject; |
| import javax.naming.ConfigurationException; |
| |
| import org.apache.cloudstack.framework.config.dao.ConfigurationDao; |
| import org.apache.cloudstack.managed.context.ManagedContextRunnable; |
| import org.apache.log4j.Logger; |
| import org.springframework.stereotype.Component; |
| |
| import com.cloud.agent.AgentManager; |
| import com.cloud.agent.api.ExternalNetworkResourceUsageAnswer; |
| import com.cloud.agent.api.ExternalNetworkResourceUsageCommand; |
| import com.cloud.configuration.Config; |
| import com.cloud.dc.DataCenterVO; |
| import com.cloud.dc.dao.DataCenterDao; |
| import com.cloud.dc.dao.HostPodDao; |
| import com.cloud.dc.dao.VlanDao; |
| import com.cloud.host.Host; |
| import com.cloud.host.HostVO; |
| import com.cloud.host.Host.Type; |
| import com.cloud.host.dao.HostDao; |
| import com.cloud.host.dao.HostDetailsDao; |
| import com.cloud.network.Networks.BroadcastDomainType; |
| import com.cloud.network.dao.ExternalFirewallDeviceDao; |
| import com.cloud.network.dao.ExternalFirewallDeviceVO; |
| import com.cloud.network.dao.ExternalLoadBalancerDeviceDao; |
| import com.cloud.network.dao.ExternalLoadBalancerDeviceVO; |
| import com.cloud.network.dao.IPAddressDao; |
| import com.cloud.network.dao.IPAddressVO; |
| import com.cloud.network.dao.InlineLoadBalancerNicMapDao; |
| import com.cloud.network.dao.InlineLoadBalancerNicMapVO; |
| import com.cloud.network.dao.LoadBalancerDao; |
| import com.cloud.network.dao.LoadBalancerVO; |
| import com.cloud.network.dao.NetworkDao; |
| import com.cloud.network.dao.NetworkExternalFirewallDao; |
| import com.cloud.network.dao.NetworkExternalFirewallVO; |
| import com.cloud.network.dao.NetworkExternalLoadBalancerDao; |
| import com.cloud.network.dao.NetworkExternalLoadBalancerVO; |
| import com.cloud.network.dao.NetworkServiceMapDao; |
| import com.cloud.network.dao.NetworkVO; |
| import com.cloud.network.dao.PhysicalNetworkDao; |
| import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; |
| import com.cloud.network.rules.LoadBalancerContainer.Scheme; |
| import com.cloud.network.rules.PortForwardingRuleVO; |
| import com.cloud.network.rules.dao.PortForwardingRulesDao; |
| import com.cloud.offering.NetworkOffering; |
| import com.cloud.offerings.dao.NetworkOfferingDao; |
| import com.cloud.resource.ResourceManager; |
| import com.cloud.user.AccountManager; |
| import com.cloud.user.AccountVO; |
| import com.cloud.user.UserStatisticsVO; |
| import com.cloud.user.dao.AccountDao; |
| import com.cloud.user.dao.UserStatisticsDao; |
| import com.cloud.utils.NumbersUtil; |
| import com.cloud.utils.component.ManagerBase; |
| import com.cloud.utils.concurrency.NamedThreadFactory; |
| import com.cloud.utils.db.GlobalLock; |
| import com.cloud.utils.db.Transaction; |
| import com.cloud.utils.db.TransactionCallbackNoReturn; |
| import com.cloud.utils.db.TransactionStatus; |
| import com.cloud.utils.exception.CloudRuntimeException; |
| import com.cloud.vm.DomainRouterVO; |
| import com.cloud.vm.NicVO; |
| import com.cloud.vm.dao.DomainRouterDao; |
| import com.cloud.vm.dao.NicDao; |
| |
| @Component |
| public class ExternalDeviceUsageManagerImpl extends ManagerBase implements ExternalDeviceUsageManager { |
| |
| String _name; |
| @Inject |
| NetworkExternalLoadBalancerDao _networkExternalLBDao; |
| @Inject |
| ExternalLoadBalancerDeviceDao _externalLoadBalancerDeviceDao; |
| @Inject |
| HostDao _hostDao; |
| @Inject |
| DataCenterDao _dcDao; |
| @Inject |
| InlineLoadBalancerNicMapDao _inlineLoadBalancerNicMapDao; |
| @Inject |
| NicDao _nicDao; |
| @Inject |
| AgentManager _agentMgr; |
| @Inject |
| ResourceManager _resourceMgr; |
| @Inject |
| IPAddressDao _ipAddressDao; |
| @Inject |
| VlanDao _vlanDao; |
| @Inject |
| NetworkOfferingDao _networkOfferingDao; |
| @Inject |
| AccountDao _accountDao; |
| @Inject |
| PhysicalNetworkDao _physicalNetworkDao; |
| @Inject |
| PhysicalNetworkServiceProviderDao _physicalNetworkServiceProviderDao; |
| @Inject |
| AccountManager _accountMgr; |
| @Inject |
| UserStatisticsDao _userStatsDao; |
| @Inject |
| NetworkDao _networkDao; |
| @Inject |
| DomainRouterDao _routerDao; |
| @Inject |
| LoadBalancerDao _loadBalancerDao; |
| @Inject |
| PortForwardingRulesDao _portForwardingRulesDao; |
| @Inject |
| ConfigurationDao _configDao; |
| @Inject |
| HostDetailsDao _hostDetailDao; |
| @Inject |
| NetworkExternalLoadBalancerDao _networkLBDao; |
| @Inject |
| NetworkServiceMapDao _ntwkSrvcProviderDao; |
| @Inject |
| NetworkExternalFirewallDao _networkExternalFirewallDao; |
| @Inject |
| ExternalFirewallDeviceDao _externalFirewallDeviceDao; |
| @Inject |
| protected HostPodDao _podDao = null; |
| @Inject |
| NetworkModel _networkModel; |
| |
| ScheduledExecutorService _executor; |
| private int _externalNetworkStatsInterval; |
| private static final org.apache.log4j.Logger s_logger = Logger.getLogger(ExternalDeviceUsageManagerImpl.class); |
| |
| @Override |
| public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { |
| _externalNetworkStatsInterval = NumbersUtil.parseInt(_configDao.getValue(Config.ExternalNetworkStatsInterval.key()), 300); |
| if (_externalNetworkStatsInterval > 0) { |
| _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("ExternalNetworkMonitor")); |
| } |
| return true; |
| |
| } |
| |
| @Override |
| public boolean start() { |
| if (_externalNetworkStatsInterval > 0) { |
| _executor.scheduleAtFixedRate(new ExternalDeviceNetworkUsageTask(), _externalNetworkStatsInterval, _externalNetworkStatsInterval, TimeUnit.SECONDS); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean stop() { |
| return true; |
| } |
| |
| @Override |
| public String getName() { |
| return _name; |
| } |
| |
| private ExternalLoadBalancerDeviceVO getExternalLoadBalancerForNetwork(Network network) { |
| NetworkExternalLoadBalancerVO lbDeviceForNetwork = _networkExternalLBDao.findByNetworkId(network.getId()); |
| if (lbDeviceForNetwork != null) { |
| long lbDeviceId = lbDeviceForNetwork.getExternalLBDeviceId(); |
| ExternalLoadBalancerDeviceVO lbDeviceVo = _externalLoadBalancerDeviceDao.findById(lbDeviceId); |
| assert (lbDeviceVo != null); |
| return lbDeviceVo; |
| } |
| return null; |
| } |
| |
| private ExternalFirewallDeviceVO getExternalFirewallForNetwork(Network network) { |
| NetworkExternalFirewallVO fwDeviceForNetwork = _networkExternalFirewallDao.findByNetworkId(network.getId()); |
| if (fwDeviceForNetwork != null) { |
| long fwDeviceId = fwDeviceForNetwork.getExternalFirewallDeviceId(); |
| ExternalFirewallDeviceVO fwDevice = _externalFirewallDeviceDao.findById(fwDeviceId); |
| assert (fwDevice != null); |
| return fwDevice; |
| } |
| return null; |
| } |
| |
| @Override |
| public void updateExternalLoadBalancerNetworkUsageStats(long loadBalancerRuleId) { |
| |
| LoadBalancerVO lb = _loadBalancerDao.findById(loadBalancerRuleId); |
| if (lb == null) { |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Cannot update usage stats, LB rule is not found"); |
| } |
| return; |
| } |
| long networkId = lb.getNetworkId(); |
| Network network = _networkDao.findById(networkId); |
| if (network == null) { |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Cannot update usage stats, Network is not found"); |
| } |
| return; |
| } |
| |
| ExternalLoadBalancerDeviceVO lbDeviceVO = getExternalLoadBalancerForNetwork(network); |
| if (lbDeviceVO == null) { |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Cannot update usage stats, No external LB device found"); |
| } |
| return; |
| } |
| |
| // Get network stats from the external load balancer |
| ExternalNetworkResourceUsageAnswer lbAnswer = null; |
| HostVO externalLoadBalancer = _hostDao.findById(lbDeviceVO.getHostId()); |
| if (externalLoadBalancer != null) { |
| ExternalNetworkResourceUsageCommand cmd = new ExternalNetworkResourceUsageCommand(); |
| lbAnswer = (ExternalNetworkResourceUsageAnswer)_agentMgr.easySend(externalLoadBalancer.getId(), cmd); |
| if (lbAnswer == null || !lbAnswer.getResult()) { |
| String details = (lbAnswer != null) ? lbAnswer.getDetails() : "details unavailable"; |
| String msg = "Unable to get external load balancer stats for network" + networkId + " due to: " + details + "."; |
| s_logger.error(msg); |
| return; |
| } |
| } |
| |
| long accountId = lb.getAccountId(); |
| AccountVO account = _accountDao.findById(accountId); |
| if (account == null) { |
| s_logger.debug("Skipping stats update for external LB for account with ID " + accountId); |
| return; |
| } |
| |
| String publicIp = _networkModel.getIp(lb.getSourceIpAddressId()).getAddress().addr(); |
| DataCenterVO zone = _dcDao.findById(network.getDataCenterId()); |
| String statsEntryIdentifier = |
| "account " + account.getAccountName() + ", zone " + zone.getName() + ", network ID " + networkId + ", host ID " + externalLoadBalancer.getName(); |
| |
| long newCurrentBytesSent = 0; |
| long newCurrentBytesReceived = 0; |
| |
| if (publicIp != null) { |
| long[] bytesSentAndReceived = null; |
| statsEntryIdentifier += ", public IP: " + publicIp; |
| boolean inline = _networkModel.isNetworkInlineMode(network); |
| if (externalLoadBalancer.getType().equals(Host.Type.ExternalLoadBalancer) && inline) { |
| // Look up stats for the guest IP address that's mapped to the public IP address |
| InlineLoadBalancerNicMapVO mapping = _inlineLoadBalancerNicMapDao.findByPublicIpAddress(publicIp); |
| |
| if (mapping != null) { |
| NicVO nic = _nicDao.findById(mapping.getNicId()); |
| String loadBalancingIpAddress = nic.getIPv4Address(); |
| bytesSentAndReceived = lbAnswer.ipBytes.get(loadBalancingIpAddress); |
| |
| if (bytesSentAndReceived != null) { |
| bytesSentAndReceived[0] = 0; |
| } |
| } |
| } else { |
| bytesSentAndReceived = lbAnswer.ipBytes.get(publicIp); |
| } |
| |
| if (bytesSentAndReceived == null) { |
| s_logger.debug("Didn't get an external network usage answer for public IP " + publicIp); |
| } else { |
| newCurrentBytesSent += bytesSentAndReceived[0]; |
| newCurrentBytesReceived += bytesSentAndReceived[1]; |
| } |
| |
| commitStats(networkId, externalLoadBalancer, accountId, publicIp, zone, statsEntryIdentifier, newCurrentBytesSent, newCurrentBytesReceived); |
| } |
| } |
| |
| private void commitStats(final long networkId, final HostVO externalLoadBalancer, final long accountId, final String publicIp, final DataCenterVO zone, |
| final String statsEntryIdentifier, final long newCurrentBytesSent, final long newCurrentBytesReceived) { |
| Transaction.execute(new TransactionCallbackNoReturn() { |
| @Override |
| public void doInTransactionWithoutResult(TransactionStatus status) { |
| UserStatisticsVO userStats; |
| userStats = _userStatsDao.lock(accountId, zone.getId(), networkId, publicIp, externalLoadBalancer.getId(), externalLoadBalancer.getType().toString()); |
| |
| if (userStats != null) { |
| long oldNetBytesSent = userStats.getNetBytesSent(); |
| long oldNetBytesReceived = userStats.getNetBytesReceived(); |
| long oldCurrentBytesSent = userStats.getCurrentBytesSent(); |
| long oldCurrentBytesReceived = userStats.getCurrentBytesReceived(); |
| String warning = |
| "Received an external network stats byte count that was less than the stored value. Zone ID: " + userStats.getDataCenterId() + ", account ID: " + |
| userStats.getAccountId() + "."; |
| |
| userStats.setCurrentBytesSent(newCurrentBytesSent); |
| if (oldCurrentBytesSent > newCurrentBytesSent) { |
| s_logger.warn(warning + "Stored bytes sent: " + oldCurrentBytesSent + ", new bytes sent: " + newCurrentBytesSent + "."); |
| userStats.setNetBytesSent(oldNetBytesSent + oldCurrentBytesSent); |
| } |
| |
| userStats.setCurrentBytesReceived(newCurrentBytesReceived); |
| if (oldCurrentBytesReceived > newCurrentBytesReceived) { |
| s_logger.warn(warning + "Stored bytes received: " + oldCurrentBytesReceived + ", new bytes received: " + newCurrentBytesReceived + "."); |
| userStats.setNetBytesReceived(oldNetBytesReceived + oldCurrentBytesReceived); |
| } |
| |
| if (_userStatsDao.update(userStats.getId(), userStats)) { |
| s_logger.debug("Successfully updated stats for " + statsEntryIdentifier); |
| } else { |
| s_logger.debug("Failed to update stats for " + statsEntryIdentifier); |
| } |
| } else { |
| s_logger.warn("Unable to find user stats entry for " + statsEntryIdentifier); |
| } |
| } |
| }); |
| } |
| |
| public boolean isNccServiceProvider(Network network) { |
| NetworkOffering networkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId()); |
| if(null!= networkOffering && networkOffering.getServicePackage() != null ) { |
| return true; |
| } |
| else { |
| return false; |
| } |
| } |
| |
| public HostVO getNetScalerControlCenterForNetwork(Network guestConfig) { |
| long zoneId = guestConfig.getDataCenterId(); |
| return _hostDao.findByTypeNameAndZoneId(zoneId, "NetscalerControlCenter", Type.NetScalerControlCenter); |
| } |
| |
| protected class ExternalDeviceNetworkUsageTask extends ManagedContextRunnable { |
| |
| public ExternalDeviceNetworkUsageTask() { |
| |
| } |
| |
| @Override |
| protected void runInContext() { |
| |
| // Check if there are any external devices |
| // Skip external device usage collection if none exist |
| |
| if(_hostDao.listByType(Host.Type.ExternalFirewall).isEmpty() && _hostDao.listByType(Host.Type.ExternalLoadBalancer).isEmpty()){ |
| s_logger.debug("External devices are not used. Skipping external device usage collection"); |
| return; |
| } |
| |
| GlobalLock scanLock = GlobalLock.getInternLock("ExternalDeviceNetworkUsageManagerImpl"); |
| try { |
| if (scanLock.lock(20)) { |
| try { |
| runExternalDeviceNetworkUsageTask(); |
| } finally { |
| scanLock.unlock(); |
| } |
| } |
| } catch (Exception e) { |
| s_logger.warn("Problems while getting external device usage", e); |
| } finally { |
| scanLock.releaseRef(); |
| } |
| } |
| |
| protected void runExternalDeviceNetworkUsageTask() { |
| s_logger.debug("External devices stats collector is running..."); |
| |
| for (DataCenterVO zone : _dcDao.listAll()) { |
| List<DomainRouterVO> domainRoutersInZone = _routerDao.listByDataCenter(zone.getId()); |
| if (domainRoutersInZone == null) { |
| continue; |
| } |
| Map<Long, ExternalNetworkResourceUsageAnswer> lbDeviceUsageAnswerMap = new HashMap<Long, ExternalNetworkResourceUsageAnswer>(); |
| Map<Long, ExternalNetworkResourceUsageAnswer> fwDeviceUsageAnswerMap = new HashMap<Long, ExternalNetworkResourceUsageAnswer>(); |
| List<Long> accountsProcessed = new ArrayList<Long>(); |
| |
| for (DomainRouterVO domainRouter : domainRoutersInZone) { |
| long accountId = domainRouter.getAccountId(); |
| |
| if (accountsProcessed.contains(new Long(accountId))) { |
| if (s_logger.isTraceEnabled()) { |
| s_logger.trace("Networks for Account " + accountId + " are already processed for external network usage, so skipping usage check."); |
| } |
| continue; |
| } |
| |
| long zoneId = zone.getId(); |
| |
| List<NetworkVO> networksForAccount = _networkDao.listByZoneAndGuestType(accountId, zoneId, Network.GuestType.Isolated, false); |
| if (networksForAccount == null) { |
| continue; |
| } |
| |
| for (NetworkVO network : networksForAccount) { |
| if (!_networkModel.networkIsConfiguredForExternalNetworking(zoneId, network.getId())) { |
| s_logger.debug("Network " + network.getId() + " is not configured for external networking, so skipping usage check."); |
| continue; |
| } |
| |
| ExternalLoadBalancerDeviceVO lbDeviceVO = getExternalLoadBalancerForNetwork(network); |
| HostVO externalNcc = null; |
| boolean isNccNetwork = isNccServiceProvider(network); |
| if(isNccNetwork) { |
| externalNcc = getNetScalerControlCenterForNetwork(network); |
| } |
| ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network); |
| |
| if (fwDeviceVO == null) { |
| continue; |
| } |
| if(externalNcc == null && lbDeviceVO == null) { |
| return; |
| } |
| |
| // Get network stats from the external firewall |
| ExternalNetworkResourceUsageAnswer firewallAnswer = null; |
| HostVO externalFirewall = null; |
| if (fwDeviceVO != null) { |
| externalFirewall = _hostDao.findById(fwDeviceVO.getHostId()); |
| if (externalFirewall != null) { |
| Long fwDeviceId = new Long(externalFirewall.getId()); |
| if (!fwDeviceUsageAnswerMap.containsKey(fwDeviceId)) { |
| try { |
| ExternalNetworkResourceUsageCommand cmd = new ExternalNetworkResourceUsageCommand(); |
| firewallAnswer = (ExternalNetworkResourceUsageAnswer)_agentMgr.easySend(externalFirewall.getId(), cmd); |
| if (firewallAnswer == null || !firewallAnswer.getResult()) { |
| String details = (firewallAnswer != null) ? firewallAnswer.getDetails() : "details unavailable"; |
| String msg = "Unable to get external firewall stats for network" + zone.getName() + " due to: " + details + "."; |
| s_logger.error(msg); |
| } else { |
| fwDeviceUsageAnswerMap.put(fwDeviceId, firewallAnswer); |
| } |
| } catch (Exception e) { |
| String msg = "Unable to get external firewall stats for network" + zone.getName(); |
| s_logger.error(msg, e); |
| } |
| } else { |
| if (s_logger.isTraceEnabled()) { |
| s_logger.trace("Reusing usage Answer for device id " + fwDeviceId + "for Network " + network.getId()); |
| } |
| firewallAnswer = fwDeviceUsageAnswerMap.get(fwDeviceId); |
| } |
| } |
| } |
| |
| // Get network stats from the external load balancer |
| ExternalNetworkResourceUsageAnswer lbAnswer = null; |
| HostVO externalLoadBalancer = null; |
| if (lbDeviceVO != null || externalNcc != null) { |
| if(isNccNetwork) { |
| externalLoadBalancer = externalNcc; |
| } else { |
| externalLoadBalancer = _hostDao.findById(lbDeviceVO.getHostId()); |
| } |
| if (externalLoadBalancer != null) { |
| Long lbDeviceId = new Long(externalLoadBalancer.getId()); |
| if (!lbDeviceUsageAnswerMap.containsKey(lbDeviceId)) { |
| try { |
| ExternalNetworkResourceUsageCommand cmd = new ExternalNetworkResourceUsageCommand(network.getId()); |
| lbAnswer = (ExternalNetworkResourceUsageAnswer)_agentMgr.easySend(externalLoadBalancer.getId(), cmd); |
| if (lbAnswer == null || !lbAnswer.getResult()) { |
| String details = (lbAnswer != null) ? lbAnswer.getDetails() : "details unavailable"; |
| String msg = "Unable to get external load balancer stats for " + zone.getName() + " due to: " + details + "."; |
| s_logger.error(msg); |
| } else { |
| lbDeviceUsageAnswerMap.put(lbDeviceId, lbAnswer); |
| } |
| } catch (Exception e) { |
| String msg = "Unable to get external load balancer stats for " + zone.getName(); |
| s_logger.error(msg, e); |
| } |
| } else { |
| if (s_logger.isTraceEnabled()) { |
| s_logger.trace("Reusing usage Answer for device id " + lbDeviceId + "for Network " + network.getId()); |
| } |
| lbAnswer = lbDeviceUsageAnswerMap.get(lbDeviceId); |
| } |
| } |
| } |
| |
| if (firewallAnswer == null && lbAnswer == null) { |
| continue; |
| } |
| |
| AccountVO account = _accountDao.findById(accountId); |
| if (account == null) { |
| s_logger.debug("Skipping stats update for account with ID " + accountId); |
| continue; |
| } |
| |
| if (!manageStatsEntries(true, accountId, zoneId, network, externalFirewall, firewallAnswer, externalLoadBalancer, lbAnswer)) { |
| continue; |
| } |
| |
| manageStatsEntries(false, accountId, zoneId, network, externalFirewall, firewallAnswer, externalLoadBalancer, lbAnswer); |
| } |
| |
| accountsProcessed.add(new Long(accountId)); |
| } |
| } |
| } |
| |
| private boolean updateBytes(UserStatisticsVO userStats, long newCurrentBytesSent, long newCurrentBytesReceived) { |
| long oldNetBytesSent = userStats.getNetBytesSent(); |
| long oldNetBytesReceived = userStats.getNetBytesReceived(); |
| long oldCurrentBytesSent = userStats.getCurrentBytesSent(); |
| long oldCurrentBytesReceived = userStats.getCurrentBytesReceived(); |
| String warning = |
| "Received an external network stats byte count that was less than the stored value. Zone ID: " + userStats.getDataCenterId() + ", account ID: " + |
| userStats.getAccountId() + "."; |
| |
| userStats.setCurrentBytesSent(newCurrentBytesSent); |
| if (oldCurrentBytesSent > newCurrentBytesSent) { |
| s_logger.warn(warning + "Stored bytes sent: " + oldCurrentBytesSent + ", new bytes sent: " + newCurrentBytesSent + "."); |
| userStats.setNetBytesSent(oldNetBytesSent + oldCurrentBytesSent); |
| } |
| |
| userStats.setCurrentBytesReceived(newCurrentBytesReceived); |
| if (oldCurrentBytesReceived > newCurrentBytesReceived) { |
| s_logger.warn(warning + "Stored bytes received: " + oldCurrentBytesReceived + ", new bytes received: " + newCurrentBytesReceived + "."); |
| userStats.setNetBytesReceived(oldNetBytesReceived + oldCurrentBytesReceived); |
| } |
| |
| return _userStatsDao.update(userStats.getId(), userStats); |
| } |
| |
| // Creates a new stats entry for the specified parameters, if one doesn't already exist. |
| private boolean createStatsEntry(long accountId, long zoneId, long networkId, String publicIp, long hostId) { |
| HostVO host = _hostDao.findById(hostId); |
| UserStatisticsVO userStats = _userStatsDao.findBy(accountId, zoneId, networkId, publicIp, hostId, host.getType().toString()); |
| if (userStats == null) { |
| return (_userStatsDao.persist(new UserStatisticsVO(accountId, zoneId, publicIp, hostId, host.getType().toString(), networkId)) != null); |
| } else { |
| return true; |
| } |
| } |
| |
| // Updates an existing stats entry with new data from the specified usage answer. |
| private boolean updateStatsEntry(long accountId, long zoneId, long networkId, String publicIp, long hostId, ExternalNetworkResourceUsageAnswer answer, |
| boolean inline) { |
| AccountVO account = _accountDao.findById(accountId); |
| DataCenterVO zone = _dcDao.findById(zoneId); |
| NetworkVO network = _networkDao.findById(networkId); |
| HostVO host = _hostDao.findById(hostId); |
| String statsEntryIdentifier = |
| "account " + account.getAccountName() + ", zone " + zone.getName() + ", network ID " + networkId + ", host ID " + host.getName(); |
| |
| long newCurrentBytesSent = 0; |
| long newCurrentBytesReceived = 0; |
| |
| if (publicIp != null) { |
| long[] bytesSentAndReceived = null; |
| statsEntryIdentifier += ", public IP: " + publicIp; |
| |
| if (host.getType().equals(Host.Type.ExternalLoadBalancer) && inline) { |
| // Look up stats for the guest IP address that's mapped to the public IP address |
| InlineLoadBalancerNicMapVO mapping = _inlineLoadBalancerNicMapDao.findByPublicIpAddress(publicIp); |
| |
| if (mapping != null) { |
| NicVO nic = _nicDao.findById(mapping.getNicId()); |
| String loadBalancingIpAddress = nic.getIPv4Address(); |
| bytesSentAndReceived = answer.ipBytes.get(loadBalancingIpAddress); |
| |
| if (bytesSentAndReceived != null) { |
| bytesSentAndReceived[0] = 0; |
| } |
| } |
| } else { |
| bytesSentAndReceived = answer.ipBytes.get(publicIp); |
| } |
| |
| if (bytesSentAndReceived == null) { |
| s_logger.debug("Didn't get an external network usage answer for public IP " + publicIp); |
| } else { |
| newCurrentBytesSent += bytesSentAndReceived[0]; |
| newCurrentBytesReceived += bytesSentAndReceived[1]; |
| } |
| } else { |
| URI broadcastURI = network.getBroadcastUri(); |
| if (broadcastURI == null) { |
| s_logger.debug("Not updating stats for guest network with ID " + network.getId() + " because the network is not implemented."); |
| return true; |
| } else { |
| long vlanTag = Integer.parseInt(BroadcastDomainType.getValue(broadcastURI)); |
| long[] bytesSentAndReceived = answer.guestVlanBytes.get(String.valueOf(vlanTag)); |
| |
| if (bytesSentAndReceived == null) { |
| s_logger.warn("Didn't get an external network usage answer for guest VLAN " + vlanTag); |
| } else { |
| newCurrentBytesSent += bytesSentAndReceived[0]; |
| newCurrentBytesReceived += bytesSentAndReceived[1]; |
| } |
| } |
| } |
| |
| UserStatisticsVO userStats; |
| try { |
| userStats = _userStatsDao.lock(accountId, zoneId, networkId, publicIp, hostId, host.getType().toString()); |
| } catch (Exception e) { |
| s_logger.warn("Unable to find user stats entry for " + statsEntryIdentifier); |
| return false; |
| } |
| |
| if (updateBytes(userStats, newCurrentBytesSent, newCurrentBytesReceived)) { |
| s_logger.debug("Successfully updated stats for " + statsEntryIdentifier); |
| return true; |
| } else { |
| s_logger.debug("Failed to update stats for " + statsEntryIdentifier); |
| return false; |
| } |
| } |
| |
| private boolean createOrUpdateStatsEntry(boolean create, long accountId, long zoneId, long networkId, String publicIp, long hostId, |
| ExternalNetworkResourceUsageAnswer answer, boolean inline) { |
| if (create) { |
| return createStatsEntry(accountId, zoneId, networkId, publicIp, hostId); |
| } else { |
| return updateStatsEntry(accountId, zoneId, networkId, publicIp, hostId, answer, inline); |
| } |
| } |
| |
| /* |
| * Creates/updates all necessary stats entries for an account and zone. |
| * Stats entries are created for source NAT IP addresses, static NAT rules, port forwarding rules, and load |
| * balancing rules |
| */ |
| private boolean manageStatsEntries(final boolean create, final long accountId, final long zoneId, final Network network, final HostVO externalFirewall, |
| final ExternalNetworkResourceUsageAnswer firewallAnswer, final HostVO externalLoadBalancer, final ExternalNetworkResourceUsageAnswer lbAnswer) { |
| final String accountErrorMsg = "Failed to update external network stats entry. Details: account ID = " + accountId; |
| try { |
| Transaction.execute(new TransactionCallbackNoReturn() { |
| @Override |
| public void doInTransactionWithoutResult(TransactionStatus status) { |
| String networkErrorMsg = accountErrorMsg + ", network ID = " + network.getId(); |
| |
| boolean sharedSourceNat = false; |
| Map<Network.Capability, String> sourceNatCapabilities = _networkModel.getNetworkServiceCapabilities(network.getId(), Network.Service.SourceNat); |
| if (sourceNatCapabilities != null) { |
| String supportedSourceNatTypes = sourceNatCapabilities.get(Network.Capability.SupportedSourceNatTypes).toLowerCase(); |
| if (supportedSourceNatTypes.contains("zone")) { |
| sharedSourceNat = true; |
| } |
| } |
| |
| if (externalFirewall != null && firewallAnswer != null) { |
| if (!sharedSourceNat) { |
| // Manage the entry for this network's source NAT IP address |
| List<IPAddressVO> sourceNatIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), true); |
| if (sourceNatIps.size() == 1) { |
| String publicIp = sourceNatIps.get(0).getAddress().addr(); |
| if (!createOrUpdateStatsEntry(create, accountId, zoneId, network.getId(), publicIp, externalFirewall.getId(), firewallAnswer, false)) { |
| throw new CloudRuntimeException(networkErrorMsg + ", source NAT IP = " + publicIp); |
| } |
| } |
| |
| // Manage one entry for each static NAT rule in this network |
| List<IPAddressVO> staticNatIps = _ipAddressDao.listStaticNatPublicIps(network.getId()); |
| for (IPAddressVO staticNatIp : staticNatIps) { |
| String publicIp = staticNatIp.getAddress().addr(); |
| if (!createOrUpdateStatsEntry(create, accountId, zoneId, network.getId(), publicIp, externalFirewall.getId(), firewallAnswer, false)) { |
| throw new CloudRuntimeException(networkErrorMsg + ", static NAT rule public IP = " + publicIp); |
| } |
| } |
| |
| // Manage one entry for each port forwarding rule in this network |
| List<PortForwardingRuleVO> portForwardingRules = _portForwardingRulesDao.listByNetwork(network.getId()); |
| for (PortForwardingRuleVO portForwardingRule : portForwardingRules) { |
| String publicIp = _networkModel.getIp(portForwardingRule.getSourceIpAddressId()).getAddress().addr(); |
| if (!createOrUpdateStatsEntry(create, accountId, zoneId, network.getId(), publicIp, externalFirewall.getId(), firewallAnswer, false)) { |
| throw new CloudRuntimeException(networkErrorMsg + ", port forwarding rule public IP = " + publicIp); |
| } |
| } |
| } else { |
| // Manage the account-wide entry for the external firewall |
| if (!createOrUpdateStatsEntry(create, accountId, zoneId, network.getId(), null, externalFirewall.getId(), firewallAnswer, false)) { |
| throw new CloudRuntimeException(networkErrorMsg); |
| } |
| } |
| } |
| |
| // If an external load balancer is added, manage one entry for each load balancing rule in this network |
| if (externalLoadBalancer != null && lbAnswer != null) { |
| boolean inline = _networkModel.isNetworkInlineMode(network); |
| List<LoadBalancerVO> loadBalancers = _loadBalancerDao.listByNetworkIdAndScheme(network.getId(), Scheme.Public); |
| for (LoadBalancerVO loadBalancer : loadBalancers) { |
| String publicIp = _networkModel.getIp(loadBalancer.getSourceIpAddressId()).getAddress().addr(); |
| if (!createOrUpdateStatsEntry(create, accountId, zoneId, network.getId(), publicIp, externalLoadBalancer.getId(), lbAnswer, inline)) { |
| throw new CloudRuntimeException(networkErrorMsg + ", load balancing rule public IP = " + publicIp); |
| } |
| } |
| } |
| } |
| }); |
| return true; |
| } catch (Exception e) { |
| s_logger.warn("Exception: ", e); |
| return false; |
| } |
| } |
| } |
| } |