@@ -351,6 +351,7 @@ def filternodes(self, job, nodes):
351351 option_parser .add_argument ('-w' , '--nodelist' )
352352 option_parser .add_argument ('-C' , '--constraint' )
353353 option_parser .add_argument ('-x' , '--exclude' )
354+ self .log (f'Filtering by Slurm options: { " " .join (options )} ' )
354355 parsed_args , _ = option_parser .parse_known_args (options )
355356 reservation = parsed_args .reservation
356357 partitions = parsed_args .partition
@@ -363,7 +364,7 @@ def filternodes(self, job, nodes):
363364 else :
364365 nodes = {node for node in nodes if not node .in_state ('RESERVED' )}
365366
366- self .log (f'[F] Filtering nodes by reservation={ reservation } : '
367+ self .log (f'Filtering nodes by reservation={ reservation } : '
367368 f'available nodes now: { len (nodes )} ' )
368369
369370 if partitions :
@@ -377,27 +378,27 @@ def filternodes(self, job, nodes):
377378 )
378379 partitions = {default_partition } if default_partition else set ()
379380 self .log (
380- f'[F] No partition specified; using { default_partition !r} '
381+ f'No partition specified; using { default_partition !r} '
381382 )
382383
383384 nodes = {n for n in nodes if n .partitions >= partitions }
384- self .log (f'[F] Filtering nodes by partition(s) { partitions } : '
385+ self .log (f'Filtering nodes by partition(s) { partitions } : '
385386 f'available nodes now: { len (nodes )} ' )
386387 if constraints :
387388 nodes = {n for n in nodes if n .satisfies (constraints )}
388- self .log (f'[F] Filtering nodes by constraint(s) { constraints } : '
389+ self .log (f'Filtering nodes by constraint(s) { constraints } : '
389390 f'available nodes now: { len (nodes )} ' )
390391
391392 if nodelist :
392393 nodelist = nodelist .strip ()
393394 nodes &= self ._get_nodes_by_name (nodelist )
394- self .log (f'[F] Filtering nodes by nodelist: { nodelist } : '
395+ self .log (f'Filtering nodes by nodelist: { nodelist } : '
395396 f'available nodes now: { len (nodes )} ' )
396397
397398 if exclude_nodes :
398399 exclude_nodes = exclude_nodes .strip ()
399400 nodes -= self ._get_nodes_by_name (exclude_nodes )
400- self .log (f'[F] Excluding node(s): { exclude_nodes } : '
401+ self .log (f'Excluding node(s): { exclude_nodes } : '
401402 f'available nodes now: { len (nodes )} ' )
402403
403404 return nodes
@@ -711,17 +712,29 @@ def is_down(self):
711712 return not self .is_avail ()
712713
713714 def satisfies (self , slurm_constraint ):
715+ def _replacemany (s , replacements ):
716+ for src , dst in replacements :
717+ s = s .replace (src , dst )
718+
719+ return s
720+
714721 # Convert the Slurm constraint to a Python expression and evaluate it,
715722 # but restrict our syntax to accept only AND or OR constraints and
716- # their combinations
717- if not re .match (r'^[\w\d\(\)\|\&]*$' , slurm_constraint ):
723+ # their combinations; to properly treat `-` in constraints we need to
724+ # convert them to valid Python identifiers before evaluating the
725+ # constraint.
726+ if not re .match (r'^[\-\w\d\(\)\|\&]*$' , slurm_constraint ):
718727 return False
719728
720- names = {grp [0 ]
721- for grp in re .finditer (r'(\w(\w|\d)*)' , slurm_constraint )}
722- expr = slurm_constraint .replace ('|' , ' or ' ).replace ('&' , ' and ' )
723- vars = {n : True for n in self .active_features }
724- vars .update ({n : False for n in names - self .active_features })
729+ names = {
730+ grp [0 ] for grp in re .finditer (r'[\-\w][\-\w\d]*' , slurm_constraint )
731+ }
732+ expr = _replacemany (slurm_constraint ,
733+ [('-' , '_' ), ('|' , ' or ' ), ('&' , ' and ' )])
734+ vars = {n .replace ('-' , '_' ): True for n in self .active_features }
735+ vars .update ({
736+ n .replace ('-' , '_' ): False for n in names - self .active_features
737+ })
725738 try :
726739 return eval (expr , {}, vars )
727740 except BaseException :
0 commit comments