From 65b7a2740742ca6968b86bcddff8d670d310cf93 Mon Sep 17 00:00:00 2001 From: prachi Date: Thu, 2 Feb 2012 17:23:07 -0800 Subject: [PATCH] Bug 13229 - Network Usage - Netscaler - NetworkUsage not being called when Lb rules are deleted and when releasing the Ip adress that has Lb rules. Reviewed-by: Kishan Changes: - When an LB rule is deleted or the IP address having an LB rule configured is released, ExternalNetworkUsageCommand is fired to gather the usage accumulated on that IP after the last run of the ExternalNetworkUsage job. --- .../DefaultComponentLibrary.java | 2 + .../ExternalLoadBalancerDeviceManager.java | 8 +- ...ExternalLoadBalancerDeviceManagerImpl.java | 128 +++++++++++++++++- .../lb/LoadBalancingRulesManagerImpl.java | 16 ++- 4 files changed, 149 insertions(+), 5 deletions(-) diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java index 2ae9d7b2722..79c9f748287 100755 --- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java +++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java @@ -72,6 +72,7 @@ import com.cloud.keystore.KeystoreDaoImpl; import com.cloud.keystore.KeystoreManagerImpl; import com.cloud.maint.UpgradeManagerImpl; import com.cloud.maint.dao.AgentUpgradeDaoImpl; +import com.cloud.network.ExternalLoadBalancerDeviceManagerImpl; import com.cloud.network.NetworkManagerImpl; import com.cloud.network.StorageNetworkManagerImpl; import com.cloud.network.dao.ExternalFirewallDeviceDaoImpl; @@ -388,6 +389,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com addManager("ElasticLoadBalancerManager", ElasticLoadBalancerManagerImpl.class); addManager("SwiftManager", SwiftManagerImpl.class); addManager("StorageNetworkManager", StorageNetworkManagerImpl.class); + addManager("ExternalLoadBalancerDeviceManager", ExternalLoadBalancerDeviceManagerImpl.class); } @Override diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManager.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManager.java index 02e9a5ea7c6..075e94b21a3 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManager.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManager.java @@ -27,7 +27,6 @@ import com.cloud.host.Host; import com.cloud.network.rules.FirewallRule; import com.cloud.resource.ServerResource; import com.cloud.utils.component.Manager; -import com.cloud.utils.exception.ExecutionException; /* ExternalLoadBalancerDeviceManager provides a abstract implementation for managing a external load balancer in device agnostic manner. * Device specific managers for external load balancers (like F5 and Netscaler) should be implemented as pluggable service extending @@ -101,5 +100,12 @@ public interface ExternalLoadBalancerDeviceManager extends Manager{ */ public boolean manageGuestNetworkWithExternalLoadBalancer(boolean add, Network guestConfig) throws ResourceUnavailableException, InsufficientCapacityException; + + /** + * updates the network usage stats for a LB rule, associated with an external LB device, that is being revoked as part of Delete LB rule or release IP actions + * @param loadBalancerRuleId + */ + public void updateExternalLoadBalancerNetworkUsageStats(long loadBalancerRuleId); + } diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java index 3d616be2e29..e18b876ba9a 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java @@ -28,6 +28,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import javax.ejb.Local; import javax.naming.ConfigurationException; import org.apache.log4j.Logger; @@ -59,7 +60,6 @@ import com.cloud.dc.VlanVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.dc.dao.VlanDao; -import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InsufficientNetworkCapacityException; import com.cloud.exception.InvalidParameterValueException; @@ -128,7 +128,7 @@ import com.cloud.vm.Nic.State; import com.cloud.vm.NicVO; import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.NicDao; - +@Local(value = { ExternalLoadBalancerDeviceManager.class }) public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase implements ExternalLoadBalancerDeviceManager, ResourceStateAdapter { @Inject @@ -1242,6 +1242,130 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase } } } + + @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 = _networkMgr.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; + + if (externalLoadBalancer.getType().equals(Host.Type.ExternalLoadBalancer) && externalLoadBalancerIsInline(externalLoadBalancer)) { + // 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.getIp4Address(); + 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]; + } + + UserStatisticsVO userStats; + final Transaction txn = Transaction.currentTxn(); + try { + txn.start(); + 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); + } + + txn.commit(); + }catch (final Exception e) { + txn.rollback(); + throw new CloudRuntimeException("Problem getting stats after reboot/stop ", e); + } + } + } @Override public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) { diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index d24c7806d5c..3ecb60da8f7 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -52,6 +52,7 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.ExternalLoadBalancerDeviceManager; import com.cloud.network.IPAddressVO; import com.cloud.network.IpAddress; import com.cloud.network.LBStickinessPolicyVO; @@ -156,6 +157,8 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa DomainService _domainMgr; @Inject ConfigurationManager _configMgr; + @Inject + ExternalLoadBalancerDeviceManager _externalLBMgr; private String getLBStickinessCapability(long networkid) { Map> serviceCapabilitiesMap = _networkMgr.getNetworkCapabilities(networkid); @@ -557,9 +560,17 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_LOAD_BALANCER_DELETE, lb.getAccountId(), 0, lb.getId(), null); _usageEventDao.persist(usageEvent); } - - txn.commit(); + txn.commit(); + + //gather external network usage stats for this lb rule + NetworkVO network = _networkDao.findById(lb.getNetworkId()); + if(network != null){ + if (_networkMgr.networkIsConfiguredForExternalNetworking(network.getDataCenterId(), network.getId())) { + _externalLBMgr.updateExternalLoadBalancerNetworkUsageStats(loadBalancerId); + } + } + if (apply) { try { if (!applyLoadBalancerConfig(loadBalancerId)) { @@ -589,6 +600,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa return success; } + @Override @ActionEvent(eventType = EventTypes.EVENT_LOAD_BALANCER_CREATE, eventDescription = "creating load balancer") public LoadBalancer createLoadBalancerRule(CreateLoadBalancerRuleCmd lb, boolean openFirewall) throws NetworkRuleConflictException, InsufficientAddressCapacityException {