Skip to content

Commit 37f7e22

Browse files
authored
Few fixes and handle modification consistently (#300)
- handle modification of objects via `modify()` consistently - use correct list of node states when modifying the node state - remove `consumable_resource` attribute of Partition class again, logic is merged into the `select_type_parameters` attribute
1 parent a84d23c commit 37f7e22

File tree

11 files changed

+182
-85
lines changed

11 files changed

+182
-85
lines changed

docs/reference/index.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ The `pyslurm` package is a wrapper around the Slurm C-API
4141
* Node API
4242
* [pyslurm.Node][]
4343
* [pyslurm.Nodes][]
44+
* Partition API
45+
* [pyslurm.Partition][]
46+
* [pyslurm.Partitions][]
4447
* New Exceptions
4548
* [pyslurm.RPCError][]
4649
* [pyslurm.PyslurmError][]

pyslurm/core/job/job.pyx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ cdef class Jobs(dict):
9292
9393
Raises:
9494
RPCError: When getting all the Jobs from the slurmctld failed.
95-
MemoryError: If malloc fails to allocate memory.
9695
"""
9796
cdef:
9897
dict passwd = {}
@@ -188,7 +187,7 @@ cdef class Jobs(dict):
188187
"""Format the information as list of Job objects.
189188
190189
Returns:
191-
(list): List of Job objects
190+
(list[pyslurm.Job]): List of Job objects
192191
"""
193192
return list(self.values())
194193

@@ -258,7 +257,6 @@ cdef class Job:
258257
Raises:
259258
RPCError: If requesting the Job information from the slurmctld was
260259
not successful.
261-
MemoryError: If malloc failed to allocate memory.
262260
263261
Examples:
264262
>>> import pyslurm

pyslurm/core/job/step.pyx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -279,15 +279,17 @@ cdef class JobStep:
279279
step_id = self.ptr.step_id.step_id
280280
verify_rpc(slurm_kill_job_step(self.job_id, step_id, 9))
281281

282-
def modify(self, changes):
282+
def modify(self, JobStep changes):
283283
"""Modify a job step.
284284
285285
Implements the slurm_update_step RPC.
286286
287287
Args:
288288
changes (pyslurm.JobStep):
289-
Another JobStep object which contains all the changes that
290-
should be applied to this instance.
289+
Another JobStep object that contains all the changes to apply.
290+
Check the `Other Parameters` of the JobStep class to see which
291+
properties can be modified.
292+
291293
Raises:
292294
RPCError: When updating the JobStep was not successful.
293295

pyslurm/core/node.pxd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ cdef class Node:
121121
Default CPU-Binding for the node
122122
state (str):
123123
State of the node
124+
reason (str):
125+
Reason for the Node, typically used along with updating the node
126+
state
124127
125128
Attributes:
126129
name (str):

pyslurm/core/node.pyx

Lines changed: 75 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -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:
694728
def _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}")

pyslurm/core/partition.pxd

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ cdef class Partition:
101101
* total_cpus
102102
* total_nodes
103103
* select_type_parameters
104-
* consumable_resource
105104
106105
Attributes:
107106
name (str):
@@ -116,10 +115,8 @@ cdef class Partition:
116115
List of QoS which are allowed to execute Jobs
117116
alternate (str):
118117
Name of the alternate Partition in case a Partition is down.
119-
consumable_resource (str):
120-
The type of consumable resource used in the Partition.
121118
select_type_parameters (list[str]):
122-
List of additional parameters passed to the select plugin used.
119+
List of Select type parameters for the select plugin.
123120
cpu_binding (str):
124121
Default CPU-binding for Jobs that execute in a Partition.
125122
default_memory_per_cpu (int):

pyslurm/core/partition.pyx

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -143,18 +143,29 @@ cdef class Partitions(dict):
143143

144144
return self
145145

