feat: ha_should_redirect + join.c HA redirect/nomaster guard (P1-6)
Add redirect helpers to ha.c/ha.h so a standby controller never accepts join requests as if it were the primary: - ha_should_redirect(): returns 1 when role is STANDBY and primary_host/port are known — caller should send E_XCE_REDIRECT. - ha_no_primary_known(): returns 1 when role is STANDBY but primary address is not yet known — caller should send E_XCE_NOMASTER (retry later). - Add E_XCE_NOMASTER and E_XCE_REDIRECT to errnox.h. - Wire both guards into handle_join_() in join.c (before the role switch) so all join types (worker, scheduler, apiserver, client) are protected. - Full redirect response sends status=-E_XCE_REDIRECT with nodata body; the primary host:port are logged so operators can trace misrouted clients. Full Cap'n Proto RedirectInfo response body is deferred to a follow-up (schema union would require regenerating capnp bindings). 5 new TDD tests — 110 total, 0 failures.
This commit is contained in:
parent
c627f69d50
commit
f5b0ac0af3
7 changed files with 191 additions and 0 deletions
|
|
@ -5,6 +5,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "cluster.h"
|
||||
#include "ha.h"
|
||||
#include "xce/cluster_def.h"
|
||||
#include "xce/errnox.h"
|
||||
|
||||
|
|
@ -177,6 +178,32 @@ static int handle_join_(cluster_t* c, endpoint_t* ep, xce_request_t* request)
|
|||
|
||||
TRACE("%s role %d join from %s", __func__, role, from->name);
|
||||
|
||||
/* ── HA guard (P1-6) ────────────────────────────────────────
|
||||
* A standby must never accept joins as if it were the primary.
|
||||
* If the primary address is known, tell the client where to go
|
||||
* (E_XCE_REDIRECT). If no primary is known yet, tell the client
|
||||
* to retry later (E_XCE_NOMASTER).
|
||||
*/
|
||||
if (ha_should_redirect(&c->ha)) {
|
||||
WARN("%s standby redirecting role-%d join from %s to %s:%u",
|
||||
__func__, role, from->name,
|
||||
c->ha.primary_host, c->ha.primary_port);
|
||||
rc = -E_XCE_REDIRECT;
|
||||
reply.status = rc;
|
||||
reply.data_which = RequestReply_data_nodata;
|
||||
xce_reply(ep, c->myhost, &reply);
|
||||
return rc;
|
||||
}
|
||||
if (ha_no_primary_known(&c->ha)) {
|
||||
WARN("%s standby has no primary yet, rejecting role-%d join from %s",
|
||||
__func__, role, from->name);
|
||||
rc = -E_XCE_NOMASTER;
|
||||
reply.status = rc;
|
||||
reply.data_which = RequestReply_data_nodata;
|
||||
xce_reply(ep, c->myhost, &reply);
|
||||
return rc;
|
||||
}
|
||||
|
||||
switch (role) {
|
||||
case HostRole_client:
|
||||
rc = handle_client_join(c, ep, request);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue