Merge branch 'fixloadbalancer2'

This commit is contained in:
Chiradeep Vittal 2010-12-20 17:52:21 -08:00
commit 1597671e73
6 changed files with 278 additions and 24 deletions

View File

@ -26,11 +26,12 @@ import com.cloud.agent.api.to.LoadBalancerTO;
public class LoadBalancerConfigCommand extends RoutingCommand { public class LoadBalancerConfigCommand extends RoutingCommand {
LoadBalancerTO[] loadBalancers; LoadBalancerTO[] loadBalancers;
public LoadBalancerConfigCommand(LoadBalancerTO[] loadBalancers) { public LoadBalancerConfigCommand( LoadBalancerTO[] loadBalancers) {
this.loadBalancers = loadBalancers; this.loadBalancers = loadBalancers;
} }
public LoadBalancerTO[] getLoadBalancers() {
public LoadBalancerTO[] getLoadBalancers() {
return loadBalancers; return loadBalancers;
} }
} }

View File

@ -49,11 +49,18 @@ import com.cloud.agent.api.routing.IPAssocCommand;
import com.cloud.agent.api.routing.IpAssocAnswer; import com.cloud.agent.api.routing.IpAssocAnswer;
import com.cloud.agent.api.routing.LoadBalancerCfgCommand; import com.cloud.agent.api.routing.LoadBalancerCfgCommand;
import com.cloud.agent.api.routing.RoutingCommand; import com.cloud.agent.api.routing.RoutingCommand;
import com.cloud.agent.api.routing.LoadBalancerConfigCommand;
import com.cloud.agent.api.routing.SavePasswordCommand; import com.cloud.agent.api.routing.SavePasswordCommand;
import com.cloud.agent.api.routing.SetPortForwardingRulesAnswer;
import com.cloud.agent.api.routing.SetPortForwardingRulesCommand;
import com.cloud.agent.api.routing.VmDataCommand; import com.cloud.agent.api.routing.VmDataCommand;
import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.IpAddressTO;
import com.cloud.agent.api.to.PortForwardingRuleTO;
import com.cloud.network.HAProxyConfigurator;
import com.cloud.network.LoadBalancerConfigurator;
import com.cloud.utils.NumbersUtil; import com.cloud.utils.NumbersUtil;
import com.cloud.utils.component.Manager; import com.cloud.utils.component.Manager;
import com.cloud.utils.net.NetUtils;
import com.cloud.utils.script.OutputInterpreter; import com.cloud.utils.script.OutputInterpreter;
import com.cloud.utils.script.Script; import com.cloud.utils.script.Script;
@ -89,11 +96,12 @@ public class VirtualRoutingResource implements Manager {
public Answer executeRequest(final Command cmd) { public Answer executeRequest(final Command cmd) {
try { try {
// if (cmd instanceof SetFirewallRuleCommand) { if (cmd instanceof SetPortForwardingRulesCommand ) {
// return execute((SetFirewallRuleCommand)cmd); return execute((SetPortForwardingRulesCommand)cmd);
// }else }else if (cmd instanceof LoadBalancerCfgCommand) {
if (cmd instanceof LoadBalancerCfgCommand) {
return execute((LoadBalancerCfgCommand)cmd); return execute((LoadBalancerCfgCommand)cmd);
} else if (cmd instanceof LoadBalancerConfigCommand) {
return execute((LoadBalancerConfigCommand)cmd);
} else if (cmd instanceof IPAssocCommand) { } else if (cmd instanceof IPAssocCommand) {
return execute((IPAssocCommand)cmd); return execute((IPAssocCommand)cmd);
} else if (cmd instanceof CheckConsoleProxyLoadCommand) { } else if (cmd instanceof CheckConsoleProxyLoadCommand) {
@ -114,7 +122,66 @@ public class VirtualRoutingResource implements Manager {
} }
} }
protected Answer execute(VmDataCommand cmd) { private Answer execute(SetPortForwardingRulesCommand cmd) {
String routerIp = cmd.getAccessDetail(RoutingCommand.ROUTER_IP);
String routerName = cmd.getAccessDetail(RoutingCommand.ROUTER_NAME);
String[] results = new String[cmd.getRules().length];
int i = 0;
for (PortForwardingRuleTO rule : cmd.getRules()) {
String result = null;
if (rule.getProtocol().equalsIgnoreCase(NetUtils.NAT_PROTO)){
setStaticNat(!rule.revoked(), routerName, routerIp, rule.getSrcIp(), rule.getDstIp());
} else {
result = setPortForwardRule(!rule.revoked(), routerName, routerIp,
rule.getProtocol(), rule.getSrcIp(),
Integer.toString(rule.getSrcPortRange()[0]), rule.getDstIp(),
Integer.toString(rule.getDstPortRange()[0]));
}
results[i++] = (result == null || result.isEmpty()) ? "Failed" : null;
}
return new SetPortForwardingRulesAnswer(cmd, results);
}
private Answer execute(LoadBalancerConfigCommand cmd) {
String routerIp = cmd.getAccessDetail(RoutingCommand.ROUTER_IP);
File tmpCfgFile = null;
try {
String cfgFilePath = "";
String routerIP = null;
LoadBalancerConfigurator cfgtr = new HAProxyConfigurator();
String[] config = cfgtr.generateConfiguration(cmd);
String[][] rules = cfgtr.generateFwRules(cmd);
if (routerIp != null) {
tmpCfgFile = File.createTempFile(routerIp.replace('.', '_'), "cfg");
final PrintWriter out
= new PrintWriter(new BufferedWriter(new FileWriter(tmpCfgFile)));
for (int i=0; i < config.length; i++) {
out.println(config[i]);
}
out.close();
cfgFilePath = tmpCfgFile.getAbsolutePath();
}
final String result = setLoadBalancerConfig(cfgFilePath,
rules[LoadBalancerConfigurator.ADD],
rules[LoadBalancerConfigurator.REMOVE],
routerIP);
return new Answer(cmd, result == null, result);
} catch (final IOException e) {
return new Answer(cmd, false, e.getMessage());
} finally {
if (tmpCfgFile != null) {
tmpCfgFile.delete();
}
}
}
protected Answer execute(VmDataCommand cmd) {
List<String[]> vmData = cmd.getVmData(); List<String[]> vmData = cmd.getVmData();
for (String[] vmDataEntry : vmData) { for (String[] vmDataEntry : vmData) {
@ -381,39 +448,47 @@ public class VirtualRoutingResource implements Manager {
return command.execute(); return command.execute();
} }
public String setFirewallRules(final boolean enable, final String routerName, final String routerIpAddress, final String protocol, public String setPortForwardRule(final boolean enable, final String routerName, final String routerIpAddress, final String protocol,
final String publicIpAddress, final String publicPort, final String privateIpAddress, final String privatePort, final String publicIpAddress, final String publicPortRange, final String privateIpAddress, final String privatePortRange) {
String oldPrivateIP, String oldPrivatePort, String vlanNetmask) {
if (routerIpAddress == null) { if (routerIpAddress == null) {
s_logger.warn("SetFirewallRuleCommand did nothing because Router IP address was null when creating rule for public IP: " + publicIpAddress); s_logger.warn("setPortForwardRule did nothing because Router IP address was null when creating rule for public IP: " + publicIpAddress);
return null; return null;
} }
if (oldPrivateIP == null) {
oldPrivateIP = "";
}
if (oldPrivatePort == null) {
oldPrivatePort = "";
}
final Script command = new Script(_firewallPath, _timeout, s_logger); final Script command = new Script(_firewallPath, _timeout, s_logger);
command.add(enable ? "-A" : "-D"); command.add(enable ? "-A" : "-D");
command.add("-P", protocol); command.add("-P", protocol);
command.add("-l", publicIpAddress); command.add("-l", publicIpAddress);
command.add("-p", publicPort); command.add("-p", publicPortRange);
command.add("-n", routerName); command.add("-n", routerName);
command.add("-i", routerIpAddress); command.add("-i", routerIpAddress);
command.add("-r", privateIpAddress); command.add("-r", privateIpAddress);
command.add("-d", privatePort); command.add("-d", privatePortRange);
command.add("-N", vlanNetmask);
command.add("-w", oldPrivateIP);
command.add("-x", oldPrivatePort);
return command.execute(); return command.execute();
} }
public String setStaticNat(final boolean enable, final String routerName, final String routerIpAddress,
final String publicIpAddress, final String privateIpAddress) {
if (routerIpAddress == null) {
s_logger.warn("setStaticNat did nothing because Router IP address was null when creating rule for public IP: " + publicIpAddress);
return null;
}
final Script command = new Script(_firewallPath, _timeout, s_logger);
command.add(enable ? "-A" : "-D");
command.add("-l", publicIpAddress);
command.add("-n", routerName);
command.add("-i", routerIpAddress);
command.add("-G", privateIpAddress);
return command.execute();
}
private boolean isBridgeExists(String bridgeName) { private boolean isBridgeExists(String bridgeName) {
Script command = new Script("/bin/sh", _timeout); Script command = new Script("/bin/sh", _timeout);
command.add("-c"); command.add("-c");

View File

@ -125,6 +125,7 @@ import com.cloud.agent.api.routing.DhcpEntryCommand;
import com.cloud.agent.api.routing.IPAssocCommand; import com.cloud.agent.api.routing.IPAssocCommand;
import com.cloud.agent.api.routing.IpAssocAnswer; import com.cloud.agent.api.routing.IpAssocAnswer;
import com.cloud.agent.api.routing.LoadBalancerCfgCommand; import com.cloud.agent.api.routing.LoadBalancerCfgCommand;
import com.cloud.agent.api.routing.LoadBalancerConfigCommand;
import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand;
import com.cloud.agent.api.routing.RoutingCommand; import com.cloud.agent.api.routing.RoutingCommand;
import com.cloud.agent.api.routing.SavePasswordCommand; import com.cloud.agent.api.routing.SavePasswordCommand;
@ -153,6 +154,8 @@ import com.cloud.agent.api.to.VolumeTO;
import com.cloud.exception.InternalErrorException; import com.cloud.exception.InternalErrorException;
import com.cloud.host.Host.Type; import com.cloud.host.Host.Type;
import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.network.HAProxyConfigurator;
import com.cloud.network.LoadBalancerConfigurator;
import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.BroadcastDomainType;
import com.cloud.network.Networks.TrafficType; import com.cloud.network.Networks.TrafficType;
import com.cloud.resource.ServerResource; import com.cloud.resource.ServerResource;
@ -349,6 +352,8 @@ public abstract class CitrixResourceBase implements ServerResource {
return execute((SetPortForwardingRulesCommand) cmd); return execute((SetPortForwardingRulesCommand) cmd);
} else if (cmd instanceof LoadBalancerCfgCommand) { } else if (cmd instanceof LoadBalancerCfgCommand) {
return execute((LoadBalancerCfgCommand) cmd); return execute((LoadBalancerCfgCommand) cmd);
} else if (cmd instanceof LoadBalancerConfigCommand) {
return execute((LoadBalancerConfigCommand) cmd);
} else if (cmd instanceof IPAssocCommand) { } else if (cmd instanceof IPAssocCommand) {
return execute((IPAssocCommand) cmd); return execute((IPAssocCommand) cmd);
} else if (cmd instanceof CheckConsoleProxyLoadCommand) { } else if (cmd instanceof CheckConsoleProxyLoadCommand) {
@ -1032,6 +1037,66 @@ public abstract class CitrixResourceBase implements ServerResource {
return new Answer(cmd); return new Answer(cmd);
} }
protected Answer execute(final LoadBalancerConfigCommand cmd) {
Connection conn = getConnection();
String routerIp = cmd.getAccessDetail(RoutingCommand.ROUTER_IP);
if (routerIp == null) {
return new Answer(cmd);
}
LoadBalancerConfigurator cfgtr = new HAProxyConfigurator();
String[] config = cfgtr.generateConfiguration(cmd);
String[][] rules = cfgtr.generateFwRules(cmd);
String tmpCfgFilePath = "/tmp/" + routerIp.replace('.', '_') + ".cfg";
String tmpCfgFileContents = "";
for (int i = 0; i < config.length; i++) {
tmpCfgFileContents += config[i];
tmpCfgFileContents += "\n";
}
String result = callHostPlugin(conn, "vmops", "createFile", "filepath", tmpCfgFilePath, "filecontents", tmpCfgFileContents);
if (result == null || result.isEmpty()) {
return new Answer(cmd, false, "LoadBalancerConfigCommand failed to create HA proxy cfg file.");
}
String[] addRules = rules[LoadBalancerConfigurator.ADD];
String[] removeRules = rules[LoadBalancerConfigurator.REMOVE];
String args = "";
args += "-i " + routerIp;
args += " -f " + tmpCfgFilePath;
StringBuilder sb = new StringBuilder();
if (addRules.length > 0) {
for (int i = 0; i < addRules.length; i++) {
sb.append(addRules[i]).append(',');
}
args += " -a " + sb.toString();
}
sb = new StringBuilder();
if (removeRules.length > 0) {
for (int i = 0; i < removeRules.length; i++) {
sb.append(removeRules[i]).append(',');
}
args += " -d " + sb.toString();
}
result = callHostPlugin(conn, "vmops", "setLoadBalancerRule", "args", args);
if (result == null || result.isEmpty()) {
return new Answer(cmd, false, "LoadBalancerConfigCommand failed");
}
callHostPlugin(conn, "vmops", "deleteFile", "filepath", tmpCfgFilePath);
return new Answer(cmd);
}
protected synchronized Answer execute(final DhcpEntryCommand cmd) { protected synchronized Answer execute(final DhcpEntryCommand cmd) {
Connection conn = getConnection(); Connection conn = getConnection();

View File

@ -25,7 +25,10 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import com.cloud.agent.api.routing.LoadBalancerConfigCommand;
import com.cloud.agent.api.to.LoadBalancerTO;
import com.cloud.agent.api.to.PortForwardingRuleTO; import com.cloud.agent.api.to.PortForwardingRuleTO;
import com.cloud.agent.api.to.LoadBalancerTO.DestinationTO;
import com.cloud.utils.net.NetUtils; import com.cloud.utils.net.NetUtils;
@ -143,6 +146,47 @@ public class HAProxyConfigurator implements LoadBalancerConfigurator {
result.add(getBlankLine()); result.add(getBlankLine());
return result; return result;
} }
private List<String> getRulesForPool(LoadBalancerTO lbTO) {
StringBuilder sb = new StringBuilder();
String poolName = sb.append(lbTO.getSrcIp().replace(".", "_")).append('-').append(lbTO.getSrcPort()).toString();
String publicIP = lbTO.getSrcIp();
String publicPort = Integer.toString(lbTO.getSrcPort());
String algorithm = lbTO.getAlgorithm();
List<String> result = new ArrayList<String>();
//add line like this: "listen 65_37_141_30-80 65.37.141.30:80"
sb = new StringBuilder();
sb.append("listen ").append(poolName).append(" ")
.append(publicIP).append(":").append(publicPort);
result.add(sb.toString());
sb = new StringBuilder();
sb.append("\t").append("balance ").append(algorithm);
result.add(sb.toString());
if (publicPort.equals(NetUtils.HTTP_PORT)) {
sb = new StringBuilder();
sb.append("\t").append("mode http");
result.add(sb.toString());
sb = new StringBuilder();
sb.append("\t").append("option httpclose");
result.add(sb.toString());
}
int i=0;
for (DestinationTO dest: lbTO.getDestinations()) {
//add line like this: "server 65_37_141_30-80_3 10.1.1.4:80 check"
if (dest.isRevoked()) {
continue;
}
sb = new StringBuilder();
sb.append("\t").append("server ").append(poolName)
.append("_").append(Integer.toString(i++)).append(" ")
.append(dest.getDestIp()).append(":").append(dest.getDestPort())
.append(" check");
result.add(sb.toString());
}
result.add(getBlankLine());
return result;
}
private String getBlankLine() { private String getBlankLine() {
return new String("\t "); return new String("\t ");
@ -176,4 +220,53 @@ public class HAProxyConfigurator implements LoadBalancerConfigurator {
return result; return result;
} }
@Override
public String[] generateConfiguration(LoadBalancerConfigCommand lbCmd) {
List<String> result = new ArrayList<String>();
result.addAll(Arrays.asList(globalSection));
result.add(getBlankLine());
result.addAll(Arrays.asList(defaultsSection));
result.add(getBlankLine());
if (lbCmd.getLoadBalancers().length == 0){
//haproxy cannot handle empty listen / frontend or backend, so add a dummy listener
//on port 9
result.addAll(Arrays.asList(defaultListen));
}
result.add(getBlankLine());
for (LoadBalancerTO lbTO: lbCmd.getLoadBalancers()){
List<String> poolRules = getRulesForPool(lbTO);
result.addAll(poolRules);
}
return result.toArray(new String[result.size()]);
}
@Override
public String[][] generateFwRules(LoadBalancerConfigCommand lbCmd) {
String [][] result = new String [2][];
Set<String> toAdd = new HashSet<String>();
Set<String> toRemove = new HashSet<String>();
for (LoadBalancerTO lbTO: lbCmd.getLoadBalancers()) {
StringBuilder sb = new StringBuilder();
sb.append(lbTO.getSrcIp()).append(":");
sb.append(lbTO.getSrcPort()).append(":");
String lbRuleEntry = sb.toString();
if (!lbTO.isRevoked()) {
toAdd.add(lbRuleEntry);
} else {
toRemove.add(lbRuleEntry);
}
}
toRemove.removeAll(toAdd);
result[ADD] = toAdd.toArray(new String[toAdd.size()]);
result[REMOVE] = toRemove.toArray(new String[toRemove.size()]);
return result;
}
} }

View File

@ -19,6 +19,7 @@ package com.cloud.network;
import java.util.List; import java.util.List;
import com.cloud.agent.api.routing.LoadBalancerConfigCommand;
import com.cloud.agent.api.to.PortForwardingRuleTO; import com.cloud.agent.api.to.PortForwardingRuleTO;
@ -32,4 +33,7 @@ public interface LoadBalancerConfigurator {
public String [] generateConfiguration(List<PortForwardingRuleTO> fwRules); public String [] generateConfiguration(List<PortForwardingRuleTO> fwRules);
public String [][] generateFwRules(List<PortForwardingRuleTO> fwRules); public String [][] generateFwRules(List<PortForwardingRuleTO> fwRules);
public String [] generateConfiguration(LoadBalancerConfigCommand lbCmd);
public String [][] generateFwRules(LoadBalancerConfigCommand lbCmd);
} }

View File

@ -2099,8 +2099,16 @@ public class DomainRouterManagerImpl implements DomainRouterManager, DomainRoute
@Override @Override
public boolean applyLBRules(Network network, List<? extends FirewallRule> rules) { public boolean applyLBRules(Network network, List<? extends FirewallRule> rules) {
DomainRouterVO router = _routerDao.findByNetworkConfiguration(network.getId());
if (router == null) {
s_logger.warn("Unable to apply lb rules, virtual router doesn't exist in the network " + network.getId());
throw new ResourceUnavailableException("Unable to apply lb rules");
}
String routerControlIpAddress = router.getPrivateIpAddress();
DomainRouterVO router = _routerDao.findByNetworkConfiguration(network.getId()); if (router.getState() == State.Running || router.getState() == State.Starting) {
Commands cmds = new Commands(OnError.Continue); Commands cmds = new Commands(OnError.Continue);
LoadBalancerTO[] lbs = new LoadBalancerTO[rules.size()]; LoadBalancerTO[] lbs = new LoadBalancerTO[rules.size()];
int i = 0; int i = 0;
@ -2124,6 +2132,14 @@ public class DomainRouterManagerImpl implements DomainRouterManager, DomainRoute
//Send commands to router //Send commands to router
return sendCommandsToRouter(router, cmds); return sendCommandsToRouter(router, cmds);
} else if (router.getState() == State.Stopped || router.getState() == State.Stopping){
s_logger.debug("Router is in " + router.getState() + ", so not sending apply LB rules commands to the backend");
return true;
} else {
s_logger.warn("Unable to apply load balancer rules, virtual router is not in the right state " + router.getState());
throw new ResourceUnavailableException("Unable to apply load balancer rules, domR is not in right state " + router.getState());
}
} }
@Override @Override