mirror of https://github.com/apache/cloudstack.git
HAProxy Configuration: network.loadbalancer.haproxy.idle.timeout (#12586)
* initial attempt at network.loadbalancer.haproxy.idle.timeout implementation * implement test cases * move idleTimeout configuration test to its own test case
This commit is contained in:
parent
e0fe953791
commit
6e810989b6
|
|
@ -36,6 +36,7 @@ public class LoadBalancerConfigCommand extends NetworkElementCommand {
|
|||
public String lbStatsAuth = "admin1:AdMiN123";
|
||||
public String lbStatsUri = "/admin?stats";
|
||||
public String maxconn = "";
|
||||
public Long idleTimeout = 50000L; /* 0=infinite, >0 = timeout in milliseconds */
|
||||
public String lbProtocol;
|
||||
public boolean keepAliveEnabled = false;
|
||||
NicTO nic;
|
||||
|
|
@ -50,7 +51,7 @@ public class LoadBalancerConfigCommand extends NetworkElementCommand {
|
|||
}
|
||||
|
||||
public LoadBalancerConfigCommand(LoadBalancerTO[] loadBalancers, String publicIp, String guestIp, String privateIp, NicTO nic, Long vpcId, String maxconn,
|
||||
boolean keepAliveEnabled) {
|
||||
boolean keepAliveEnabled, Long idleTimeout) {
|
||||
this.loadBalancers = loadBalancers;
|
||||
this.lbStatsPublicIP = publicIp;
|
||||
this.lbStatsPrivateIP = privateIp;
|
||||
|
|
@ -59,6 +60,7 @@ public class LoadBalancerConfigCommand extends NetworkElementCommand {
|
|||
this.vpcId = vpcId;
|
||||
this.maxconn = maxconn;
|
||||
this.keepAliveEnabled = keepAliveEnabled;
|
||||
this.idleTimeout = idleTimeout;
|
||||
}
|
||||
|
||||
public NicTO getNic() {
|
||||
|
|
|
|||
|
|
@ -638,6 +638,19 @@ public class HAProxyConfigurator implements LoadBalancerConfigurator {
|
|||
if (lbCmd.keepAliveEnabled) {
|
||||
dSection.set(7, "\tno option httpclose");
|
||||
}
|
||||
if (lbCmd.idleTimeout > 0) {
|
||||
dSection.set(9, "\ttimeout client " + Long.toString(lbCmd.idleTimeout));
|
||||
dSection.set(10, "\ttimeout server " + Long.toString(lbCmd.idleTimeout));
|
||||
} else if (lbCmd.idleTimeout == 0) {
|
||||
// .remove() is not allowed, only .set() operations are allowed as the list
|
||||
// is a fixed size. So lets just mark the entry as blank.
|
||||
dSection.set(9, "");
|
||||
dSection.set(10, "");
|
||||
} else {
|
||||
// Negative idleTimeout values are considered invalid; retain the
|
||||
// default HAProxy timeout values from defaultsSection for predictability.
|
||||
logger.warn("Negative idleTimeout ({}) configured; retaining default HAProxy timeouts.", lbCmd.idleTimeout);
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
for (final String s : dSection) {
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ public class ConfigHelperTest {
|
|||
lbs.toArray(arrayLbs);
|
||||
|
||||
final NicTO nic = new NicTO();
|
||||
final LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(arrayLbs, "64.10.2.10", "10.1.10.2", "192.168.1.2", nic, null, "1000", false);
|
||||
final LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(arrayLbs, "64.10.2.10", "10.1.10.2", "192.168.1.2", nic, null, "1000", false, 0L);
|
||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, "10.1.10.2");
|
||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, ROUTERNAME);
|
||||
|
||||
|
|
|
|||
|
|
@ -783,7 +783,7 @@ public class VirtualRoutingResourceTest implements VirtualRouterDeployer {
|
|||
final LoadBalancerTO[] arrayLbs = new LoadBalancerTO[lbs.size()];
|
||||
lbs.toArray(arrayLbs);
|
||||
final NicTO nic = new NicTO();
|
||||
final LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(arrayLbs, "64.10.2.10", "10.1.10.2", "192.168.1.2", nic, null, "1000", false);
|
||||
final LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(arrayLbs, "64.10.2.10", "10.1.10.2", "192.168.1.2", nic, null, "1000", false, 50000L);
|
||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, "10.1.10.2");
|
||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, ROUTERNAME);
|
||||
return cmd;
|
||||
|
|
@ -799,7 +799,7 @@ public class VirtualRoutingResourceTest implements VirtualRouterDeployer {
|
|||
lbs.toArray(arrayLbs);
|
||||
final NicTO nic = new NicTO();
|
||||
nic.setIp("10.1.10.2");
|
||||
final LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(arrayLbs, "64.10.2.10", "10.1.10.2", "192.168.1.2", nic, Long.valueOf(1), "1000", false);
|
||||
final LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(arrayLbs, "64.10.2.10", "10.1.10.2", "192.168.1.2", nic, Long.valueOf(1), "1000", false, 50000L);
|
||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, "10.1.10.2");
|
||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, ROUTERNAME);
|
||||
return cmd;
|
||||
|
|
|
|||
|
|
@ -79,13 +79,14 @@ public class HAProxyConfiguratorTest {
|
|||
LoadBalancerTO[] lba = new LoadBalancerTO[1];
|
||||
lba[0] = lb;
|
||||
HAProxyConfigurator hpg = new HAProxyConfigurator();
|
||||
LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lba, "10.0.0.1", "10.1.0.1", "10.1.1.1", null, 1L, "12", false);
|
||||
LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lba, "10.0.0.1", "10.1.0.1", "10.1.1.1", null, 1L, "12", false, 0L);
|
||||
String result = genConfig(hpg, cmd);
|
||||
assertTrue("keepalive disabled should result in 'option httpclose' in the resulting haproxy config", result.contains("\toption httpclose"));
|
||||
|
||||
cmd = new LoadBalancerConfigCommand(lba, "10.0.0.1", "10.1.0.1", "10.1.1.1", null, 1L, "4", true);
|
||||
cmd = new LoadBalancerConfigCommand(lba, "10.0.0.1", "10.1.0.1", "10.1.1.1", null, 1L, "4", true, 0L);
|
||||
result = genConfig(hpg, cmd);
|
||||
assertTrue("keepalive enabled should result in 'no option httpclose' in the resulting haproxy config", result.contains("\tno option httpclose"));
|
||||
|
||||
// TODO
|
||||
// create lb command
|
||||
// setup tests for
|
||||
|
|
@ -93,6 +94,27 @@ public class HAProxyConfiguratorTest {
|
|||
// httpmode
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link com.cloud.network.HAProxyConfigurator#generateConfiguration(com.cloud.agent.api.routing.LoadBalancerConfigCommand)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGenerateConfigurationLoadBalancerIdleTimeoutConfigCommand() {
|
||||
LoadBalancerTO lb = new LoadBalancerTO("1", "10.2.0.1", 80, "http", "bla", false, false, false, null);
|
||||
LoadBalancerTO[] lba = new LoadBalancerTO[1];
|
||||
lba[0] = lb;
|
||||
HAProxyConfigurator hpg = new HAProxyConfigurator();
|
||||
|
||||
LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lba, "10.0.0.1", "10.1.0.1", "10.1.1.1", null, 1L, "4", true, 0L);
|
||||
String result = genConfig(hpg, cmd);
|
||||
assertTrue("idleTimeout of 0 should not generate 'timeout server' in the resulting haproxy config", !result.contains("\ttimeout server"));
|
||||
assertTrue("idleTimeout of 0 should not generate 'timeout client' in the resulting haproxy config", !result.contains("\ttimeout client"));
|
||||
|
||||
cmd = new LoadBalancerConfigCommand(lba, "10.0.0.1", "10.1.0.1", "10.1.1.1", null, 1L, "4", true, 1234L);
|
||||
result = genConfig(hpg, cmd);
|
||||
assertTrue("idleTimeout of 1234 should result in 'timeout server 1234' in the resulting haproxy config", result.contains("\ttimeout server 1234"));
|
||||
assertTrue("idleTimeout of 1234 should result in 'timeout client 1234' in the resulting haproxy config", result.contains("\ttimeout client 1234"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link com.cloud.network.HAProxyConfigurator#generateConfiguration(com.cloud.agent.api.routing.LoadBalancerConfigCommand)}.
|
||||
*/
|
||||
|
|
@ -106,7 +128,7 @@ public class HAProxyConfiguratorTest {
|
|||
LoadBalancerTO[] lba = new LoadBalancerTO[1];
|
||||
lba[0] = lb;
|
||||
HAProxyConfigurator hpg = new HAProxyConfigurator();
|
||||
LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lba, "10.0.0.1", "10.1.0.1", "10.1.1.1", null, 1L, "12", false);
|
||||
LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lba, "10.0.0.1", "10.1.0.1", "10.1.1.1", null, 1L, "12", false, 0L);
|
||||
String result = genConfig(hpg, cmd);
|
||||
assertTrue("'send-proxy' should result if protocol is 'tcp-proxy'", result.contains("send-proxy"));
|
||||
}
|
||||
|
|
@ -118,7 +140,7 @@ public class HAProxyConfiguratorTest {
|
|||
LoadBalancerTO[] lba = new LoadBalancerTO[1];
|
||||
lba[0] = lb;
|
||||
HAProxyConfigurator hpg = new HAProxyConfigurator();
|
||||
LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lba, "10.0.0.1", "10.1.0.1", "10.1.1.1", null, 1L, "12", false);
|
||||
LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lba, "10.0.0.1", "10.1.0.1", "10.1.1.1", null, 1L, "12", false, 0L);
|
||||
String result = genConfig(hpg, cmd);
|
||||
Assert.assertTrue(result.contains("acl network_allowed src 1.1.1.1 2.2.2.2/24 \n\ttcp-request connection reject if !network_allowed"));
|
||||
}
|
||||
|
|
@ -131,7 +153,7 @@ public class HAProxyConfiguratorTest {
|
|||
LoadBalancerTO[] lba = new LoadBalancerTO[1];
|
||||
lba[0] = lb;
|
||||
HAProxyConfigurator hpg = new HAProxyConfigurator();
|
||||
LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lba, "10.0.0.1", "10.1.0.1", "10.1.1.1", null, 1L, "12", false);
|
||||
LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lba, "10.0.0.1", "10.1.0.1", "10.1.1.1", null, 1L, "12", false, 0L);
|
||||
String result = genConfig(hpg, cmd);
|
||||
Assert.assertTrue(result.contains("bind 10.2.0.1:443 ssl crt /etc/cloudstack/ssl/10_2_0_1-443.pem"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,14 @@ public interface NetworkOrchestrationService {
|
|||
"Load Balancer(haproxy) maximum number of concurrent connections(global max)",
|
||||
true,
|
||||
Scope.Global);
|
||||
ConfigKey<Long> NETWORK_LB_HAPROXY_IDLE_TIMEOUT = new ConfigKey<>(
|
||||
"Network",
|
||||
Long.class,
|
||||
"network.loadbalancer.haproxy.idle.timeout",
|
||||
"50000",
|
||||
"Load Balancer(haproxy) idle timeout in milliseconds. Use 0 for infinite.",
|
||||
true,
|
||||
Scope.Global);
|
||||
|
||||
List<? extends Network> setupNetwork(Account owner, NetworkOffering offering, DeploymentPlan plan, String name, String displayText, boolean isDefault)
|
||||
throws ConcurrentOperationException;
|
||||
|
|
|
|||
|
|
@ -4940,6 +4940,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
|
|||
return new ConfigKey<?>[]{NetworkGcWait, NetworkGcInterval, NetworkLockTimeout, DeniedRoutes,
|
||||
GuestDomainSuffix, NetworkThrottlingRate, MinVRVersion,
|
||||
PromiscuousMode, MacAddressChanges, ForgedTransmits, MacLearning, RollingRestartEnabled,
|
||||
TUNGSTEN_ENABLED, NSX_ENABLED, NETRIS_ENABLED, NETWORK_LB_HAPROXY_MAX_CONN};
|
||||
TUNGSTEN_ENABLED, NSX_ENABLED, NETRIS_ENABLED, NETWORK_LB_HAPROXY_MAX_CONN,
|
||||
NETWORK_LB_HAPROXY_IDLE_TIMEOUT};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,7 +214,8 @@ public class ElasticLoadBalancerManagerImpl extends ManagerBase implements Elast
|
|||
maxconn = offering.getConcurrentConnections().toString();
|
||||
}
|
||||
LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lbs, elbVm.getPublicIpAddress(), _nicDao.getIpAddress(guestNetworkId, elbVm.getId()),
|
||||
elbVm.getPrivateIpAddress(), null, null, maxconn, offering.isKeepAliveEnabled());
|
||||
elbVm.getPrivateIpAddress(), null, null, maxconn, offering.isKeepAliveEnabled(),
|
||||
NetworkOrchestrationService.NETWORK_LB_HAPROXY_IDLE_TIMEOUT.value());
|
||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, elbVm.getPrivateIpAddress());
|
||||
cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, elbVm.getInstanceName());
|
||||
//FIXME: why are we setting attributes directly? Ick!! There should be accessors and
|
||||
|
|
|
|||
|
|
@ -513,7 +513,8 @@ public class InternalLoadBalancerVMManagerImpl extends ManagerBase implements In
|
|||
}
|
||||
final LoadBalancerConfigCommand cmd =
|
||||
new LoadBalancerConfigCommand(lbs, guestNic.getIPv4Address(), guestNic.getIPv4Address(), internalLbVm.getPrivateIpAddress(), _itMgr.toNicTO(guestNicProfile,
|
||||
internalLbVm.getHypervisorType()), internalLbVm.getVpcId(), maxconn, offering.isKeepAliveEnabled());
|
||||
internalLbVm.getHypervisorType()), internalLbVm.getVpcId(), maxconn, offering.isKeepAliveEnabled(),
|
||||
NetworkOrchestrationService.NETWORK_LB_HAPROXY_IDLE_TIMEOUT.value());
|
||||
|
||||
cmd.lbStatsVisibility = _configDao.getValue(Config.NetworkLBHaproxyStatsVisbility.key());
|
||||
cmd.lbStatsUri = _configDao.getValue(Config.NetworkLBHaproxyStatsUri.key());
|
||||
|
|
|
|||
|
|
@ -396,7 +396,8 @@ public class CommandSetupHelper {
|
|||
}
|
||||
|
||||
final LoadBalancerConfigCommand cmd = new LoadBalancerConfigCommand(lbs, routerPublicIp, _routerControlHelper.getRouterIpInNetwork(guestNetworkId, router.getId()),
|
||||
router.getPrivateIpAddress(), _itMgr.toNicTO(nicProfile, router.getHypervisorType()), router.getVpcId(), maxconn, offering.isKeepAliveEnabled());
|
||||
router.getPrivateIpAddress(), _itMgr.toNicTO(nicProfile, router.getHypervisorType()), router.getVpcId(), maxconn, offering.isKeepAliveEnabled(),
|
||||
NetworkOrchestrationService.NETWORK_LB_HAPROXY_IDLE_TIMEOUT.value());
|
||||
|
||||
cmd.lbStatsVisibility = _configDao.getValue(Config.NetworkLBHaproxyStatsVisbility.key());
|
||||
cmd.lbStatsUri = _configDao.getValue(Config.NetworkLBHaproxyStatsUri.key());
|
||||
|
|
|
|||
|
|
@ -1688,7 +1688,7 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
|
|||
} else {
|
||||
loadBalancingData.append("maxconn=").append(offering.getConcurrentConnections());
|
||||
}
|
||||
|
||||
loadBalancingData.append(",idletimeout=").append(NetworkOrchestrationService.NETWORK_LB_HAPROXY_IDLE_TIMEOUT.value());
|
||||
loadBalancingData.append(",sourcePortStart=").append(firewallRuleVO.getSourcePortStart())
|
||||
.append(",sourcePortEnd=").append(firewallRuleVO.getSourcePortEnd());
|
||||
if (firewallRuleVO instanceof LoadBalancerVO) {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,46 @@ def checkMaxconn(haproxyData, haCfgSections):
|
|||
|
||||
return True
|
||||
|
||||
def checkIdletimeout(haproxyData, haCfgSections):
|
||||
if "idletimeout" not in haproxyData:
|
||||
return True
|
||||
|
||||
# Normalize idletimeout value to string for comparison
|
||||
idle_value = str(haproxyData["idletimeout"]).strip()
|
||||
|
||||
# Safely get the defaults section and its timeout directives
|
||||
defaults_section = haCfgSections.get("defaults", {})
|
||||
timeout_lines = defaults_section.get("timeout", [])
|
||||
|
||||
# Extract client and server timeout values from the parsed "timeout" entries
|
||||
timeout_values = {}
|
||||
for tline in timeout_lines:
|
||||
tline = tline.strip()
|
||||
if not tline:
|
||||
continue
|
||||
parts = tline.split(None, 1)
|
||||
if len(parts) < 2:
|
||||
continue
|
||||
kind, value = parts[0].strip(), parts[1].strip()
|
||||
if kind in ("client", "server"):
|
||||
timeout_values[kind] = value
|
||||
|
||||
# Special handling for idletimeout == 0: there should be no client/server timeouts configured
|
||||
if idle_value == "0":
|
||||
if "client" in timeout_values or "server" in timeout_values:
|
||||
print("defaults timeout client or timeout server should be absent when idletimeout is 0")
|
||||
return False
|
||||
return True
|
||||
|
||||
# Non-zero idletimeout: both client and server timeouts must be present
|
||||
if "client" not in timeout_values or "server" not in timeout_values:
|
||||
print("defaults timeout client or timeout server missing")
|
||||
return False
|
||||
|
||||
if idle_value != timeout_values["client"] or idle_value != timeout_values["server"]:
|
||||
print("defaults timeout client or timeout server mismatch occurred")
|
||||
return False
|
||||
return True
|
||||
|
||||
def checkLoadBalance(haproxyData, haCfgSections):
|
||||
correct = True
|
||||
|
|
@ -120,9 +160,10 @@ def main():
|
|||
currSectionDict[lineSec[0]].append(lineSec[1] if len(lineSec) > 1 else '')
|
||||
|
||||
checkMaxConn = checkMaxconn(haproxyData[0], haCfgSections)
|
||||
checkIdleTimeout = checkIdletimeout(haproxyData[0], haCfgSections)
|
||||
checkLbRules = checkLoadBalance(haproxyData, haCfgSections)
|
||||
|
||||
if checkMaxConn and checkLbRules:
|
||||
if checkMaxConn and checkIdleTimeout and checkLbRules:
|
||||
print("All checks pass")
|
||||
exit(0)
|
||||
else:
|
||||
|
|
|
|||
Loading…
Reference in New Issue