package org.openstack.atlas.service.domain.services.impl;
import org.openstack.atlas.service.domain.entities.*;
import org.openstack.atlas.service.domain.exceptions.*;
import org.openstack.atlas.service.domain.services.AccessListService;
import org.openstack.atlas.service.domain.services.AccountLimitService;
import org.openstack.atlas.service.domain.services.LoadBalancerStatusHistoryService;
import org.openstack.atlas.service.domain.services.helpers.StringHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openstack.atlas.util.ip.exception.IPStringConversionException;
import org.openstack.atlas.util.ip.exception.IpTypeMissMatchException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
@Service
public class AccessListServiceImpl extends BaseService implements AccessListService {
private final Log LOG = LogFactory.getLog(AccessListServiceImpl.class);
@Autowired
private AccountLimitService accountLimitService;
@Autowired
private LoadBalancerStatusHistoryService loadBalancerStatusHistoryService;
@Override
public List<AccessList> getAccessListByAccountIdLoadBalancerId(int accountId, int loadbalancerId, Integer... p) throws EntityNotFoundException, DeletedStatusException {
return loadBalancerRepository.getAccessListByAccountIdLoadBalancerId(accountId, loadbalancerId, p);
}
@Override
@Transactional(rollbackFor = {Exception.class})
public LoadBalancer updateAccessList(LoadBalancer rLb) throws EntityNotFoundException, ImmutableEntityException, BadRequestException, UnprocessableEntityException {
String msg;
String format;
LoadBalancer dLb;
String className = AccessListServiceImpl.class.getName();
try {
dLb = loadBalancerRepository.getByIdAndAccountId(rLb.getId(), rLb.getAccountId());
} catch (EntityNotFoundException ex) {
Logger.getLogger(className).log(Level.SEVERE, null, ex);
throw ex;
}
LOG.debug("Updating the lb status to pending_update");
if(!loadBalancerRepository.testAndSetStatus(dLb.getAccountId(), dLb.getId(), LoadBalancerStatus.PENDING_UPDATE, false)) {
String message = StringHelper.immutableLoadBalancer(dLb);
LOG.warn(message);
throw new ImmutableEntityException(message);
} else {
//Set status record
loadBalancerStatusHistoryService.save(dLb.getAccountId(), dLb.getId(), LoadBalancerStatus.PENDING_UPDATE);
}
Integer aListTotal = dLb.getAccessLists().size() + rLb.getAccessLists().size();
Integer accessListLimit = accountLimitService.getLimit(dLb.getAccountId(), AccountLimitType.ACCESS_LIST_LIMIT);
if (aListTotal > accessListLimit) {
throw new BadRequestException(String.format("Access list size must not exceed %d items.", accessListLimit));
}
if (hasDupeIpInAccessLists(dLb.getAccessLists(), rLb.getAccessLists())) {
throw new BadRequestException("Must supply a unique access list item to update the current list.");
}
try {
AccessList badAccessList = blackListedItemAccessList(rLb.getAccessLists());
if (badAccessList != null) {
throw new BadRequestException(String.format("Invalid network item address. The address '%s' is currently not accepted for this request.", badAccessList.getIpAddress()));
}
} catch (IPStringConversionException ipe) {
LOG.warn("IPStringConversionException thrown. Sending error response to client...");
throw new BadRequestException("IP address was not converted properly, we are unable to process this request.");
} catch (IpTypeMissMatchException ipte) {
LOG.warn("EntityNotFoundException thrown. Sending error response to client...");
throw new BadRequestException("IP addresses type are mismatched, we are unable to process this request.");
}
for (AccessList al : rLb.getAccessLists()) {
dLb.addAccessList(al);
}
return rLb;
}
// Deletes all AccessLists for this Lb
@Transactional
@Override
public LoadBalancer markForDeletionAccessList(LoadBalancer rLb) throws EntityNotFoundException, ImmutableEntityException, DeletedStatusException, UnprocessableEntityException {
String format;
String msg;
List<AccessList> al = new ArrayList<AccessList>();
LoadBalancer dLb;
String className = this.getClass().getName();
al = loadBalancerRepository.getAccessListByAccountIdLoadBalancerId(rLb.getAccountId(), rLb.getId(), 0, 1);
if (al.isEmpty()) {
throw new UnprocessableEntityException("No access list found to delete");
}
dLb = loadBalancerRepository.getByIdAndAccountId(rLb.getId(), rLb.getAccountId());
format = "Pre Zxtm updateing Lb[%d] to PENDING_DELETE while deleting accesslists";
msg = String.format(format, rLb.getId());
dLb.setStatus(LoadBalancerStatus.PENDING_UPDATE);
loadBalancerRepository.update(dLb);
//Set status record
loadBalancerStatusHistoryService.save(dLb.getAccountId(), dLb.getId(), LoadBalancerStatus.PENDING_UPDATE);
return rLb;
}
@Override
@Transactional
public Set<AccessList> getNetworkItemsByIdList(int loadbalancerId, int accountId, List<Integer> networkItemIds) throws DeletedStatusException, EntityNotFoundException {
List<AccessList> list = loadBalancerRepository.getAccessListByAccountIdLoadBalancerId(accountId, loadbalancerId);
Set<AccessList> retSet = new HashSet<AccessList>();
for (AccessList item : list) {
if (networkItemIds.contains(item.getId())) {
retSet.add(item);
}
}
return retSet;
}
@Override
@Transactional
public LoadBalancer markForDeletionNetworkItems(LoadBalancer returnLB, List<Integer> networkItemIds) throws BadRequestException, ImmutableEntityException, EntityNotFoundException {
LoadBalancer domainLB;
List<AccessList> accessLists = new ArrayList<AccessList>();
LOG.debug("Entering " + getClass());
domainLB = loadBalancerRepository.getByIdAndAccountId(returnLB.getId(), returnLB.getAccountId());
if (!isActiveLoadBalancer(domainLB, false)) {
String message = StringHelper.immutableLoadBalancer(domainLB);
LOG.warn(message);
throw new ImmutableEntityException(message);
}
List<Integer> badList = new ArrayList<Integer>();
for (Integer networkItemId : networkItemIds) {
boolean isFound = false;
for (AccessList al : domainLB.getAccessLists()) {
if (networkItemId.equals(al.getId())) {
isFound = true;
accessLists.add(al);
}
}
if (!isFound) {
badList.add(networkItemId);
}
}
if (badList.size() != 0) {
String outList = "";
for (Integer list : badList) {
outList += list + ", ";
}
String out = outList.substring(0, outList.length() - 2);
String plural = "";
if (badList.size() > 1) {
plural = "s";
}
throw new BadRequestException("Network item" + plural + " with id" + plural + " " + out + " not found.");
}
domainLB.getAccessLists().removeAll(accessLists);
LOG.debug("Updating the lb status to pending_update");
domainLB.setStatus(LoadBalancerStatus.PENDING_UPDATE);
returnLB.getAccessLists().clear();
returnLB.getAccessLists().addAll(domainLB.getAccessLists());
loadBalancerRepository.update(domainLB);
//Set status record
loadBalancerStatusHistoryService.save(domainLB.getAccountId(), domainLB.getId(), LoadBalancerStatus.PENDING_UPDATE);
return returnLB;
}
@Transactional
@Override
public LoadBalancer markForDeletionNetworkItem(LoadBalancer rLb) throws EntityNotFoundException, ImmutableEntityException {
AccessList ai;
LoadBalancer dLb = null;
Integer nid = null;
LOG.debug("Entering " + getClass());
for (AccessList ni : rLb.getAccessLists()) {
nid = ni.getId();
break;
}
// If the network item doesn't exist on this account or loadbalancer puke an EntityNotFound
try {
ai = loadBalancerRepository.getNetworkItemByAccountIdLoadBalancerIdNetworkItemId(rLb.getAccountId(), rLb.getId(), nid);
dLb = ai.getLoadbalancer();
} catch (EntityNotFoundException ex) {
LOG.warn("EntityNotFoundException thrown. Sending error response to client...");
throw ex;
}
if (!isActiveLoadBalancer(dLb, false)) {
String message = StringHelper.immutableLoadBalancer(dLb);
LOG.warn(message);
throw new ImmutableEntityException(message);
}
LOG.debug("Updating the lb status to pending_update");
dLb.setStatus(LoadBalancerStatus.PENDING_UPDATE);
dLb.getAccessLists().remove(ai);
rLb.getAccessLists().clear();
rLb.getAccessLists().add(ai);
loadBalancerRepository.update(dLb);
return rLb;
}
@Override
public Set<AccessList> diffRequestAccessListWithDomainAccessList(LoadBalancer rLb, LoadBalancer dLb) {
boolean alInRlb;
boolean alInDlb;
Set<AccessList> out = new HashSet<AccessList>();
Map<String, AccessList> alMap = new HashMap<String, AccessList>();
for (AccessList al : dLb.getAccessLists()) {
String ip = al.getIpAddress();
String type = al.getType().name();
String key = String.format("%s:%s", ip, type);
alMap.put(key, al);
}
for (AccessList al : rLb.getAccessLists()) {
String ip = al.getIpAddress();
String type = al.getType().name();
String key = String.format("%s:%s", ip, type);
alInRlb = (al.getId() != null);
alInDlb = alMap.containsKey(key);
if(alInRlb == alInDlb) {
continue; // No Difference so don't add
}
if(alInRlb){
out.add(al);
}else{// We already know alInDlb at this point
out.add(alMap.get(key));
}
}
return out;
}
private boolean hasDupeIpInAccessLists(Set<AccessList>... als) {
boolean out;
int i;
Set<String> ipSet = new HashSet<String>();
String ip;
for (i = 0; i < als.length; i++) {
for (AccessList al : als[i]) {
ip = al.getIpAddress();
if (ipSet.contains(ip)) {
out = true;
return out;
}
ipSet.add(ip);
}
}
out = false;
return out;
}
}