Skip to content

Commit d7bd7d4

Browse files
authored
Merge pull request #6209 from grondo/flux-jobs-include
flux-jobs: add `-i, --include=HOSTS|RANKS` option
2 parents 7d18dd7 + b2868cc commit d7bd7d4

File tree

5 files changed

+91
-3
lines changed

5 files changed

+91
-3
lines changed

doc/man1/flux-jobs.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ OPTIONS
5151
List jobs in a specific queue or queues. Multiple queues may be separated
5252
by a comma or by using the :option:`-q, --queue` option multiple times.
5353

54+
.. option:: -i, --include=HOSTS|RANKS
55+
56+
List only jobs where the assigned resources intersect with the supplied
57+
argument, which may be specified either as an RFC 22 idset of broker ranks
58+
or an RFC 29 hostlist of host names. It is not an error to specify ranks or
59+
hosts which do not exist.
60+
5461
.. option:: -c, --count=N
5562

5663
Limit output to N jobs (default 1000)
@@ -618,6 +625,12 @@ RESOURCES
618625

619626
.. include:: common/resources.rst
620627

628+
FLUX RFC
629+
========
630+
631+
| :doc:`rfc:spec_22`
632+
| :doc:`rfc:spec_29`
633+
621634
SEE ALSO
622635
========
623636

src/bindings/python/flux/job/list.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,15 @@ def job_list(
5151
since=0.0,
5252
name=None,
5353
queue=None,
54+
constraint=None,
5455
):
55-
# N.B. an "and" operation with no values returns everything
56-
constraint = {"and": []}
56+
if constraint is None:
57+
# N.B. an "and" operation with no values returns everything
58+
constraint = {"and": []}
59+
else:
60+
# O/w, a provided constraint will be anded with other parameters below:
61+
constraint = {"and": [constraint]}
62+
5763
if userid != flux.constants.FLUX_USERID_UNKNOWN:
5864
constraint["and"].append({"userid": [userid]})
5965
if name:
@@ -83,7 +89,13 @@ def job_list(
8389

8490

8591
def job_list_inactive(
86-
flux_handle, since=0.0, max_entries=1000, attrs=["all"], name=None, queue=None
92+
flux_handle,
93+
since=0.0,
94+
max_entries=1000,
95+
attrs=["all"],
96+
name=None,
97+
queue=None,
98+
constraint=None,
8799
):
88100
"""Same as ``flux.job.list.job_list``, but lists only inactive jobs."""
89101
return job_list(
@@ -95,6 +107,7 @@ def job_list_inactive(
95107
since=since,
96108
name=name,
97109
queue=queue,
110+
constraint=constraint,
98111
)
99112

100113

@@ -207,6 +220,10 @@ class JobList:
207220
:since: Limit jobs to those that have been active since a given timestamp.
208221
:name: Limit jobs to those with a specific name.
209222
:queue: Limit jobs to those submitted to a specific queue or queues
223+
:constraint: An RFC 31 Constraint object describing a job-list constraint
224+
as documented in RFC 43 Constraint Operators section. This constraint
225+
may then be joined with other constraints provided by above parameters
226+
via the ``and`` operator.
210227
"""
211228

212229
# pylint: disable=too-many-instance-attributes
@@ -240,6 +257,7 @@ def __init__(
240257
since=0.0,
241258
name=None,
242259
queue=None,
260+
constraint=None,
243261
):
244262
self.handle = flux_handle
245263
self.attrs = list(attrs)
@@ -255,6 +273,7 @@ def __init__(
255273
for x in fname.split(","):
256274
self.add_filter(x)
257275
self.set_user(user)
276+
self.constraint = constraint
258277

259278
def set_user(self, user):
260279
"""Only return jobs for user (may be a username or userid)"""
@@ -306,6 +325,7 @@ def fetch_jobs(self):
306325
since=self.since,
307326
name=self.name,
308327
queue=self.queue,
328+
constraint=self.constraint,
309329
)
310330

311331
def jobs(self):

src/cmd/flux-jobs.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import sys
1818

1919
import flux.constants
20+
from flux.hostlist import Hostlist
21+
from flux.idset import IDset
2022
from flux.job import JobID, JobInfo, JobInfoFormat, JobList, job_fields_to_attrs
2123
from flux.job.stats import JobStats
2224
from flux.util import (
@@ -156,6 +158,16 @@ def fetch_jobs_flux(args, fields, flux_handle=None):
156158
if not args.filter:
157159
args.filter = {"pending", "running"}
158160

161+
constraint = None
162+
if args.include:
163+
try:
164+
constraint = {"ranks": [IDset(args.include).encode()]}
165+
except ValueError:
166+
try:
167+
constraint = {"hostlist": [Hostlist(args.include).encode()]}
168+
except ValueError:
169+
raise ValueError(f"-i/--include: invalid targets: {args.include}")
170+
159171
jobs_rpc = JobList(
160172
flux_handle,
161173
ids=args.jobids,
@@ -166,6 +178,7 @@ def fetch_jobs_flux(args, fields, flux_handle=None):
166178
since=since,
167179
name=args.name,
168180
queue=args.queue,
181+
constraint=constraint,
169182
)
170183

171184
jobs = jobs_rpc.jobs()
@@ -270,6 +283,14 @@ def parse_args():
270283
metavar="QUEUE,...",
271284
help="Limit output to specific queue or queues",
272285
)
286+
parser.add_argument(
287+
"-i",
288+
"--include",
289+
type=str,
290+
metavar="HOSTS|RANKS",
291+
help="Limit output to jobs that were allocated to the specified "
292+
+ "HOSTS or RANKS provided as a hostlist or idset.",
293+
)
273294
parser.add_argument(
274295
"-o",
275296
"--format",

t/python/t0013-job-list.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,18 @@ def test_18_list_id_fail(self):
320320
with self.assertRaises(FileNotFoundError):
321321
rpc_handle.get_jobinfo()
322322

323+
def test_19_list_inactive_constraints(self):
324+
for job in flux.job.job_list_inactive(
325+
self.fh, constraint={"name": ["sleep"]}
326+
).get_jobinfos():
327+
self.assertEqual(job.name, "sleep")
328+
329+
def test_20_list_constraints(self):
330+
for job in flux.job.job_list(
331+
self.fh, constraint={"name": ["sleep"]}
332+
).get_jobinfos():
333+
self.assertEqual(job.name, "sleep")
334+
323335

324336
if __name__ == "__main__":
325337
from subflux import rerun_under_flux

t/t2800-jobs-cmd.t

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,28 @@ test_expect_success 'flux-jobs --count works' '
412412
test $count -eq 8
413413
'
414414

415+
#
416+
# -i, --include tests
417+
#
418+
test_expect_success 'flux-jobs -i, --include works with ranks' '
419+
for rank in $(flux jobs -ai 0 -no {ranks}); do
420+
test $rank -eq 0
421+
done
422+
'
423+
test_expect_success 'flux-jobs -i, --include works with ranks' '
424+
for rank in $(flux jobs -ai 0,3 -no {ranks}); do
425+
test $rank -eq 0 -o $rank -eq 3
426+
done
427+
'
428+
test_expect_success 'flux jobs -i, --include works with hosts' '
429+
for host in $(flux jobs -ai $(hostname) -no {nodelist}); do
430+
test $host = $(hostname)
431+
done
432+
'
433+
test_expect_success 'flux jobs -i, --include fails with bad idset/hostlist' '
434+
test_must_fail flux jobs -ai "foo["
435+
'
436+
415437
#
416438
# test specific IDs
417439
#

0 commit comments

Comments
 (0)