Skip to content

Commit c02ca5c

Browse files
authored
Merge pull request #7753 from grondo/vqueues-support
add core support for RFC 33 virtual queues
2 parents a112d01 + 432e1b9 commit c02ca5c

28 files changed

Lines changed: 2734 additions & 124 deletions

doc/guide/admin_config.rst

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,17 @@ define a default queue.
575575
Finally, queues can override the ``[policy]`` table on a per queue basis.
576576
This is useful for setting queue-specific limits.
577577

578+
A queue may also be configured as a *virtual queue* by setting ``parent``
579+
to the name of another queue. A virtual queue is an alternate submission
580+
name for the parent queue's resources with different policy: it inherits the
581+
parent's policy and overrides only the keys it sets. For example, a virtual
582+
queue that raises the parent's limits can allow a subset of users to submit
583+
jobs that bypass those limits. Note that Flux does not yet enforce per-queue
584+
access control, so restricting who may use a virtual queue currently requires
585+
an external mechanism such as the flux-accounting multi-factor priority
586+
plugin. A virtual queue may also be started, stopped, enabled, or disabled
587+
independently of its parent. See :man5:`flux-config-queues` for details.
588+
578589
Here is an example that puts these concepts together:
579590

580591
.. code-block:: toml
@@ -630,8 +641,12 @@ is rejected.
630641
``nnodes`` *and* ``ncores`` limits when configuring job size policy limits.
631642

632643
Limits are global when set in the top level ``[policy]`` table. Global limits
633-
may be overridden by a ``policy`` table within a ``[queues]`` entry. Here is
634-
an example which implements duration and job size limits for two queues:
644+
may be overridden by a ``policy`` table within a ``[queues]`` entry. A virtual
645+
queue's ``policy`` table overrides its parent queue's limits on a per-key
646+
basis, so a virtual queue that overrides only the duration limit still
647+
inherits the parent's job size limits. Here is an example which implements
648+
duration and job size limits for two queues, and adds a virtual queue for
649+
smaller jobs with a longer duration limit in the batch queue.
635650

636651
.. code-block:: toml
637652
@@ -652,6 +667,12 @@ an example which implements duration and job size limits for two queues:
652667
policy.limits.job-size.max.nnodes = 16
653668
policy.limits.job-size.max.ncores = 128
654669
670+
[queues.small]
671+
parent = "batch"
672+
policy.limits.duration = "24h"
673+
policy.limits.job-size.max.nnodes = 2
674+
policy.limits.job-size.max.ncores = 16
675+
655676
See also: :man5:`flux-config-policy`.
656677

657678
Use PAM to Restrict Access to Compute Nodes

doc/man1/flux-jobs.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ OPTIONS
5656

5757
List jobs in a specific queue or queues. Multiple queues may be separated
5858
by a comma or by using the :option:`-q, --queue` option multiple times.
59+
If a named queue has virtual queues configured (RFC 33), then jobs
60+
submitted to any of its virtual queues are also listed, since they are
61+
scheduled as part of the named queue. Naming a virtual queue directly
62+
lists only the jobs submitted to that virtual queue.
5963

6064
.. option:: -i, --include=HOSTS|RANKS
6165

doc/man1/flux-queue.rst

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ The :program:`flux queue` command operates on Flux job queue(s).
3232
By default, Flux has one anonymous queue. Multiple named queues may be
3333
configured - see :man5:`flux-config-queues`.
3434

35+
A named queue may be a virtual queue, as described in RFC 33: an alternate
36+
submission name for a parent queue's resources with different policy,
37+
such as raised limits for a subset of users. Jobs submitted to a virtual
38+
queue are scheduled as part of the parent queue. The :program:`flux queue`
39+
administrative commands below operate on a virtual queue's own state
40+
without affecting its parent or sibling queues, but note that a virtual
41+
queue's jobs are only eligible for scheduling when both the virtual queue
42+
and its parent are started.
43+
3544
COMMANDS
3645
========
3746

@@ -42,7 +51,9 @@ list
4251

4352
.. program:: flux queue list
4453

45-
List queue status, defaults, and limits.
54+
List queue status, defaults, and limits. When one or more virtual
55+
queues are configured, a ``PARENT`` column is also shown, listing each
56+
virtual queue's parent queue (blank for a non-virtual queue).
4657

4758
.. option:: -q, --queue=QUEUE,...
4859

