fix(worker): bug-1569 periodic resval reports tagged with wrong host
collect_load_indices() (resource_sync.c) tagged every periodic mem/r1m/r15m/r15s/ut/pg/ls/it/swp/io/tmp report with gethostname()'s raw OS/container hostname instead of the worker's own join identity (xcecd_ctx.virtual_name, the -n/--name value). Every other worker-keyed lookup downstream (scheduler's sched_get_worker(), and the same HOOK_DETAIL_RESOURCE_UPDATE payload forwarded on to the Go apiserver) matches by that join identity, so the mismatch silently dropped every periodic resource report for the real worker. Also adds a startup INFO log (main.c) naming the resolved job picker plugin, used to rule out a legacy-picker hypothesis while chasing a related (still-open) dispatch issue. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
0d1ab09eb7
commit
6e5c3a891a
4 changed files with 180 additions and 3 deletions
|
|
@ -327,6 +327,10 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
sched_init(&sched, &config, cluster_cfg_ptr, scheduler_req_handler);
|
sched_init(&sched, &config, cluster_cfg_ptr, scheduler_req_handler);
|
||||||
|
|
||||||
|
INFO("active job picker plugin: %s", sched.core.job_pick_plugin
|
||||||
|
? sched.core.job_pick_plugin
|
||||||
|
: "(null)");
|
||||||
|
|
||||||
/* Req 5 AC 10 (scheduler-core spec, task 9.1): stash the resolved
|
/* Req 5 AC 10 (scheduler-core spec, task 9.1): stash the resolved
|
||||||
* --record-dir value on the live xce_scheduler_t -- see scheduler.h's
|
* --record-dir value on the live xce_scheduler_t -- see scheduler.h's
|
||||||
* field comment. Not consumed anywhere yet (task 9.2's job); this
|
* field comment. Not consumed anywhere yet (task 9.2's job); this
|
||||||
|
|
|
||||||
|
|
@ -203,9 +203,29 @@ static xce_resval_t* collect_load_indices(int* count)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char hostname[256];
|
/* bug-1569: this worker's JOIN identity (the -n/--name value, e.g.
|
||||||
if (gethostname(hostname, sizeof(hostname)) != 0) {
|
* "pc13v" -- xcecd_ctx.virtual_name, set from config->virutal_name in
|
||||||
strcpy(hostname, "unknown");
|
* xcecd_init(), xcecd.c) is what the controller/scheduler key every
|
||||||
|
* OTHER per-worker resource value by (mark_host_res()/update_val_res(),
|
||||||
|
* worker.c; sched_get_worker(), core_events.c). Using gethostname()
|
||||||
|
* (the raw OS/container hostname, which is NOT the same value and can
|
||||||
|
* be identical across every worker in a multi-worker-per-host test
|
||||||
|
* setup, or simply a generic sandbox/container name unrelated to any
|
||||||
|
* configured worker identity) here instead made every periodic load-
|
||||||
|
* index report's .host wrong -- the controller forwards it to the
|
||||||
|
* scheduler unmodified (do_update_resvals(), opupd.c), which then
|
||||||
|
* fails sched_get_worker(core, rv->host) for the REAL worker and
|
||||||
|
* silently drops the value ("RESVALS_DELTA: unknown worker <host>,
|
||||||
|
* skipping", core_events.c) -- live-confirmed: gethostname() here
|
||||||
|
* returned "xce" in this sandbox, not "pc13v". */
|
||||||
|
const char* hostname = xcecd_ctx.virtual_name;
|
||||||
|
char hostname_buf[256];
|
||||||
|
|
||||||
|
if (hostname == NULL || hostname[0] == '\0') {
|
||||||
|
if (gethostname(hostname_buf, sizeof(hostname_buf)) != 0) {
|
||||||
|
strcpy(hostname_buf, "unknown");
|
||||||
|
}
|
||||||
|
hostname = hostname_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < rescount; i++) {
|
for (int i = 0; i < rescount; i++) {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,21 @@ test('worker controller_connector test', controller_connector_test,
|
||||||
timeout: 60,
|
timeout: 60,
|
||||||
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
||||||
|
|
||||||
|
# bug-1569: collect_load_indices() (resource_sync.c) must tag every periodic
|
||||||
|
# resource report with xcecd_ctx.virtual_name (the worker's own join
|
||||||
|
# identity), not gethostname()'s raw OS/container hostname -- see
|
||||||
|
# test_resource_sync.c's own header comment for the full mechanism trace.
|
||||||
|
resource_sync_test = executable('resource_sync_test',
|
||||||
|
'test_resource_sync.c',
|
||||||
|
include_directories: [worker_test_incdir],
|
||||||
|
dependencies: worker_test_deps,
|
||||||
|
install: false)
|
||||||
|
|
||||||
|
test('worker resource_sync test', resource_sync_test,
|
||||||
|
suite: 'worker',
|
||||||
|
timeout: 60,
|
||||||
|
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
||||||
|
|
||||||
# component-failover-adoption task 2.2: worker startup-ordering white-box
|
# component-failover-adoption task 2.2: worker startup-ordering white-box
|
||||||
# test. #include's xcecd.c directly (same technique as controller_connector_
|
# test. #include's xcecd.c directly (same technique as controller_connector_
|
||||||
# test above, but a separate binary/file -- xcecd.c and controller_connector.c
|
# test above, but a separate binary/file -- xcecd.c and controller_connector.c
|
||||||
|
|
|
||||||
138
src/worker/testsuite/test_resource_sync.c
Normal file
138
src/worker/testsuite/test_resource_sync.c
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* test_resource_sync.c - regression test for bug-1569: collect_load_indices()
|
||||||
|
* (resource_sync.c) must tag every periodic resource value with the
|
||||||
|
* worker's own JOIN identity (xcecd_ctx.virtual_name -- the -n/--name value,
|
||||||
|
* set from config->virutal_name in xcecd_init(), xcecd.c), not
|
||||||
|
* gethostname()'s raw OS/container hostname.
|
||||||
|
*
|
||||||
|
* Why this matters: the controller forwards each report's .host field to
|
||||||
|
* the scheduler UNMODIFIED (do_update_resvals(), src/controller/opupd.c),
|
||||||
|
* which keys EVERY other per-worker resource value by this SAME join
|
||||||
|
* identity (mark_host_res()/update_val_res(), src/controller/worker.c;
|
||||||
|
* sched_get_worker(), src/scheduler/src/core_events.c). A mismatch here
|
||||||
|
* silently drops every periodic ("mem"/"r15s"/etc.) resource report for the
|
||||||
|
* real worker -- live-confirmed against two independent deployments in this
|
||||||
|
* sandbox: gethostname() returned a generic container hostname ("xce"), not
|
||||||
|
* the worker's configured "-n pc13v" identity, so the scheduler's own
|
||||||
|
* "unknown worker xce, skipping" WARN fired every ~15s (resource_sync's own
|
||||||
|
* LOAD_INDICES_INTERVAL_DEFAULT) and "info worker pc13v" never showed real
|
||||||
|
* mem/r15s/etc values despite xce_test's live `resval` query showing them
|
||||||
|
* correctly (a DIFFERENT, correctly-addressed query path).
|
||||||
|
*
|
||||||
|
* White-box #include of ../src/resource_sync.c (same convention this
|
||||||
|
* suite already establishes for controller_connector.c/xcecd.c). The 11
|
||||||
|
* builtin load-index getters (node_info_get_15s/etc., real implementations
|
||||||
|
* in node_information.c, not linked here) are stubbed as trivial
|
||||||
|
* deterministic returns -- this test is about collect_load_indices()'s own
|
||||||
|
* .host-tagging logic, not the real /proc-reading getters' own values.
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <unity/unity.h>
|
||||||
|
|
||||||
|
#include "xcecd.h"
|
||||||
|
|
||||||
|
/* Real globals this white-box TU's resource_sync.c references
|
||||||
|
* (xcecd_ctx.virtual_name) -- not linking xcecd.c itself (its own
|
||||||
|
* main()/full daemon init is out of scope for this narrow test), so a
|
||||||
|
* plain definition here satisfies the linker, matching this suite's own
|
||||||
|
* "provide just the global a white-box #include needs" idiom
|
||||||
|
* (test_xcecd_startup_order.c's g_dummy_subsystem-style stubs). */
|
||||||
|
xcecd_context_t xcecd_ctx;
|
||||||
|
|
||||||
|
/* Stubs for the 11 builtin load-index getters (node_information.c, not
|
||||||
|
* linked here) -- deterministic, non-NULL so collect_load_indices() never
|
||||||
|
* takes its own NULL-getter fallback path (out of scope for this test). */
|
||||||
|
static char* stub_getter(void)
|
||||||
|
{
|
||||||
|
return strdup("1.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
char* node_info_get_15s(void) { return stub_getter(); }
|
||||||
|
char* node_info_get_1m(void) { return stub_getter(); }
|
||||||
|
char* node_info_get_15m(void) { return stub_getter(); }
|
||||||
|
char* node_info_get_ut(void) { return stub_getter(); }
|
||||||
|
char* node_info_get_pg(void) { return stub_getter(); }
|
||||||
|
char* node_info_get_ls(void) { return stub_getter(); }
|
||||||
|
char* node_info_get_it(void) { return stub_getter(); }
|
||||||
|
char* node_info_get_swap(void) { return stub_getter(); }
|
||||||
|
char* node_info_get_mem(void) { return stub_getter(); }
|
||||||
|
char* node_info_get_tmp(void) { return stub_getter(); }
|
||||||
|
char* node_info_get_io(void) { return stub_getter(); }
|
||||||
|
|
||||||
|
/* Linker stub for controller_connector.c's real implementation -- only
|
||||||
|
* referenced by resource_sync_thread() (the background polling loop),
|
||||||
|
* never invoked by this test (which calls collect_load_indices()
|
||||||
|
* directly). */
|
||||||
|
bool xcecd_send_load_indices(xce_resval_t** vals, int count)
|
||||||
|
{
|
||||||
|
(void)vals;
|
||||||
|
(void)count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "../src/resource_sync.c"
|
||||||
|
|
||||||
|
void setUp(void) { return; }
|
||||||
|
void tearDown(void) { return; }
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_collect_load_indices_tags_host_with_virtual_name_not_gethostname(void)
|
||||||
|
{
|
||||||
|
xce_resval_t* vals;
|
||||||
|
int count = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(&xcecd_ctx, 0, sizeof(xcecd_ctx));
|
||||||
|
xcecd_ctx.virtual_name = (char*)"pc13v";
|
||||||
|
|
||||||
|
vals = collect_load_indices(&count);
|
||||||
|
|
||||||
|
TEST_ASSERT_NOT_NULL(vals);
|
||||||
|
TEST_ASSERT_TRUE(count > 0);
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
TEST_ASSERT_NOT_NULL(vals[i].host);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("pc13v", vals[i].host);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_resvals(vals, count);
|
||||||
|
|
||||||
|
printf("test_collect_load_indices_tags_host_with_virtual_name_not_"
|
||||||
|
"gethostname: PASS\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_collect_load_indices_falls_back_to_gethostname_when_virtual_name_unset(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
xce_resval_t* vals;
|
||||||
|
int count = 0;
|
||||||
|
char expected[256];
|
||||||
|
|
||||||
|
memset(&xcecd_ctx, 0, sizeof(xcecd_ctx));
|
||||||
|
xcecd_ctx.virtual_name = NULL;
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT(0, gethostname(expected, sizeof(expected)));
|
||||||
|
|
||||||
|
vals = collect_load_indices(&count);
|
||||||
|
|
||||||
|
TEST_ASSERT_NOT_NULL(vals);
|
||||||
|
TEST_ASSERT_TRUE(count > 0);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(expected, vals[0].host);
|
||||||
|
|
||||||
|
free_resvals(vals, count);
|
||||||
|
|
||||||
|
printf("test_collect_load_indices_falls_back_to_gethostname_when_"
|
||||||
|
"virtual_name_unset: PASS\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(test_collect_load_indices_tags_host_with_virtual_name_not_gethostname);
|
||||||
|
RUN_TEST(test_collect_load_indices_falls_back_to_gethostname_when_virtual_name_unset);
|
||||||
|
return UNITY_END();
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue