Repository navigation
LB: per-rule keepalive and timeouts, plus three HAProxy config fixes - #14131
bhouse-nexthop wants to merge 14 commits into
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #14131 +/- ##
============================================
+ Coverage 3.86% 20.78% +16.92%
- Complexity 0 20887 +20887
============================================
Files 494 6053 +5559
Lines 42875 548341 +505466
Branches 8136 73252 +65116
============================================
+ Hits 1657 113989 +112332
- Misses 40986 420998 +380012
- Partials 232 13354 +13122
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
a8f56df to
4eed46e
Compare
4eed46e to
6a432c2
Compare
6a432c2 to
08327da
Compare
|
@bhouse-nexthop |
|
@weizhouapache good catch, thanks - added in the latest commit.
The http mode test needed widening as well, otherwise a rule that sets keepalive itself stopped Compatibility: an older management server sends none of these keys, and a rule that inherits sends I ran the script against generated configs rather than only reading it - a matching config passes, |
There was a problem hiding this comment.
thanks @bhouse-nexthop, the changes look right. CLGTM.
|
@blueorangutan package |
|
@DaanHoogland a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 19626 |
When applying an updated rule to the router fails, updateLoadBalancerRule puts back the name, description, algorithm and cidrs, but not the keepalive and timeouts. Those stayed in the database while the router still ran the old values, and the next successful apply of anything on that router would quietly push them. The settings held before the update are now restored along with the rest. They were also written before the provider validated the rule, so a rule it rejected kept the new settings. The other fields only reach the database at _lbDao.update, after validation; the settings are now written at the same point. Signed-off-by: Brad House <bhouse@nexthop.ai>
The keepalive, idle timeout and keepalive timeout parameters, and the cleanupconnectionsettings flag, were marked since 4.23.0. That release shipped without them, and main is now 24.0.0-SNAPSHOT following the vote to drop the "4." prefix starting with release 24. Signed-off-by: Brad House <bhouse@nexthop.ai>
updateLoadBalancerRule now passes the command's id to the connection settings, which take a long. UpdateLoadBalancerTest built its command without an id, so the null unboxed and testValidateRuleBeforeUpdateLB threw. The API marks id as required, so only the test could get there. Set the id on the command and stub the DAO calls with it, and mock the firewall rule details DAO the settings are read from. testRuleNotValidated only passed before because the null id missed the lookup and raised the same exception type. It now finds the rule and fails on validation, which is what it means to test. Signed-off-by: Brad House <bhouse@nexthop.ai>
4433e91 to
802ca0a
Compare
|
@blueorangutan package |
|
@DaanHoogland a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 19684 |
|
@blueorangutan test |
|
@DaanHoogland a [SL] Trillian-Jenkins test job (ol8 mgmt + kvm-ol8) has been kicked to run smoke tests |
|
[SF] Trillian Build Failed (tid-17222) |
|
[SF] Trillian test result (tid-17228)
|
updateLoadBalancerRule called lb.getLbProtocol().equals(...) after applying the config. lb_protocol is null for a rule created through the API without a protocol, so the update threw an NPE and reported failure although the change had already been applied to the router. Stock hits this on an algorithm or CIDR change; with the per-rule connection settings every keepalive or timeout update on such a rule hits it. Signed-off-by: Brad House <bhouse@nexthop.ai>
updateLoadBalancerRule took its result from _lbDao.update(), which returns false when no column of the rule changed. The keepalive and timeout settings are kept in firewall_rule_details, so an update that only changed them applied the new config to the router and then failed with "Failed to update load balancer rule". Count a settings change as an update. An update that changes nothing still fails, as before. Signed-off-by: Brad House <bhouse@nexthop.ai>
Test report: per-rule keepalive and timeouts, and the HAProxy fixes, on running virtual routersEnvironment
1. An http rule with all three settings
So keep-alive and 2. A tcp rule with only an idle timeout ( 3. Rules that set nothing render as before:
4.
5. AppCookie renders as a stick table. Since #13315 (merged 10-21; this PR's branch does not include it yet), So the generator path is reached only by an AppCookie policy stored before an upgrade. To test that case, I inserted one (
The PR description says AppCookie "is reachable from the API". That is no longer true on main because of #13315. The fix still matters for policies stored before that change. 6. No leak between configs from one agent
7. Health check
8. Back to defaults
9. Validation 10. Rollback when the router update fails
The test plan's first idea for this step was Result: pass.
Two update bugs the lab found, both fixed in the PR The first run found two ways
I retested on a build with both fixes, on two rules: one created without
Not covered
|
|
@blueorangutan package |
|
@RosiKyu a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✖️ el8 ✖️ el9 ✖️ debian ✖️ suse15. SL-JID 20002 |
|
@blueorangutan package |
|
@RosiKyu a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✖️ el8 ✖️ el9 ✖️ debian ✖️ suse15. SL-JID 20003 |
|
@blueorangutan package |
|
@RosiKyu a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✖️ el8 ✖️ el9 ✖️ debian ✖️ suse15. SL-JID 20007 |
|
@bhouse-nexthop FYI: |
Signed-off-by: Brad House <bhouse@nexthop.ai>
|
@DaanHoogland thanks for the heads-up. #14166 removed the test's |
|
@blueorangutan package |
|
@DaanHoogland a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress. |
Description
#12586 made the load balancer idle timeout globally configurable, as
network.loadbalancer.haproxy.idle.timeout. This expands that to per load balancer rule, anddoes the same for keepalive, which until now could only be set on the network offering.
Where these settings live today:
keepaliveenabled, create-time only, no UIoption httpcloseindefaultsnetwork.loadbalancer.haproxy.idle.timeout(#12574, #12586)timeout client,timeout serverindefaultsBoth land in the
defaultssection, so they apply to every LB rule on every network using thatoffering. One rule cannot differ from another on the same router.
New parameters on
createLoadBalancerRuleandupdateLoadBalancerRuleEach is optional, and each writes into that rule's own
listensection, which overridesdefaults:keepaliveoption http-keep-alive, elseoption httpclosekeepaliveenabledidletimeouttimeout clientandtimeout serverkeepalivetimeouttimeout http-keep-aliveidletimeoutappliesidletimeoutkeeps the global's meaning, including0for infinite.What that produces, taken from the generator - an http rule with all three set, a tcp rule with
only an idle timeout, and a rule that set nothing:
The three values are returned on
listLoadBalancerRules, and are settable on the load balancerrule's edit form in the UI, where blank reads as "Use default".
A negative timeout is rejected by the API. Haproxy treats one as a fatal parse error, which would
leave every rule on that router serving its previous config, so the generator drops it as well.
Stored as
firewall_rule_details. No schema change.Applies to public LB rules. Application load balancers are created through a different command and
are not covered.
What this makes possible
A rule on port 80 can now have keep-alive and
X-Forwarded-For. It could not before:mode httpConnection: closeper responsemode tcpforwardforneeds http modemode httpA rule that sets nothing keeps today's behaviour exactly, including the fall back to
mode tcpwhen the offering flag is on.
Also fixes three bugs in the same file
1.
option forcecloseis not a valid keywordWith keepalive enabled, a rule that also uses HTTP-based stickiness or SSL offload emits
no option forceclose. HAProxy has rejected that keyword since 2.0, and the system VM is Debian 12(HAProxy 2.6):
The whole file is rejected, so haproxy keeps serving the previous config and the rule silently
never takes effect. Replaced with
option http-keep-alive.2. One rule's settings leak into every rule generated afterwards
globalSectionanddefaultsSectionarestatic String[]. The generator wraps them inArrays.asList(...)and callsset(), which writes through to the arrays, so the valuesurvives the call:
no option httpclosein the defaults for every later rule, any network, any accountidleTimeout> 0idleTimeout== 0The generator now copies into a fresh list, and the sections themselves became
List.of(...), so afuture
set()throws instead of silently corrupting every config the agent builds afterwards.Output is unchanged for a single rule.
3.
appsessionwas removed from HAProxy in 1.6An LB rule with
AppCookiestickiness emittedappsession, which the shipped haproxy refuses:Same blast radius as bug 1 - the file is rejected, so every rule on that router keeps serving its
previous config. The VR advertises
AppCookieas a supported stickiness method, so this isreachable from the API.
Replaced with the documented stick table equivalent:
len <n>stick-table type string len <n> size 10ktimeout <h>expire <h>stick store-response res.cook(<name>)+stick match req.cook(<name>)request-learnstick store-request req.cook(<name>)prefix,modeprefixandmodewere never applied - the directive carrying them was rejected - so no workingbehaviour changes.
Types of changes
Feature/Enhancement Scale or Bug Severity
Feature/Enhancement Scale
Bug Severity
How Has This Been Tested?
HAProxyConfiguratorTestTests run: 17, Failures: 0andLoadBalancingRulesManagerImplTestTests run: 16, Failures: 0.Each bug fix has a case that fails without it:
forceclose, and does emitoption http-keep-aliveno option httpclosebehindAppCookiestickiness emits a stick table and neverappsessionThe rest cover the per-rule settings:
timeout http-keep-aliveis emitted, and only when keepalive is onidletimeoutoverrides per rule on a tcp rule, leaving the defaults section aloneGenerated configs are checked against a real
haproxy -c, which is where the alert text abovecomes from. A file holding an
AppCookierule, an http rule with all three settings, a tcp rulewith a timeout, and a rule with a negative timeout is fatal before these changes and valid
after - the three alerts above become zero.