@@ -223,23 +234,35 @@ The following field names can be specified:
223234
**queuem**
224235
queue name, but default queue is marked up with an asterisk
225236

237+
**parent**
238+
parent queue name if this is a virtual queue (RFC 33), otherwise empty.
239+
This field is only shown by default if at least one configured queue
240+
has a parent.
241+
226242
**submission**
227243
Description of queue submission status: ``enabled`` or ``disabled``
228244

229245
**scheduling**
230-
Description of queue scheduling status: ``started`` or ``stopped``
246+
Description of queue scheduling status: ``started``, ``stopped``, or,
247+
for a virtual queue whose own state is started but whose parent queue
248+
is stopped, ``stopped (parent)``.
231249

232250
**enabled**
233251
Single character submission status: ```` if enabled, ```` if disabled.
234252

235253
**started**
236254
Single character scheduling status: ```` if started, ```` if stopped.
255+
A virtual queue whose own state is started but whose parent queue is
256+
stopped shows ```` instead: scheduling will resume automatically once
257+
the parent is started.
237258

238259
**enabled.ascii**
239260
Single character submission status: ``y`` if enabled, ``n`` if disabled.
240261

241262
**started.ascii**
242-
Single character scheduling status: ``y`` if started, ``n`` if stopped.
263+
Single character scheduling status: ``y`` if started, ``n`` if stopped,
264+
or ``p`` if started but paused because its parent is stopped (see
265+
**started** above).
243266

244267
**defaults.timelimit**
245268
default timelimit for jobs submitted to the queue

doc/man1/flux-resource.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,9 @@ The following field names can be specified for the **list** subcommand:
493493

494494
**queue**
495495
Queue(s) associated with resources. When ``-q, --queue`` is used,
496-
only the specified queues are shown.
496+
only the specified queues are shown. Virtual queues (RFC 33) do not
497+
appear in this field, since they share their parent queue's resources
498+
rather than being associated with any resources of their own.
497499

498500
**properties**
499501
Properties associated with resources.

doc/man5/flux-config-policy.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ and limits, as described in RFC 33.
1212
Each queue defined in the ``queues`` table described in
1313
:man5:`flux-config-queues` may have a ``policy`` sub-table that follows the
1414
same rules as the main table. The per-queue table overrides the general table
15-
for jobs submitted to that queue.
15+
for jobs submitted to that queue. A virtual queue (RFC 33) adds a further
16+
level: its own ``policy`` table, where set, overrides its parent queue's
17+
effective policy on a per-key basis, which in turn overrides the general
18+
table.
1619

1720
DEFAULTS
1821
========

doc/man5/flux-config-queues.rst

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,44 @@ policy (table)
2525
A policy table as described in :man5:`flux-config-policy` that overrides
2626
the general system policy for jobs submitted to this queue.
2727

28+
parent (string)
29+
Declares this queue to be a virtual queue, as described in RFC 33. The
30+
value names another queue in the ``[queues]`` table from which this
31+
queue inherits its resource subset and policy. A virtual queue MUST
32+
NOT set ``requires`` or ``policy.scheduler``: it always shares its
33+
parent's resources, and thus its parent's scheduler configuration.
34+
The named parent must not itself be a virtual queue. A virtual queue
35+
may be configured as the default queue.
36+
2837
A default queue name may be configured by setting
2938
``policy.jobspec.defaults.system.queue`` as described in
3039
:man5:`flux-config-policy`.
3140

3241

42+
VIRTUAL QUEUES
43+
==============
44+
45+
A virtual queue is an alternate name under which jobs may be submitted to
46+
a parent queue's resources, with different policy applied at job
47+
ingest. A job submitted to a virtual queue keeps the virtual queue's name
48+
for listing, accounting, and per-queue policy purposes, but is scheduled
49+
as part of its parent queue: it competes for the parent's resources in the
50+
same priority order as jobs submitted directly to the parent.
51+
52+
A virtual queue inherits every policy key from its parent, and any key it
53+
sets itself overrides only that key. For example, a virtual queue that
54+
sets ``policy.limits.duration`` but not ``policy.limits.job-size`` still
55+
inherits the parent's job-size limits. Job defaults
56+
(``policy.jobspec.defaults.system``) are inherited the same way.
57+
58+
A virtual queue may be enabled/disabled and started/stopped
59+
independently of its parent. However, because a virtual queue's jobs are
60+
scheduled as part of its parent, they are only eligible for scheduling
61+
when both the virtual queue and its parent are started. Starting a
62+
virtual queue whose parent is stopped does not release its jobs; they
63+
become eligible only once the parent is also started.
64+
65+
3366
EXAMPLE
3467
=======
3568

