package org.openstack.atlas.usagerefactor.processor.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openstack.atlas.service.domain.entities.AccountUsage;
import org.openstack.atlas.service.domain.entities.LoadBalancer;
import org.openstack.atlas.service.domain.entities.Usage;
import org.openstack.atlas.service.domain.entities.VirtualIpType;
import org.openstack.atlas.service.domain.events.UsageEvent;
import org.openstack.atlas.service.domain.exceptions.EntityNotFoundException;
import org.openstack.atlas.service.domain.repository.AccountUsageRepository;
import org.openstack.atlas.service.domain.repository.LoadBalancerRepository;
import org.openstack.atlas.service.domain.repository.UsageRepository;
import org.openstack.atlas.service.domain.repository.VirtualIpRepository;
import org.openstack.atlas.service.domain.services.LoadBalancerService;
import org.openstack.atlas.service.domain.services.NotificationService;
import org.openstack.atlas.service.domain.services.UsageRefactorService;
import org.openstack.atlas.service.domain.services.helpers.AlertType;
import org.openstack.atlas.service.domain.usage.BitTag;
import org.openstack.atlas.service.domain.usage.BitTags;
import org.openstack.atlas.service.domain.usage.entities.LoadBalancerHostUsage;
import org.openstack.atlas.service.domain.usage.entities.LoadBalancerMergedHostUsage;
import org.openstack.atlas.usagerefactor.SnmpUsage;
import org.openstack.atlas.usagerefactor.processor.UsageEventProcessor;
import org.openstack.atlas.usagerefactor.processor.mapper.UsageEventMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import static org.openstack.atlas.service.domain.events.UsageEvent.*;
@Component
public class UsageEventProcessorImpl implements UsageEventProcessor {
private final Log LOG = LogFactory.getLog(UsageEventProcessorImpl.class);
protected UsageRefactorService usageRefactorService;
protected VirtualIpRepository virtualIpRepository;
protected LoadBalancerRepository loadBalancerRepository;
protected AccountUsageRepository accountUsageRepository;
protected UsageRepository usageRepository;
protected LoadBalancerService loadBalancerService;
protected NotificationService notificationService;
private class TagsBitMaskAndNumVips {
public int tagsBitmask = 1;
public int numVips = 1;
}
@Autowired
public void setLoadBalancerRepository(LoadBalancerRepository loadBalancerRepository) {
this.loadBalancerRepository = loadBalancerRepository;
}
@Autowired
public void setAccountUsageRepository(AccountUsageRepository accountUsageRepository) {
this.accountUsageRepository = accountUsageRepository;
}
@Autowired
public void setVirtualIpRepository(VirtualIpRepository virtualIpRepository) {
this.virtualIpRepository = virtualIpRepository;
}
@Autowired
public void setUsageRefactorService(UsageRefactorService usageRefactorService) {
this.usageRefactorService = usageRefactorService;
}
@Autowired
public void setUsageRepository(UsageRepository usageRepository) {
this.usageRepository = usageRepository;
}
@Autowired
public void setLoadBalancerService(LoadBalancerService loadBalancerService) {
this.loadBalancerService = loadBalancerService;
}
@Autowired
public void setNotificationService(NotificationService notificationService) {
this.notificationService = notificationService;
}
@Override
public void processUsageEvent(List<SnmpUsage> usages, LoadBalancer loadBalancer, UsageEvent usageEvent, Calendar pollTime) {
LOG.info(String.format("Processing '%s' usage event for load balancer '%d'...", usageEvent.name(),
loadBalancer.getId()));
int tagsBitmask = loadBalancerService.getCurrentBitTags(loadBalancer.getId()).toInt();
int numVips = virtualIpRepository.getNumIpv4VipsForLoadBalancer(loadBalancer).intValue();
List<LoadBalancerHostUsage> usageRecordsToCreate = new ArrayList<LoadBalancerHostUsage>();
//If for whatever reason there were no usage records returned by any hosts for this load balancer, insert 1 record with -1 values for bandwidth
//and the event type.
if (usages.isEmpty()) {
notificationService.saveAlert(loadBalancer.getAccountId(), loadBalancer.getId(), new EntityNotFoundException(),
AlertType.USAGE_FAILURE.name(), String.format("Usage processing for %s event failed because no hosts returned " +
"usage for this load balancer. Inserting -1 for bandwidth and event anyway.", usageEvent.name()));
SnmpUsage phantomUsage = new SnmpUsage();
phantomUsage.setConcurrentConnections(0);
phantomUsage.setConcurrentConnectionsSsl(0);
phantomUsage.setBytesIn(-1L);
phantomUsage.setBytesOut(-1L);
phantomUsage.setBytesInSsl(-1L);
phantomUsage.setBytesOutSsl(-1L);
phantomUsage.setHostId(loadBalancer.getHost().getId());
phantomUsage.setLoadbalancerId(loadBalancer.getId());
LoadBalancerHostUsage usageRecordToProcess = new UsageEventMapper(loadBalancer, phantomUsage, usageEvent, pollTime, tagsBitmask, 0).mapSnmpUsageToUsageEvent();
usageRefactorService.createUsageEvent(usageRecordToProcess);
}
for (SnmpUsage usage : usages) {
LoadBalancerHostUsage usageRecordToProcess;
LOG.info(String.format("Creating usage event for load balancer '%d'...", loadBalancer.getId()));
usageRecordToProcess = new UsageEventMapper(loadBalancer, usage, usageEvent, pollTime, tagsBitmask, numVips)
.mapSnmpUsageToUsageEvent();
if(usageEvent == UsageEvent.DELETE_LOADBALANCER) {
usageRecordToProcess.setNumVips(0);
}
usageRecordsToCreate.add(usageRecordToProcess);
LOG.info(String.format("Added usage record for load balancer id '%d' to list to be inserted.",
loadBalancer.getId()));
}
if(!usageRecordsToCreate.isEmpty()){
for (LoadBalancerHostUsage hostUsage : usageRecordsToCreate) {
LOG.info(String.format("Inserting record into lb_host_usage table: \n%s", hostUsage.toString()));
}
usageRefactorService.batchCreateLoadBalancerHostUsages(usageRecordsToCreate);
} else {
LOG.warn(String.format("There were no usage records created for load balancer %d for event %s. " +
"This is probably a problem.", loadBalancer.getId(), usageEvent.toString()));
}
LOG.info(String.format("Successfully inserted '%d' usage records into lb_host_usage table.", usageRecordsToCreate.size()));
// If account specific event then go ahead and create entry in account usage table
if (usageEvent.equals(CREATE_LOADBALANCER) || usageEvent.equals(DELETE_LOADBALANCER)
|| usageEvent.equals(CREATE_VIRTUAL_IP) || usageEvent.equals(DELETE_VIRTUAL_IP)) {
LOG.info(String.format("Creating account usage event for load balancer '%d'...",
loadBalancer.getId()));
createAccountUsageEntry(loadBalancer, pollTime);
LOG.info(String.format("Successfully created account usage event for load balancer '%d'...",
loadBalancer.getId()));
}
LOG.debug(String.format("Finished processing '%s' usage event for load balancer '%d'...",
usageEvent.name(), loadBalancer.getId()));
}
@Override
public AccountUsage createAccountUsageEntry(LoadBalancer loadBalancer, Calendar eventTime) {
Integer accountId = loadBalancer.getAccountId();
AccountUsage usage = new AccountUsage();
usage.setAccountId(accountId);
usage.setStartTime(eventTime);
usage.setNumLoadBalancers(loadBalancerRepository.getNumNonDeletedLoadBalancersForAccount(accountId));
usage.setNumPublicVips(virtualIpRepository.getNumUniqueVipsForAccount(accountId, VirtualIpType.PUBLIC));
usage.setNumServicenetVips(virtualIpRepository.getNumUniqueVipsForAccount(accountId, VirtualIpType.SERVICENET));
accountUsageRepository.save(usage);
return usage;
}
private boolean isInvalidUsage(SnmpUsage usage, UsageEvent usageEvent) {
return usage.getBytesOut() == -1 && usage.getBytesOutSsl() == -1 && usage.getBytesIn() == -1 &&
usage.getBytesInSsl() == -1 && usageEvent != UsageEvent.DELETE_LOADBALANCER;
}
private void setNegativeUsageToZero(SnmpUsage usage) {
if(usage.getBytesOut() < 0L){
usage.setBytesOut(0L);
}
if(usage.getBytesOutSsl() < 0L){
usage.setBytesOutSsl(0L);
}
if(usage.getBytesIn() < 0L){
usage.setBytesIn(0L);
}
if(usage.getBytesInSsl() < 0L){
usage.setBytesInSsl(0L);
}
if(usage.getConcurrentConnections() < 0){
usage.setConcurrentConnections(0);
}
if(usage.getConcurrentConnectionsSsl() < 0){
usage.setConcurrentConnectionsSsl(0);
}
}
}