package org.openstack.atlas.api.mgmt.resources;
import java.util.ArrayList;
import java.util.HashSet;
import org.openstack.atlas.docs.loadbalancers.api.management.v1.*;
import org.openstack.atlas.lb.helpers.ipstring.exceptions.IPOctetOutOfRangeException;
import org.openstack.atlas.lb.helpers.ipstring.exceptions.IPStringConversionException;
import org.openstack.atlas.service.domain.entities.AccountLimit;
import org.openstack.atlas.service.domain.pojos.LoadBalancerCountByAccountIdClusterId;
import org.openstack.atlas.service.domain.pojos.Hostssubnet;
import org.openstack.atlas.service.domain.pojos.Hostsubnet;
import org.openstack.atlas.service.domain.pojos.NetInterface;
import static org.openstack.atlas.util.ip.IPUtils.isValidIpv4Subnet;
import static org.openstack.atlas.util.ip.IPUtils.isValidIpv6Subnet;
import org.openstack.atlas.lb.helpers.ipstring.IPv4Range;
import org.openstack.atlas.lb.helpers.ipstring.IPv4Ranges;
import org.openstack.atlas.lb.helpers.ipstring.IPv4ToolSet;
import org.openstack.atlas.util.ip.IPv4Cidrs;
import org.openstack.atlas.util.ip.IPv6Cidrs;
import org.openstack.atlas.util.ip.IPv4Cidr;
import org.openstack.atlas.util.ip.IPv6Cidr;
import org.openstack.atlas.service.domain.services.helpers.AlertType;
import org.openstack.atlas.api.faults.HttpResponseBuilder;
import org.openstack.atlas.api.helpers.ResponseFactory;
import org.openstack.atlas.api.mgmt.mapper.dozer.DomainToRestModel;
import org.openstack.atlas.api.mgmt.repository.ValidatorRepository;
import org.openstack.atlas.api.mgmt.resources.providers.ManagementDependencyProvider;
import org.openstack.atlas.api.validation.context.HttpRequestType;
import org.openstack.atlas.api.validation.results.ValidatorResult;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openstack.atlas.docs.loadbalancers.api.v1.faults.BadRequest;
import org.openstack.atlas.util.ip.IPUtils;
public class ClusterResource extends ManagementDependencyProvider {
private final Log LOG = LogFactory.getLog(ClusterResource.class);
private VirtualIpsResource virtualIpsResource;
private ErrorpageResource errorpageResource;
private int id;
@GET // Jira:https://jira.mosso.com/browse/SITESLB-231
@Path("customercount")
public Response getCustomersCounts() {
if (!isUserInRole("cp,ops,support")) {
return ResponseFactory.accessDenied();
}
List<LoadBalancerCountByAccountIdClusterId> daccountsInCluster;
AccountsInCluster accountsInCluster = new AccountsInCluster();
AccountInCluster accountInCluster;
try {
daccountsInCluster = clusterService.getAccountsInCluster(id);
for (LoadBalancerCountByAccountIdClusterId daccountInCluster : daccountsInCluster) {
accountInCluster = getDozerMapper().map(daccountInCluster, AccountInCluster.class);
accountsInCluster.getAccountInClusters().add(accountInCluster);
}
accountsInCluster.setTotalAccounts(daccountsInCluster.size());
return Response.status(200).entity(accountsInCluster).build();
} catch (Exception e) {
return ResponseFactory.getErrorResponse(e, null, null);
}
}
@Path("errorpage")
public ErrorpageResource retrieveErrorPageResource() {
errorpageResource.setClusterId(id);
return errorpageResource;
}
@GET
@Path("hosts")
public Response getClusterHosts() {
if (!isUserInRole("cp,ops,support")) {
return ResponseFactory.accessDenied();
}
Hosts rHosts = new Hosts();
List<org.openstack.atlas.service.domain.entities.Host> dHosts;
try {
dHosts = clusterService.getHosts(id);
for (org.openstack.atlas.service.domain.entities.Host dHost : dHosts) {
rHosts.getHosts().add(getDozerMapper().map(dHost, Host.class));
}
} catch (Exception ex) {
return ResponseFactory.getErrorResponse(ex, null, null);
}
return Response.status(200).entity(rHosts).build();
}
@GET
@Path("virtualips")
public Response getVirtualIpsDetails(@QueryParam("offset") Integer offset, @QueryParam("limit") Integer limit) {
if (!isUserInRole("cp,ops,support")) {
return ResponseFactory.accessDenied();
}
VirtualIps rVips = new VirtualIps();
List<org.openstack.atlas.service.domain.entities.VirtualIp> dVips;
try {
dVips = clusterService.getVirtualIps(id, offset, limit);
for (org.openstack.atlas.service.domain.entities.VirtualIp dVip : dVips) {
rVips.getVirtualIps().add(getDozerMapper().map(dVip, VirtualIp.class));
}
} catch (Exception ex) {
return ResponseFactory.getErrorResponse(ex, null, null);
}
return Response.status(200).entity(rVips).build();
}
@POST
@Path("virtualipblocks")
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response addVirtualIpBlocks(VirtualIpBlocks vBlocks) {
if (!isUserInRole("cp,ops")) {
return ResponseFactory.accessDenied();
}
if(vBlocks == null){
String error = "VirtualIpBlocks must not be null";
return getValidationFaultResponse(error);
}
try {
IPv4Cidrs ipv4Cidrs = getIpv4SubnetCidrs(id);
List<String> errors = getIpsNotContainedInASubnet(vBlocks, ipv4Cidrs);
if(!errors.isEmpty()){
return getValidationFaultResponse(errors);
}
clusterService.addVirtualIpBlocks(getDozerMapper().map(vBlocks, org.openstack.atlas.service.domain.pojos.VirtualIpBlocks.class), id);
return Response.status(200).entity(vBlocks).build();
} catch (Exception ex) {
LOG.error(ex);
return ResponseFactory.getErrorResponse(ex, null, null);
}
}
@GET
@Path("activeratelimits")
public Response getActiveRateLimitsInCluster() {
if (!isUserInRole("cp,ops,support")) {
return ResponseFactory.accessDenied();
}
Integer clusterId = id;
List<ZeusRateLimitedLoadBalancer> zeusRateLimitedLoadBalancerList;
ZeusRateLimitedLoadBalancers zeusRateLimitedLoadBalancers = new ZeusRateLimitedLoadBalancers();
try {
zeusRateLimitedLoadBalancerList = clusterService.getRateLimitedLoadBalancersInCluster(clusterId);
} catch (Exception e) {
return ResponseFactory.getErrorResponse(e, null, null);
}
zeusRateLimitedLoadBalancers.getZeusRateLimitedLoadBalancers().addAll(zeusRateLimitedLoadBalancerList);
return Response.status(200).entity(zeusRateLimitedLoadBalancers).build();
}
@GET
@Path("apiratelimit")
public Response getApiRateLimitsForCluster() {
if (!isUserInRole("cp,ops,support")) {
return ResponseFactory.accessDenied();
}
List<org.openstack.atlas.service.domain.entities.AccountGroup> domainAccountGroups;
AccountGroups acGroups = new AccountGroups();
org.openstack.atlas.docs.loadbalancers.api.management.v1.AccountGroup accountGroup;
try {
domainAccountGroups = clusterService.getAPIRateLimitedAccounts(id);
for (org.openstack.atlas.service.domain.entities.AccountGroup lbg : domainAccountGroups) {
accountGroup = dozerMapper.map(lbg, org.openstack.atlas.docs.loadbalancers.api.management.v1.AccountGroup.class);
acGroups.getAccountGroups().add(accountGroup);
}
return Response.status(200).entity(acGroups).build();
} catch (Exception e) {
return ResponseFactory.getErrorResponse(e, null, null);
}
}
@GET
@Path("customlimitaccounts")
public Response getAbsoluteRateLimitsInCluster() {
if (!isUserInRole("cp,ops,support")) {
return ResponseFactory.accessDenied();
}
Map<Integer, List<AccountLimit>> clusterLimitAccounts = accountLimitService.getAccountLimitsForCluster(id);
return Response.status(200).entity(DomainToRestModel.customLimitAccountsInClusterMapToCustomLimitAccounts(clusterLimitAccounts)).build();
}
@GET
@Path("endpoint")
public Response getClusterSoapEndPoint() {
if (!isUserInRole("cp,ops,support")) {
return ResponseFactory.accessDenied();
}
Integer clusterId = id;
org.openstack.atlas.docs.loadbalancers.api.management.v1.Host rHost;
org.openstack.atlas.service.domain.entities.Host dHost;
try {
dHost = hostService.getEndPointHost(clusterId);
rHost = getDozerMapper().map(dHost, org.openstack.atlas.docs.loadbalancers.api.management.v1.Host.class);
} catch (Exception ex) {
return ResponseFactory.getErrorResponse(ex, null, null);
}
return Response.status(200).entity(rHost).build();
}
@GET
@Path("virtualips/availabilityreport")
public Response retrieveCapacityReports() {
if (!isUserInRole("cp,ops,support")) {
return ResponseFactory.accessDenied();
}
List<org.openstack.atlas.service.domain.pojos.VirtualIpAvailabilityReport> dVipReports;
VirtualIpAvailabilityReport rVipReport;
VirtualIpAvailabilityReports rVipReports = new VirtualIpAvailabilityReports();
dVipReports = clusterService.getVirtualIpAvailabilityReport(id);
for (org.openstack.atlas.service.domain.pojos.VirtualIpAvailabilityReport dr : dVipReports) {
org.openstack.atlas.docs.loadbalancers.api.management.v1.VirtualIpAvailabilityReport rr;
rr = getDozerMapper().map(dr, org.openstack.atlas.docs.loadbalancers.api.management.v1.VirtualIpAvailabilityReport.class);
rVipReports.getVirtualIpAvailabilityReports().add(rr);
}
return Response.status(200).entity(rVipReports).build();
}
@POST
@Path("virtualips")
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response createClusterVirtualIps(VirtualIps vips) {
if (!isUserInRole("cp,ops")) {
return ResponseFactory.accessDenied();
}
ValidatorResult result = ValidatorRepository.getValidatorFor(VirtualIps.class).validate(vips, HttpRequestType.POST);
for (VirtualIp vip : vips.getVirtualIps()) {
vip.setClusterId(id);
}
if (!result.passedValidation()) {
return Response.status(400).entity(HttpResponseBuilder.buildBadRequestResponse("Validation fault", result.getValidationErrorMessages())).build();
}
return Response.status(Response.Status.ACCEPTED).entity(String.format("We are currently provisioning your virtual ips into Cluster %d", id)).build();
}
@GET
public Response retrieveCluster() {
org.openstack.atlas.service.domain.entities.Cluster domainCl;
if (!isUserInRole("cp,ops,support")) {
return ResponseFactory.accessDenied();
}
try {
domainCl = clusterService.get(id);
org.openstack.atlas.docs.loadbalancers.api.management.v1.Cluster dataModelCls;
dataModelCls = getDozerMapper().map(domainCl, org.openstack.atlas.docs.loadbalancers.api.management.v1.Cluster.class, "SIMPLE_CL");
dataModelCls.setNumberOfHostMachines(clusterService.getHosts(domainCl.getId()).size());
dataModelCls.setNumberOfUniqueCustomers(clusterService.getNumberOfUniqueAccountsForCluster(domainCl.getId()));
dataModelCls.setNumberOfLoadBalancingConfigurations(clusterService.getNumberOfActiveLoadBalancersForCluster(domainCl.getId()));
/* TODO: Read ticket SITESLB-1360 */ //dataModelCls.setUtilization(getUtilization(domainCl.getId()));
dataModelCls.setUtilization("0.0%");
return Response.status(200).entity(dataModelCls).build();
} catch (Exception e) {
return ResponseFactory.getErrorResponse(e, null, null);
}
}
public void setVirtualIpsResource(VirtualIpsResource virtualIpsResource) {
this.virtualIpsResource = virtualIpsResource;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public String getUtilization(Integer id) {
//get sum of max allowed connections for all host in cluster
long maxAllowed = getHostRepository().getHostsConnectionsForCluster(id);
double utilization = 0;
if (maxAllowed > 0) {
List<org.openstack.atlas.service.domain.entities.Host> hosts = clusterService.getHosts(id);
int totalConnections = 0;
for (org.openstack.atlas.service.domain.entities.Host dbHost : hosts) {
int conn = 0;
try {
conn = reverseProxyLoadBalancerService.getTotalCurrentConnectionsForHost(dbHost);
} catch (Exception e) {
LOG.error(e);
notificationService.saveAlert(e, AlertType.ZEUS_FAILURE.name(), "Error during getting total connections for host " + dbHost.getId());
}
totalConnections = totalConnections + conn;
}
utilization = (totalConnections / maxAllowed) * 100;
}
return (utilization + " %");
}
public ErrorpageResource getErrorpageResource() {
return errorpageResource;
}
public void setErrorpageResource(ErrorpageResource errorpageResource) {
this.errorpageResource = errorpageResource;
}
private List<String> getIpsNotContainedInASubnet(VirtualIpBlocks vBlocks, IPv4Cidrs ipv4Cidrs) throws IPStringConversionException, IPOctetOutOfRangeException {
List<String> errors = new ArrayList<String>();
for(VirtualIpBlock vBlock : vBlocks.getVirtualIpBlocks()){
String first = vBlock.getFirstIp();
String last = vBlock.getLastIp();
long lo = IPv4ToolSet.ip2long(first);
long hi = IPv4ToolSet.ip2long(last);
if(lo>hi){
String msg = String.format("LastIP=%s and FirstIP=%s must have been switched will not proceed",last,first);
errors.add(msg);
continue;
}
for(long i=lo;i<=hi;i++){
String ipStr = IPv4ToolSet.long2ip(i);
List<String> containingCidrs = ipv4Cidrs.getCidrsContainingIp(ipStr);
if(containingCidrs.isEmpty()){
String msg = String.format("ip=%s not found in any Cidrs",ipStr);
errors.add(msg);
}
}
}
return errors;
}
private IPv4Cidrs getIpv4SubnetCidrs(Integer clusterId) throws Exception {
IPv4Cidrs ipv4Cidrs = new IPv4Cidrs();
Set<String> cidrs = new HashSet<String>();
List<org.openstack.atlas.service.domain.entities.Host> hosts = clusterService.getHosts(clusterId);
List<org.openstack.atlas.service.domain.pojos.Cidr> x;
for (org.openstack.atlas.service.domain.entities.Host host : hosts) {
Hostssubnet hostssubnet = reverseProxyLoadBalancerService.getSubnetMappings(host);
for (Hostsubnet hostsubnet : hostssubnet.getHostsubnets()) {
for (NetInterface ni : hostsubnet.getNetInterfaces()) {
for (org.openstack.atlas.service.domain.pojos.Cidr cidr : ni.getCidrs()) {
String block = cidr.getBlock();
if (IPUtils.isValidIpv4Subnet(block)) {
cidrs.add(block);// Avoid the duplicates we will be seeing by adding to a set only
}
}
}
}
}
for (String block : cidrs) {
ipv4Cidrs.getCidrs().add(new IPv4Cidr(block));
}
return ipv4Cidrs;
}
}