@@ -51,8 +84,13 @@ EXAMPLE
5184

5285
[queues.batch]
5386
policy.limits.duration = "8h"
87+
policy.limits.job-size.max.nnodes = 16
5488
requires = [ "batch" ]
5589

90+
[queues.expedite]
91+
parent = "batch"
92+
policy.limits.duration = "1h"
93+
5694
[policy.jobspec.defaults.system]
5795
queue = "batch"
5896

@@ -63,6 +101,11 @@ EXAMPLE
63101
match-policy = "lonodex"
64102
match-format = "rv1_nosched"
65103

104+
In this configuration, ``expedite`` is a virtual queue of ``batch``: jobs
105+
submitted with ``--queue=expedite`` run on ``batch``'s resources, subject
106+
to a shorter 1 hour duration limit, but still inherit ``batch``'s
107+
16 node job-size limit since ``expedite`` does not override it.
108+
66109

67110
CAVEATS
68111
=======

src/bindings/python/flux/job/frobnicator/plugins/constraints.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,25 @@ def __init__(self, config={}):
2525

2626
def queue_properties(self, name):
2727
try:
28-
return self.queues[name]["requires"]
28+
entry = self.queues[name]
2929
except KeyError:
3030
return None
31+
# A virtual queue (RFC 33) has no 'requires' of its own -
32+
# inject the parent's instead, since that is what makes the
33+
# job schedule as part of the parent's job list. Inheritance
34+
# is one level (validated by conf_policy.c), so no chain to
35+
# walk. An unresolvable parent is a fatal error (fail closed):
36+
# silently dropping the parent's constraint would place the
37+
# job outside the parent's resource slice.
38+
parent = entry.get("parent")
39+
if parent is not None:
40+
try:
41+
entry = self.queues[parent]
42+
except KeyError:
43+
raise ValueError(
44+
f"queue '{name}': parent queue '{parent}' is not configured"
45+
)
46+
return entry.get("requires")
3147

3248
def apply_constraints(self, jobspec):
3349
"""Apply queue-specific constraints to jobspec"""

src/bindings/python/flux/job/frobnicator/plugins/defaults.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,42 @@ def validate_config(self):
4949
self.queue_defaults(queue)
5050

5151
def queue_defaults(self, name):
52-
"""Create a copy of self.defaults updated with queue-specific values"""
52+
"""Create a copy of self.defaults updated with queue-specific values
53+
54+
Effective defaults are layered: global defaults, then (if 'name'
55+
is a virtual queue, RFC 33) the parent queue's own defaults,
56+
then this queue's own defaults - each layer overlaid per-key
57+
over the last. Inheritance is one level (validated by
58+
conf_policy.c), so there is no chain to walk beyond the parent.
59+
"""
60+
61+
def queue_system_defaults(qconf):
62+
try:
63+
return qconf["policy"]["jobspec"]["defaults"]["system"]
64+
except KeyError:
65+
return None
66+
5367
defaults = copy.deepcopy(self.defaults)
5468
if name and self.queues:
5569
if name not in self.queues:
5670
raise ValueError(f"Invalid queue '{name}' specified")
5771
qconf = self.queues[name]
58-
try:
59-
qdefaults = qconf["policy"]["jobspec"]["defaults"]["system"]
72+
# A virtual queue (RFC 33) inherits the parent's defaults
73+
# beneath its own. An unresolvable parent is a fatal error
74+
# (fail closed): silently skipping the parent layer would
75+
# give the vqueue the wrong effective defaults.
76+
parent = qconf.get("parent")
77+
if parent is not None:
78+
if parent not in self.queues:
79+
raise ValueError(
80+
f"queue '{name}': parent queue '{parent}' is not configured"
81+
)
82+
pdefaults = queue_system_defaults(self.queues[parent])
83+
if pdefaults is not None:
84+
defaults.update(pdefaults)
85+
qdefaults = queue_system_defaults(qconf)
86+
if qdefaults is not None:
6087
defaults.update(qdefaults)
61-
return defaults
62-
except KeyError:
63-
return defaults
6488
return defaults
6589

6690
def setattr_default(self, jobspec, attr, value):

0 commit comments

Comments
 (0)