package org.openstack.atlas.adapter.helpers;
import com.zxtm.service.client.VirtualServerProtocol;
import org.codehaus.jackson.map.ObjectMapper;
import org.openstack.atlas.adapter.LoadBalancerEndpointConfiguration;
import org.openstack.atlas.adapter.exceptions.InsufficientRequestException;
import org.openstack.atlas.adapter.zxtm.ZxtmConversionUtils;
import org.openstack.atlas.service.domain.entities.*;
import org.openstack.atlas.util.ca.StringUtils;
import org.openstack.atlas.util.ca.zeus.ZeusCrtFile;
import org.openstack.atlas.util.ca.zeus.ZeusUtils;
import org.openstack.atlas.util.ip.exception.IPStringConversionException;
import org.rackspace.stingray.client.bandwidth.Bandwidth;
import org.rackspace.stingray.client.bandwidth.BandwidthBasic;
import org.rackspace.stingray.client.bandwidth.BandwidthProperties;
import org.rackspace.stingray.client.monitor.Monitor;
import org.rackspace.stingray.client.monitor.MonitorBasic;
import org.rackspace.stingray.client.monitor.MonitorHttp;
import org.rackspace.stingray.client.monitor.MonitorProperties;
import org.rackspace.stingray.client.pool.*;
import org.rackspace.stingray.client.protection.*;
import org.rackspace.stingray.client.ssl.keypair.Keypair;
import org.rackspace.stingray.client.ssl.keypair.KeypairBasic;
import org.rackspace.stingray.client.ssl.keypair.KeypairProperties;
import org.rackspace.stingray.client.traffic.ip.TrafficIp;
import org.rackspace.stingray.client.traffic.ip.TrafficIpBasic;
import org.rackspace.stingray.client.traffic.ip.TrafficIpIpMapping;
import org.rackspace.stingray.client.traffic.ip.TrafficIpProperties;
import org.rackspace.stingray.client.util.EnumFactory;
import org.rackspace.stingray.client.virtualserver.*;
import java.io.IOException;
import java.util.*;
public class ResourceTranslator {
public Pool cPool;
public Monitor cMonitor;
public Map<String, TrafficIp> cTrafficIpGroups;
public VirtualServer cVServer;
public VirtualServer cRedirectVServer;
public Protection cProtection;
public Bandwidth cBandwidth;
public Keypair cKeypair;
protected static final ZeusUtils zeusUtil;
static {
zeusUtil = new ZeusUtils();
}
public static ResourceTranslator getNewResourceTranslator() {
return new ResourceTranslator();
}
public void translateLoadBalancerResource(LoadBalancerEndpointConfiguration config,
String vsName, LoadBalancer loadBalancer, LoadBalancer queLb) throws InsufficientRequestException {
translateLoadBalancerResource(config, vsName, loadBalancer, queLb, true);
}
public void translateLoadBalancerResource(LoadBalancerEndpointConfiguration config,
String vsName, LoadBalancer loadBalancer, LoadBalancer queLb, boolean careAboutCert) throws InsufficientRequestException {
//Order matters when translating the entire entity.
if (loadBalancer.getHealthMonitor() != null && !loadBalancer.hasSsl()) translateMonitorResource(loadBalancer);
if (loadBalancer.getRateLimit() != null) translateBandwidthResource(loadBalancer);
translateTrafficIpGroupsResource(config, loadBalancer, true);
if (loadBalancer.getSslTermination() != null) translateKeypairResource(loadBalancer, careAboutCert);
if ((loadBalancer.getAccessLists() != null && !loadBalancer.getAccessLists().isEmpty()) || loadBalancer.getConnectionLimit() != null)
translateProtectionResource(loadBalancer);
translatePoolResource(vsName, loadBalancer, queLb);
translateVirtualServerResource(config, vsName, loadBalancer);
if (loadBalancer.isHttpsRedirect() != null && loadBalancer.isHttpsRedirect()) {
translateRedirectVirtualServerResource(config, vsName, loadBalancer);
}
}
//This could probably be trimmed down a bit
private VirtualServer translateRedirectVirtualServerResource(LoadBalancerEndpointConfiguration config, String vsName, LoadBalancer loadBalancer) throws InsufficientRequestException {
VirtualServerBasic basic = new VirtualServerBasic();
VirtualServerSsl ssl = new VirtualServerSsl();
VirtualServerProperties properties = new VirtualServerProperties();
VirtualServerConnectionError ce = new VirtualServerConnectionError();
VirtualServerLog log;
List<String> rules = new ArrayList<String>();
properties.setBasic(basic);
properties.setSsl(ssl);
cRedirectVServer = new VirtualServer();
cRedirectVServer.setProperties(properties);
basic.setEnabled(true);
// Redirection specific
basic.setPort(80);
basic.setPool("discard");
basic.setProtocol(VirtualServerProtocol.http.getValue());
log = new VirtualServerLog();
log.setEnabled(false);
properties.setLog(log);
ce.setError_file("Default");
properties.setConnection_errors(ce);
//trafficscript or rule settings
rules.add(StmConstants.HTTPS_REDIRECT);
basic.setRequest_rules(rules);
//trafficIpGroup settings
basic.setListen_on_any(false);
basic.setListen_on_traffic_ips(genGroupNameSet(loadBalancer));
//ssl settings
ssl.setServer_cert_default(vsName);
return cRedirectVServer;
}
public VirtualServer translateVirtualServerResource(LoadBalancerEndpointConfiguration config,
String vsName, LoadBalancer loadBalancer) throws InsufficientRequestException {
VirtualServerBasic basic = new VirtualServerBasic();
VirtualServerSsl ssl = new VirtualServerSsl();
VirtualServerProperties properties = new VirtualServerProperties();
VirtualServerConnectionError ce = new VirtualServerConnectionError();
VirtualServerTcp tcp = new VirtualServerTcp();
VirtualServerLog log;
List<String> rules = new ArrayList<String>();
properties.setBasic(basic);
properties.setSsl(ssl);
cVServer = new VirtualServer();
cVServer.setProperties(properties);
//basic virtual server settings
if (vsName.equals(ZxtmNameBuilder.genSslVSName(loadBalancer))) {
basic.setPort(loadBalancer.getSslTermination().getSecurePort());
basic.setSsl_decrypt(true);
basic.setEnabled(loadBalancer.isUsingSsl());
} else {
basic.setPort(loadBalancer.getPort());
if (loadBalancer.hasSsl()) {
basic.setEnabled(!loadBalancer.isSecureOnly());
} else {
basic.setEnabled(true);
}
}
basic.setPool(ZxtmNameBuilder.genVSName(loadBalancer));
basic.setProtocol(ZxtmConversionUtils.mapProtocol(loadBalancer.getProtocol()).getValue());
//protection class settings
if ((loadBalancer.getAccessLists() != null && !loadBalancer.getAccessLists().isEmpty()) || loadBalancer.getConnectionLimit() != null) {
basic.setProtection_class(ZxtmNameBuilder.genVSName(loadBalancer));
}
//connection log settings
if (loadBalancer.isConnectionLogging() != null && loadBalancer.isConnectionLogging()) {
log = new VirtualServerLog();
final String nonHttpLogFormat = "%v %t %h %A:%p %n %B %b %T";
final String httpLogFormat = "%v %{Host}i %h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\" %n";
if (loadBalancer.getProtocol() != LoadBalancerProtocol.HTTP) {
log.setFormat(nonHttpLogFormat);
} else if (loadBalancer.getProtocol() == LoadBalancerProtocol.HTTP) {
log.setFormat(httpLogFormat);
}
log.setEnabled(loadBalancer.isConnectionLogging());
log.setFilename(config.getLogFileLocation());
properties.setLog(log);
} else if (loadBalancer.isConnectionLogging() != null && !loadBalancer.isConnectionLogging()) {
log = new VirtualServerLog();
log.setEnabled(false);
properties.setLog(log);
}
//webcache settings
if (loadBalancer.isContentCaching() != null && loadBalancer.isContentCaching()) {
VirtualServerWebcache cache = new VirtualServerWebcache();
cache.setEnabled(true);
properties.setWeb_cache(cache);
rules.add(StmConstants.CONTENT_CACHING);
}
//error file settings
if (loadBalancer.getUserPages() != null && loadBalancer.getUserPages().getErrorpage() != null) { // if userPages is null, just leave the ce object alone and it should use the default page
ce.setError_file(ZxtmNameBuilder.generateErrorPageName(ZxtmNameBuilder.genVSName(loadBalancer)));
} else {
//Doesnt look like thats the case for some reason :( may be bug in STM -- need to reverify this
ce.setError_file("Default");
}
properties.setConnection_errors(ce);
//X_forwarded headers
if (loadBalancer.getProtocol() == LoadBalancerProtocol.HTTP) {
basic.setAdd_x_forwarded_for(true);
basic.setAdd_x_forwarded_proto(true);
rules.add(StmConstants.XFPORT);
}
//trafficscript or rule settings
basic.setRequest_rules(rules);
//Half closed proxy settings
tcp.setProxy_close(loadBalancer.isHalfClosed());
properties.setTcp(tcp);
//trafficIpGroup settings
basic.setListen_on_any(false);
basic.setListen_on_traffic_ips(genGroupNameSet(loadBalancer));
//ssl settings
ssl.setServer_cert_default(vsName);
return cVServer;
}
public Map<String, TrafficIp> translateTrafficIpGroupsResource(LoadBalancerEndpointConfiguration config,
LoadBalancer loadBalancer, boolean isEnabled) throws InsufficientRequestException {
Map<String, TrafficIp> nameandgroup = new HashMap<String, TrafficIp>();
// Add new traffic ip groups for IPv4 vips
for (LoadBalancerJoinVip loadBalancerJoinVipToAdd : loadBalancer.getLoadBalancerJoinVipSet()) {
nameandgroup.put(ZxtmNameBuilder.generateTrafficIpGroupName(loadBalancer, loadBalancerJoinVipToAdd.getVirtualIp()),
translateTrafficIpGroupResource(config, loadBalancerJoinVipToAdd.getVirtualIp().getIpAddress(), isEnabled));
}
// Add new traffic ip groups for IPv6 vips
for (LoadBalancerJoinVip6 loadBalancerJoinVip6ToAdd : loadBalancer.getLoadBalancerJoinVip6Set()) {
try {
nameandgroup.put(ZxtmNameBuilder.generateTrafficIpGroupName(loadBalancer, loadBalancerJoinVip6ToAdd.getVirtualIp()),
translateTrafficIpGroupResource(config, loadBalancerJoinVip6ToAdd.getVirtualIp().getDerivedIpString(), isEnabled));
} catch (IPStringConversionException e) {
//Generally means there is a missing value, wrap up the exception into general IRE;
throw new InsufficientRequestException(e);
}
}
cTrafficIpGroups = nameandgroup;
return nameandgroup;
}
private TrafficIp translateTrafficIpGroupResource(LoadBalancerEndpointConfiguration config
, String ipaddress, boolean isEnabled) {
TrafficIp tig = new TrafficIp();
TrafficIpProperties properties = new TrafficIpProperties();
TrafficIpBasic basic = new TrafficIpBasic();
// TrafficIpIpMapping mapping = new TrafficIpIpMapping();
// List<TrafficIpIpMapping> mappings = new ArrayList<TrafficIpIpMapping>(Arrays.asList(mapping));
// basic.setIp_mapping(mappings);
basic.setHash_source_port(false);
basic.setKeeptogether(false);
basic.setEnabled(isEnabled);
basic.setIpaddresses(new HashSet<String>(Arrays.asList(ipaddress)));
Set<String> machines = new HashSet<String>();
machines.add(config.getTrafficManagerName());
machines.addAll(config.getFailoverTrafficManagerNames());
basic.setMachines(machines);
basic.setSlaves(new HashSet<String>(config.getFailoverTrafficManagerNames()));
properties.setBasic(basic);
tig.setProperties(properties);
return tig;
}
public Set<String> genGroupNameSet(LoadBalancer loadBalancer) throws InsufficientRequestException {
Set<String> groupSet = new HashSet<String>();
int acctId = loadBalancer.getAccountId();
for (LoadBalancerJoinVip loadBalancerJoinVipToAdd : loadBalancer.getLoadBalancerJoinVipSet()) {
groupSet.add(ZxtmNameBuilder.generateTrafficIpGroupName(acctId, loadBalancerJoinVipToAdd.getVirtualIp().getId().toString()));
}
for (LoadBalancerJoinVip6 loadBalancerJoinVip6ToAdd : loadBalancer.getLoadBalancerJoinVip6Set()) {
groupSet.add(ZxtmNameBuilder.generateTrafficIpGroupName(acctId, loadBalancerJoinVip6ToAdd.getVirtualIp().getId().toString()));
}
return groupSet;
}
public Pool translatePoolResource(String vsName, LoadBalancer loadBalancer, LoadBalancer queLb) throws InsufficientRequestException {
cPool = new Pool();
PoolProperties properties = new PoolProperties();
PoolBasic basic = new PoolBasic();
List<PoolNodeWeight> weights = new ArrayList<PoolNodeWeight>();
PoolLoadbalancing poollb = new PoolLoadbalancing();
Set<Node> nodes = loadBalancer.getNodes();
Set<Node> enabledNodes = new HashSet<Node>();
enabledNodes.addAll(NodeHelper.getNodesWithCondition(nodes, NodeCondition.ENABLED));
enabledNodes.addAll(NodeHelper.getNodesWithCondition(nodes, NodeCondition.DRAINING));
basic.setNodes(NodeHelper.getNodeStrValue(enabledNodes));
basic.setDraining(NodeHelper.getNodeStrValue(NodeHelper.getNodesWithCondition(nodes, NodeCondition.DRAINING)));
basic.setDisabled(NodeHelper.getNodeStrValue(NodeHelper.getNodesWithCondition(nodes, NodeCondition.DISABLED)));
basic.setPassive_monitoring(false);
String lbAlgo = loadBalancer.getAlgorithm().name().toLowerCase();
if (queLb.getNodes() != null && !queLb.getNodes().isEmpty()) {
if (lbAlgo.equals(EnumFactory.Accept_from.WEIGHTED_ROUND_ROBIN.toString())
|| lbAlgo.equals(EnumFactory.Accept_from.WEIGHTED_LEAST_CONNECTIONS.toString())) {
PoolNodeWeight nw;
for (Node n : nodes) {
nw = new PoolNodeWeight();
nw.setNode(n.getIpAddress() + ":" + Integer.toString(n.getPort()));
nw.setWeight(n.getWeight());
weights.add(nw);
}
poollb.setNode_weighting(weights);
}
}
ZeusNodePriorityContainer znpc = new ZeusNodePriorityContainer(nodes);
poollb.setPriority_enabled(znpc.hasSecondary());
poollb.setPriority_values(znpc.getPriorityValuesSet());
poollb.setAlgorithm(lbAlgo);
PoolConnection connection = null;
if (queLb.getTimeout() != null) {
connection = new PoolConnection();
connection.setMax_reply_time(loadBalancer.getTimeout());
}
if (queLb.getHealthMonitor() != null)
basic.setMonitors(new HashSet<String>(Arrays.asList(vsName)));
if ((queLb.getSessionPersistence() != null) && !(queLb.getSessionPersistence().name().equals(SessionPersistence.NONE.name()))) {
basic.setPersistence_class(loadBalancer.getSessionPersistence().name());
} else {
basic.setPersistence_class("");
}
if (queLb.getRateLimit() != null) {
basic.setBandwidth_class(vsName);
} else {
basic.setBandwidth_class(null);
}
properties.setBasic(basic);
properties.setLoad_balancing(poollb);
properties.setConnection(connection);
cPool.setProperties(properties);
return cPool;
}
public Monitor translateMonitorResource(LoadBalancer loadBalancer) {
Monitor monitor = new Monitor();
MonitorProperties properties = new MonitorProperties();
MonitorBasic basic = new MonitorBasic();
MonitorHttp http;
HealthMonitor hm = loadBalancer.getHealthMonitor();
basic.setDelay(hm.getDelay());
basic.setTimeout(hm.getTimeout());
basic.setFailures(hm.getAttemptsBeforeDeactivation());
if (hm.getType().equals(HealthMonitorType.CONNECT)) {
basic.setType(EnumFactory.Accept_from.CONNECT.toString());
} else if (hm.getType().equals(HealthMonitorType.HTTP) || hm.getType().equals(HealthMonitorType.HTTPS)) {
basic.setType(EnumFactory.Accept_from.HTTP.toString());
http = new MonitorHttp();
http.setPath(hm.getPath());
http.setStatus_regex(hm.getStatusRegex());
http.setBody_regex(hm.getBodyRegex());
http.setHost_header(hm.getHostHeader());
if (hm.getType().equals(HealthMonitorType.HTTPS)) {
basic.setUse_ssl(true);
} else {
basic.setUse_ssl(false);
}
properties.setHttp(http);
}
properties.setBasic(basic);
monitor.setProperties(properties);
cMonitor = monitor;
return cMonitor;
}
public Protection translateProtectionResource(LoadBalancer loadBalancer) {
cProtection = new Protection();
ProtectionBasic basic = new ProtectionBasic();
ProtectionProperties properties = new ProtectionProperties();
ConnectionLimit limits = loadBalancer.getConnectionLimit();
Set<AccessList> accessList = loadBalancer.getAccessLists();
ProtectionAccessRestriction pac = new ProtectionAccessRestriction();
if (accessList != null && !accessList.isEmpty()) {
Set<String> allowed = new HashSet<String>();
Set<String> banned = new HashSet<String>();
for (AccessList item : accessList) {
if (item.getType().equals(AccessListType.ALLOW)) {
allowed.add(item.getIpAddress());
} else {
banned.add(item.getIpAddress());
}
}
pac.setAllowed(allowed);
pac.setBanned(banned);
}
properties.setAccess_restriction(pac);
ProtectionConnectionLimiting limiting = new ProtectionConnectionLimiting();
if (limits != null) {
Integer maxConnections = limits.getMaxConnections();
if (maxConnections == null) maxConnections = 0;
limiting.setMax_1_connections(maxConnections);
limiting.setMax_10_connections(maxConnections * 10);
limiting.setMax_connection_rate(limits.getMaxConnectionRate());
limiting.setMin_connections(limits.getMinConnections());
limiting.setRate_timer(limits.getRateInterval());
} else {
limiting.setMax_10_connections(0);
limiting.setMax_1_connections(0);
limiting.setMax_connection_rate(0);
limiting.setMin_connections(0);
limiting.setRate_timer(1);
}
properties.setConnection_limiting(limiting);
properties.setBasic(basic);
cProtection.setProperties(properties);
return cProtection;
}
public Keypair translateKeypairResource(LoadBalancer loadBalancer, boolean careAboutCert)
throws InsufficientRequestException {
ZeusCrtFile zeusCertFile = zeusUtil.buildZeusCrtFileLbassValidation(loadBalancer.getSslTermination().getPrivatekey(),
loadBalancer.getSslTermination().getCertificate(), loadBalancer.getSslTermination().getIntermediateCertificate());
if (zeusCertFile.hasFatalErrors()) {
String fmt = "StingrayCertFile generation Failure: %s";
String errors = StringUtils.joinString(zeusCertFile.getErrors(), ",");
String msg = String.format(fmt, errors);
if (careAboutCert)
throw new InsufficientRequestException(msg);
else
return null;
}
cKeypair = new Keypair();
KeypairProperties keypairProperties = new KeypairProperties();
KeypairBasic keypairBasic = new KeypairBasic();
keypairBasic.setPrivate(zeusCertFile.getPrivate_key());
keypairBasic.setPublic(zeusCertFile.getPublic_cert());
keypairProperties.setBasic(keypairBasic);
cKeypair.setProperties(keypairProperties);
return cKeypair;
}
public Bandwidth translateBandwidthResource(LoadBalancer loadBalancer) throws InsufficientRequestException {
Bandwidth bandwidth = new Bandwidth();
BandwidthProperties properties = new BandwidthProperties();
BandwidthBasic basic = new BandwidthBasic();
RateLimit rateLimit = loadBalancer.getRateLimit();
if (rateLimit != null) {
Ticket ticket = rateLimit.getTicket();
basic.setMaximum(rateLimit.getMaxRequestsPerSecond());
if (ticket != null)
basic.setNote(ticket.getComment());
}
properties.setBasic(basic);
bandwidth.setProperties(properties);
cBandwidth = bandwidth;
return cBandwidth;
}
public <T> String objectToString(Object obj, Class<T> clazz) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Object myObject = mapper.writeValueAsString(obj);
// System.out.println(myObject.toString());
return myObject.toString();
}
public <T> T stringToObject(String str, Class<T> clazz) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Object myObject = mapper.readValue(str, clazz);
return (T) myObject;
}
public Pool getcPool() {
return cPool;
}
public void setcPool(Pool cPool) {
this.cPool = cPool;
}
public Monitor getcMonitor() {
return cMonitor;
}
public void setcMonitor(Monitor cMonitor) {
this.cMonitor = cMonitor;
}
public Map<String, TrafficIp> getcTrafficIpGroups() {
return cTrafficIpGroups;
}
public void setcTrafficIpGroups(Map<String, TrafficIp> cTrafficIpGroups) {
this.cTrafficIpGroups = cTrafficIpGroups;
}
public VirtualServer getcVServer() {
return cVServer;
}
public void setcVServer(VirtualServer cVServer) {
this.cVServer = cVServer;
}
public VirtualServer getcRedirectVServer() {
return cRedirectVServer;
}
public void setcRedirectVServer(VirtualServer cVServer) {
this.cRedirectVServer = cVServer;
}
public Protection getcProtection() {
return cProtection;
}
public void setcProtection(Protection cProtection) {
this.cProtection = cProtection;
}
public Bandwidth getcBandwidth() {
return cBandwidth;
}
public void setcBandwidth(Bandwidth cBandwidth) {
this.cBandwidth = cBandwidth;
}
public Keypair getcKeypair() {
return cKeypair;
}
public void setcKeypair(Keypair keypair) {
this.cKeypair = keypair;
}
}