146-
def set_state(self, state):
147-
"""Modify the State of all Partitions in this Collection.
146+
def modify(self, changes):
147+
"""Modify all Partitions in a Collection.
148148
149149
Args:
150-
state (str):
151-
Partition state to set
150+
changes (pyslurm.Partition):
151+
Another Partition object that contains all the changes to
152+
apply. Check the `Other Parameters` of the Partition class to
153+
see which properties can be modified.
152154
153155
Raises:
154-
RPCError: When updating the state failed
156+
RPCError: When updating at least one Partition failed.
157+
158+
Examples:
159+
>>> import pyslurm
160+
>>>
161+
>>> parts = pyslurm.Partitions.load()
162+
>>> # Prepare the changes
163+
>>> changes = pyslurm.Partition(state="DRAIN")
164+
>>> # Apply the changes to all the partitions
165+
>>> parts.modify(changes)
155166
"""
156167
for part in self.values():
157-
part.modify(state=state)
168+
part.modify(changes)
158169

159170
def as_list(self):
160171
"""Format the information as list of Partition objects.
@@ -270,40 +281,30 @@ cdef class Partition:
270281
verify_rpc(slurm_create_partition(self.ptr))
271282
return self
272283

273-
def modify(self, **changes):
284+
def modify(self, Partition changes):
274285
"""Modify a Partition.
275286
276287
Implements the slurm_update_partition RPC.
277288
278289
Args:
279-
**changes (Any):
280-
Changes for the Partition. Almost every Attribute from a
281-
Partition can be modified, except for:
282-
283-
* total_cpus
284-
* total_nodes
285-
* select_type_parameters
286-
* consumable_resource
290+
changes (pyslurm.Partition):
291+
Another Partition object that contains all the changes to
292+
apply. Check the `Other Parameters` of the Partition class to
293+
see which properties can be modified.
287294
288295
Raises:
289-
ValueError: When no changes were specified or when a parsing error
290-
occured.
291296
RPCError: When updating the Partition was not successful.
292297
293298
Examples:
294299
>>> import pyslurm
295300
>>>
296-
>>> # Modifying the maximum time limit
297-
>>> mypart = pyslurm.Partition("normal")
298-
>>> mypart.modify(max_time_limit="10-00:00:00")
299-
>>>
300-
>>> # Modifying the partition state
301-
>>> mypart.modify(state="DRAIN")
301+
>>> part = pyslurm.Partition.load("normal")
302+
>>> # Prepare the changes
303+
>>> changes = pyslurm.Partition(state="DRAIN")
304+
>>> # Apply the changes to the "normal" Partition
305+
>>> part.modify(changes)
302306
"""
303-
if not changes:
304-
raise ValueError("No changes were specified")
305-
306-
cdef Partition part = Partition(**changes)
307+
cdef Partition part = <Partition>changes
307308
part.name = self._error_or_name()
308309
verify_rpc(slurm_update_partition(part.ptr))
309310

@@ -381,10 +382,6 @@ cdef class Partition:
381382
def alternate(self, val):
382383
cstr.fmalloc(&self.ptr.alternate, val)
383384

384-
@property
385-
def consumable_resource(self):
386-
return _select_type_int_to_cons_res(self.ptr.cr_type)
387-
388385
@property
389386
def select_type_parameters(self):
390387
return _select_type_int_to_list(self.ptr.cr_type)
@@ -757,7 +754,7 @@ def _split_oversubscribe_str(val):
757754
def _select_type_int_to_list(stype):
758755
# The rest of the CR_* stuff are just some extra parameters to the select
759756
# plugin
760-
out = []
757+
out = _select_type_int_to_cons_res(stype)
761758

762759
if stype & slurm.CR_OTHER_CONS_RES:
763760
out.append("OTHER_CONS_RES")
@@ -800,7 +797,7 @@ def _select_type_int_to_cons_res(stype):
800797
elif stype & slurm.CR_MEMORY:
801798
return "MEMORY"
802799
else:
803-
return None
800+
return []
804801

805802

806803
def _preempt_mode_str_to_int(mode):

0 commit comments

Comments
 (0)