@@ -38,6 +38,7 @@ from pyslurm.utils.helpers import (
3838 instance_to_dict,
3939 _sum_prop,
4040 nodelist_from_range_str,
41+ nodelist_to_range_str,
4142)
4243
4344
@@ -157,10 +158,37 @@ cdef class Nodes(dict):
157158 """ Format the information as list of Node objects.
158159
159160 Returns:
160- (list): List of Node objects
161+ (list[pyslurm.Node] ): List of Node objects
161162 """
162163 return list (self .values())
163164
165+ def modify (self , Node changes ):
166+ """ Modify all Nodes in a collection.
167+
168+ Args:
169+ changes (pyslurm.Node):
170+ Another Node object that contains all the changes to apply.
171+ Check the `Other Parameters` of the Node class to see which
172+ properties can be modified.
173+
174+ Raises:
175+ RPCError: When updating the Node was not successful.
176+
177+ Examples:
178+ >>> import pyslurm
179+ >>>
180+ >>> nodes = pyslurm.Nodes.load()
181+ >>> # Prepare the changes
182+ >>> changes = pyslurm.Node(state="DRAIN", reason="DRAIN Reason")
183+ >>> # Apply the changes to all the nodes
184+ >>> nodes.modify(changes)
185+ """
186+ cdef Node n = < Node> changes
187+ node_str = nodelist_to_range_str(list (self .keys()))
188+ n._alloc_umsg()
189+ cstr.fmalloc(& n.umsg.node_names, node_str)
190+ verify_rpc(slurm_update_node(n.umsg))
191+
164192 @property
165193 def free_memory (self ):
166194 return _sum_prop(self , Node.free_memory)
@@ -340,25 +368,27 @@ cdef class Node:
340368
341369 return self
342370
343- def modify (self , changes ):
371+ def modify (self , Node changes ):
344372 """ Modify a node.
345373
346374 Implements the slurm_update_node RPC.
347375
348376 Args:
349377 changes (pyslurm.Node):
350- Another Node object which contains all the changes that
351- should be applied to this instance.
378+ Another Node object that contains all the changes to apply.
379+ Check the `Other Parameters` of the Node class to see which
380+ properties can be modified.
352381
353382 Raises:
354383 RPCError: When updating the Node was not successful.
355384
356385 Examples:
357386 >>> import pyslurm
358387 >>>
359- >>> mynode = pyslurm.Node("localhost")
360- >>> changes = pyslurm.Node(weight=100)
361- >>> # Setting the weight to 100 for the "localhost" node
388+ >>> mynode = pyslurm.Node.load("localhost")
389+ >>> # Prepare the changes
390+ >>> changes = pyslurm.Node(state="DRAIN", reason="DRAIN Reason")
391+ >>> # Modify it
362392 >>> mynode.modify(changes)
363393 """
364394 cdef Node n = < Node> changes
@@ -448,6 +478,10 @@ cdef class Node:
448478 def reason (self ):
449479 return cstr.to_unicode(self .info.reason)
450480
481+ @reason.setter
482+ def reason (self , val ):
483+ cstr.fmalloc2(& self .info.reason, & self .umsg.reason, val)
484+
451485 @property
452486 def reason_user (self ):
453487 return uid_to_name(self .info.reason_uid, lookup = self .passwd)
@@ -667,6 +701,10 @@ cdef class Node:
667701 xfree(state)
668702 return state_str
669703
704+ @state.setter
705+ def state (self , val ):
706+ self .umsg.node_state= self .info.node_state = _node_state_from_str(val)
707+
670708 @property
671709 def next_state (self ):
672710 if ((self .info.next_state != slurm.NO_VAL)
@@ -677,10 +715,6 @@ cdef class Node:
677715 else :
678716 return None
679717
680- @state.setter
681- def state (self , val ):
682- self .umsg.node_state= self .info.node_state = _node_state_from_str(val)
683-
684718 @property
685719 def cpu_load (self ):
686720 load = u32_parse(self .info.cpu_load)
@@ -694,10 +728,36 @@ cdef class Node:
694728def _node_state_from_str (state , err_on_invalid = True ):
695729 if not state:
696730 return slurm.NO_VAL
697-
698- for i in range (slurm.NODE_STATE_END):
699- if state == slurm_node_state_string(i):
700- return i
731+ ustate = state.upper()
732+
733+ # Following states are explicitly possible as per documentation
734+ # https://slurm.schedmd.com/scontrol.html#OPT_State_1
735+ if ustate == " CANCEL_REBOOT" :
736+ return slurm.NODE_STATE_CANCEL_REBOOT
737+ elif ustate == " DOWN" :
738+ return slurm.NODE_STATE_DOWN
739+ elif ustate == " DRAIN" :
740+ return slurm.NODE_STATE_DRAIN
741+ elif ustate == " FAIL" :
742+ return slurm.NODE_STATE_FAIL
743+ elif ustate == " FUTURE" :
744+ return slurm.NODE_STATE_FUTURE
745+ elif ustate == " NORESP" or ustate == " NO_RESP" :
746+ return slurm.NODE_STATE_NO_RESPOND
747+ elif ustate == " POWER_DOWN" :
748+ return slurm.NODE_STATE_POWER_DOWN
749+ elif ustate == " POWER_DOWN_ASAP" :
750+ # Drain and mark for power down
751+ return slurm.NODE_STATE_POWER_DOWN | slurm.NODE_STATE_POWER_DRAIN
752+ elif ustate == " POWER_DOWN_FORCE" :
753+ # Kill all Jobs and power down
754+ return slurm.NODE_STATE_POWER_DOWN | slurm.NODE_STATE_POWERED_DOWN
755+ elif ustate == " POWER_UP" :
756+ return slurm.NODE_STATE_POWER_UP
757+ elif ustate == " RESUME" :
758+ return slurm.NODE_RESUME
759+ elif ustate == " UNDRAIN" :
760+ return slurm.NODE_STATE_UNDRAIN
701761
702762 if err_on_invalid:
703763 raise ValueError (f" Invalid Node state: {state}" )
0 commit comments