fix(scheduler): fix limit-plugin usergroup/scope/error-code cascade (gitea#46)
While live-verifying gitea#46, found and fixed a cascade of 5 previously undetected bugs that together made every usergroup-scoped limit in limits.yaml silently non-functional: - Named usergroups/hostgroups (users.yaml/hosts.yaml) were never registered into the scheduler's group managers (groupmgr_add() had zero production callers), so any limit referencing one by name could never resolve real membership. - An unconfigured limit scope (e.g. no "projects:") arrived as an empty-but-present capnp group, not NULL, so build_consumer() built a real empty group (matching no one) instead of falling back to "all". - Three separate call sites conflated key_find()'s negative "not found" return with a real error, short-circuiting before ever reaching the "instantiate on first use" logic right below them -- the same defect class already fixed once before in this codebase (bug-1495). - Two call sites passed &(sched->core.resmgr) where a plain handle was expected, one level of indirection too many, causing RTTI's key_find() to reject it as an invalid handle. All five are live-verified: fresh cluster deploys now correctly match and instantiate usage tracking for all 7 limits in limits.yaml on every job submission, reproduced across multiple independent from-scratch redeploys. A 6th, architecturally distinct issue remains open (bug-1789, logged, not fixed): sched_fill_limit_requests() computes a job's consumption of a slots-scoped global limit by reading the wrong request vector, so the numeric cap itself still never binds. This needs a design decision on intended cross-scope semantics, not a mechanical fix, so it's left for a follow-up. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hb6Edtj4KbS8CrgEWYdA2E
This commit is contained in:
parent
099dbdabdc
commit
22cfe61642
8 changed files with 432 additions and 19 deletions
|
|
@ -200,7 +200,21 @@ static int match_job_global_limit_(xce_sched_plugin_t* plugin,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (is_host_based_limit(&(sched->core.resmgr), limit) > 0) {
|
||||
/* bug-1787: is_host_based_limit()/instantiate_limit() both take a
|
||||
* plain `var resmgr` (core.h: `var resmgr;` -- already a handle, not
|
||||
* a var*), matching how every other resmgr/ugmgr/etc. consumer in
|
||||
* this codebase (get_group(), is_in_group(), key_find() itself) takes
|
||||
* its manager by value. Passing &(sched->core.resmgr) here instead
|
||||
* (as this and the instantiate_limit() call below previously did)
|
||||
* handed those functions the ADDRESS of the field instead of its
|
||||
* value -- one level of indirection too many. RTTI's key_find()
|
||||
* dispatch then rejected that as an invalid object handle: silently
|
||||
* inside is_host_based_limit() (its own `rc<=0` guard turns ANY
|
||||
* key_find() failure, including this one, into a uniform -ENOENT --
|
||||
* see bug-1786's comment above for why that's not itself a bug), but
|
||||
* fatally inside instantiate_limit()'s own key_find() call, which
|
||||
* returned -EINVAL and aborted vres instantiation outright. */
|
||||
if (is_host_based_limit(sched->core.resmgr, limit) > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -216,18 +230,30 @@ static int match_job_global_limit_(xce_sched_plugin_t* plugin,
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* bug-1786: key_find() returning <= 0 here means "not found" (this
|
||||
* codebase's established kvmgr convention, matching get_group()'s and
|
||||
* is_host_based_limit()'s own identical rc<=0 checks) -- the FIRST
|
||||
* time ANY limit ever matches a given user/queue/project combination,
|
||||
* this is always the case, since no vres has been instantiated for it
|
||||
* yet. Returning early here (as this code previously did) never gave
|
||||
* the instantiate_limit() block below a chance to run: vres stays
|
||||
* uninitialized (calloc'd to NULL at declaration, never reassigned by
|
||||
* a failed key_find), so `if (vres == NULL)` below is the correct,
|
||||
* sufficient signal to instantiate -- this key_find's own rc need not
|
||||
* gate anything further. Before this fix, bug-1784/1785's fixes made
|
||||
* match_limit() correctly match for the first time in this codebase's
|
||||
* history, which only then exposed this: a limit could match a job
|
||||
* but its usage/threshold accounting could never actually initialize,
|
||||
* so no limit's numeric cap (e.g. limits.yaml's ug1_normal_slots
|
||||
* value: 8) was ever enforced, only the pass/fail match itself. */
|
||||
lock(privdata->instances, RTTI_LOCK_READ);
|
||||
rc = key_find(privdata->instances, (void*)vresname, (void*)&vres);
|
||||
unlock(privdata->instances);
|
||||
|
||||
if (rc <= 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
FREEUP(vresname);
|
||||
|
||||
if (vres == NULL) {
|
||||
rc = instantiate_limit(&vres, &(sched->core.resmgr), limit, obj->user,
|
||||
rc = instantiate_limit(&vres, sched->core.resmgr, limit, obj->user,
|
||||
obj->queue, obj->project);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
|
|
@ -337,7 +363,7 @@ static int match_job_host_limit_(xce_sched_plugin_t* plugin,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (is_host_based_limit(&(sched->core.resmgr), limit) <= 0) {
|
||||
if (is_host_based_limit(sched->core.resmgr, limit) <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -376,7 +402,7 @@ static int match_job_host_limit_(xce_sched_plugin_t* plugin,
|
|||
FREEUP(vresname);
|
||||
|
||||
if (vres == NULL) {
|
||||
rc = instantiate_limit(&vres, &(sched->core.resmgr), limit, obj->user,
|
||||
rc = instantiate_limit(&vres, sched->core.resmgr, limit, obj->user,
|
||||
obj->queue, obj->project);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "client.h"
|
||||
#include "controller.capnp.h"
|
||||
#include "decision.h"
|
||||
#include "group.h"
|
||||
#include "kvmgr.h"
|
||||
#include "misc.h"
|
||||
#include "plugin.h"
|
||||
|
|
@ -1094,6 +1095,16 @@ static int sched_init_queues(xce_scheduler_t* sched)
|
|||
}
|
||||
int sched_init_config(xce_scheduler_t* sched, xce_conf4sched_t* config)
|
||||
{
|
||||
/* bug-1784: register the cluster's NAMED usergroups/hostgroups (from
|
||||
* users.yaml's "usergroups:"/hosts.yaml's "hostgroups:") into
|
||||
* core.ugmgr/core.hgmgr BEFORE plugin_config_update() below -- a limit
|
||||
* config that references one of these by name (e.g. a limit scoped to
|
||||
* users.members=["ug1"]) resolves it via build_consumer()'s own
|
||||
* makeGroup() call, which can only find an existing named group if it
|
||||
* was already registered under that name. */
|
||||
groupmgr_load_configs(sched->core.ugmgr, config->n_ugroups, config->ugroups);
|
||||
groupmgr_load_configs(sched->core.hgmgr, config->n_hgroups, config->hgroups);
|
||||
|
||||
plugin_config_update(sched, config);
|
||||
sched->core.config = config;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue