package org.openstack.atlas.service.domain.services.impl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openstack.atlas.service.domain.entities.*; import org.openstack.atlas.service.domain.exceptions.*; import org.openstack.atlas.service.domain.services.HealthMonitorService; import org.openstack.atlas.service.domain.services.LoadBalancerStatusHistoryService; import org.openstack.atlas.service.domain.services.helpers.NodesPrioritiesContainer; import org.openstack.atlas.service.domain.services.helpers.StringHelper; import org.openstack.atlas.service.domain.util.Constants; 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; @Service public class HealthMonitorServiceImpl extends BaseService implements HealthMonitorService { private final Log LOG = LogFactory.getLog(HealthMonitorServiceImpl.class); @Autowired private LoadBalancerStatusHistoryService loadBalancerStatusHistoryService; @Override public HealthMonitor get(Integer accountId, Integer lbId) throws EntityNotFoundException, DeletedStatusException { return loadBalancerRepository.getHealthMonitor(accountId, lbId); } @Override @Transactional(rollbackFor = {EntityNotFoundException.class, ImmutableEntityException.class, UnprocessableEntityException.class, BadRequestException.class}) public void update(LoadBalancer requestLb) throws EntityNotFoundException, ImmutableEntityException, UnprocessableEntityException, BadRequestException { LOG.debug("Entering " + getClass()); LoadBalancer dbLoadBalancer = loadBalancerRepository.getByIdAndAccountId(requestLb.getId(), requestLb.getAccountId()); HealthMonitor requestMonitor = requestLb.getHealthMonitor(); HealthMonitor dbMonitor = dbLoadBalancer.getHealthMonitor(); HealthMonitor monitorToUpdate = dbMonitor == null ? new HealthMonitor() : dbMonitor; monitorToUpdate.setLoadbalancer(dbLoadBalancer); // Needs to be set verifyMonitorProtocol(requestMonitor, dbLoadBalancer, dbMonitor); if (requestMonitor.getType().equals(HealthMonitorType.CONNECT)) { if (requestMonitor.getPath() != null || requestMonitor.getStatusRegex() != null || requestMonitor.getBodyRegex() != null) { throw new BadRequestException("Updating to CONNECT monitor. Please provide the required fields only."); } setConnectMonitorProperties(requestMonitor, dbMonitor, monitorToUpdate); } else { if ((requestMonitor.getType().equals(HealthMonitorType.HTTP) || requestMonitor.getType().equals(HealthMonitorType.HTTPS)) && requestMonitor.getPath() == null) { throw new BadRequestException("Updating to HTTP/HTTPS monitor. Please provide all required fields."); } setHttpMonitorProperties(requestMonitor, dbMonitor, monitorToUpdate); } LOG.debug("Updating the lb status to pending_update"); if (!loadBalancerRepository.testAndSetStatus(dbLoadBalancer.getAccountId(), dbLoadBalancer.getId(), LoadBalancerStatus.PENDING_UPDATE, false)) { String message = StringHelper.immutableLoadBalancer(dbLoadBalancer); LOG.warn(message); throw new ImmutableEntityException(message); } else { //Set status record loadBalancerStatusHistoryService.save(dbLoadBalancer.getAccountId(), dbLoadBalancer.getId(), LoadBalancerStatus.PENDING_UPDATE); } dbLoadBalancer.setHealthMonitor(monitorToUpdate); loadBalancerRepository.update(dbLoadBalancer); LOG.debug("Leaving " + getClass()); } @Override public void verifyMonitorProtocol(HealthMonitor requestMonitor, LoadBalancer dbLoadBalancer, HealthMonitor dbMonitor) throws BadRequestException { if (requestMonitor.getType() != null) { if (dbLoadBalancer.getProtocol().equals(LoadBalancerProtocol.DNS_UDP) || dbLoadBalancer.getProtocol().equals(LoadBalancerProtocol.UDP) || dbLoadBalancer.getProtocol().equals(LoadBalancerProtocol.UDP_STREAM)) { throw new BadRequestException("Protocol UDP, UDP_STREAM and DNS_UDP are not allowed with health monitors. "); } if (requestMonitor.getType().equals(HealthMonitorType.HTTP)) { if (!(dbLoadBalancer.getProtocol().name().equals(LoadBalancerProtocol.HTTP.name()))) { throw new BadRequestException("Cannot update Health Monitor to Type HTTP because load balancer protocol is " + dbLoadBalancer.getProtocol().name()); } } else if (requestMonitor.getType().equals(HealthMonitorType.HTTPS)) { if (!(dbLoadBalancer.getProtocol().name().equals(LoadBalancerProtocol.HTTPS.name()))) { throw new BadRequestException("Cannot update Health Monitor to Type HTTPS because load balancer protocol is " + dbLoadBalancer.getProtocol().name()); } } } else { throw new BadRequestException("Must provide a type for the request"); } } @Override @Transactional(rollbackFor = {EntityNotFoundException.class, ImmutableEntityException.class, UnprocessableEntityException.class}) public void prepareForDeletion(LoadBalancer requestLb) throws EntityNotFoundException, UnprocessableEntityException, ImmutableEntityException, BadRequestException { LOG.debug("Entering " + getClass()); LoadBalancer dbLb = loadBalancerRepository.getByIdAndAccountId(requestLb.getId(), requestLb.getAccountId()); isLbActive(dbLb); // we won't allowed to delete a health monitor if it has Secondary nodes NodesPrioritiesContainer npc = new NodesPrioritiesContainer(dbLb.getNodes()); if (npc.hasSecondary()) { throw new BadRequestException(Constants.WontDeleteMonitorCauseSecNodes); } if (dbLb.getHealthMonitor() == null) { throw new UnprocessableEntityException("No health monitor found to delete."); } LOG.debug("Updating the lb status to pending_update"); if (!loadBalancerRepository.testAndSetStatus(dbLb.getAccountId(), dbLb.getId(), LoadBalancerStatus.PENDING_UPDATE, false)) { String message = StringHelper.immutableLoadBalancer(dbLb); LOG.warn(message); throw new ImmutableEntityException(message); } else { //Set status record loadBalancerStatusHistoryService.save(dbLb.getAccountId(), dbLb.getId(), LoadBalancerStatus.PENDING_UPDATE); } } @Override @Transactional public void delete(LoadBalancer requestLb) throws EntityNotFoundException, Exception { LoadBalancer dbLb = loadBalancerRepository.getByIdAndAccountId(requestLb.getId(), requestLb.getAccountId()); for (Node node : dbLb.getNodes()) { if (node.getCondition().equals(NodeCondition.ENABLED)) node.setStatus(NodeStatus.ONLINE); } loadBalancerRepository.update(dbLb); loadBalancerRepository.removeHealthMonitor(dbLb); } private void setHttpMonitorProperties(HealthMonitor requestMonitor, HealthMonitor dbMonitor, HealthMonitor newMonitor) throws BadRequestException { setConnectMonitorProperties(requestMonitor, dbMonitor, newMonitor); if (requestMonitor.getPath() != null) { newMonitor.setPath(requestMonitor.getPath()); } else if (dbMonitor != null && dbMonitor.getPath() != null && dbMonitor.getPath().length() > 0) { newMonitor.setPath(dbMonitor.getPath()); } else { throw new BadRequestException("Must provide a path for the request"); } if (requestMonitor.getStatusRegex() != null) { newMonitor.setStatusRegex(requestMonitor.getStatusRegex()); } else if (dbMonitor != null && dbMonitor.getStatusRegex() != null && dbMonitor.getStatusRegex().length() > 0) { newMonitor.setStatusRegex(dbMonitor.getStatusRegex()); } else { newMonitor.setStatusRegex(null); } if (requestMonitor.getBodyRegex() != null) { newMonitor.setBodyRegex(requestMonitor.getBodyRegex()); } else if (dbMonitor != null && dbMonitor.getBodyRegex() != null && dbMonitor.getBodyRegex().length() > 0) { newMonitor.setBodyRegex(dbMonitor.getBodyRegex()); } else { newMonitor.setBodyRegex(null); } if (requestMonitor.getHostHeader() != null) { newMonitor.setHostHeader(requestMonitor.getHostHeader()); } else if (dbMonitor != null && dbMonitor.getHostHeader() != null) { newMonitor.setHostHeader(dbMonitor.getHostHeader()); } else { newMonitor.setHostHeader(null); } } private void setConnectMonitorProperties(HealthMonitor requestMonitor, HealthMonitor dbMonitor, HealthMonitor newMonitor) throws BadRequestException { if (requestMonitor.getType() != null) { newMonitor.setType(requestMonitor.getType()); } else if (dbMonitor != null) { newMonitor.setType(dbMonitor.getType()); } else { throw new BadRequestException("Must provide a type for the request"); } if (requestMonitor.getDelay() != null) { newMonitor.setDelay(requestMonitor.getDelay()); } else if (dbMonitor != null) { newMonitor.setDelay(dbMonitor.getDelay()); } else { throw new BadRequestException("Must provide a delay for the request"); } if (requestMonitor.getTimeout() != null) { newMonitor.setTimeout(requestMonitor.getTimeout()); } else if (dbMonitor != null) { newMonitor.setTimeout(dbMonitor.getTimeout()); } else { throw new BadRequestException("Must provide a timeout for the request"); } if (requestMonitor.getAttemptsBeforeDeactivation() != null) { newMonitor.setAttemptsBeforeDeactivation(requestMonitor.getAttemptsBeforeDeactivation()); } else if (dbMonitor != null) { newMonitor.setAttemptsBeforeDeactivation(dbMonitor.getAttemptsBeforeDeactivation()); } else { throw new BadRequestException("Must provide attemptsBeforeActivation for the request"); } newMonitor.setPath(null); newMonitor.setStatusRegex(null); newMonitor.setBodyRegex(null); } }