Add 'apps/arv-web/' from commit 'f9732ad8460d013c2f28363655d0d1b91894dca5'
[arvados.git] / services / nodemanager / arvnodeman / computenode / dispatch / slurm.py
1 #!/usr/bin/env python
2
3 from __future__ import absolute_import, print_function
4
5 import subprocess
6 import time
7
8 from . import \
9     ComputeNodeSetupActor, ComputeNodeUpdateActor, ComputeNodeMonitorActor
10 from . import ComputeNodeShutdownActor as ShutdownActorBase
11
12 class ComputeNodeShutdownActor(ShutdownActorBase):
13     SLURM_END_STATES = frozenset(['down\n', 'down*\n', 'drain\n', 'fail\n'])
14
15     def on_start(self):
16         arv_node = self._monitor.arvados_node.get()
17         if arv_node is None:
18             return super(ComputeNodeShutdownActor, self).on_start()
19         else:
20             self._nodename = arv_node['hostname']
21             self._logger.info("Draining SLURM node %s", self._nodename)
22             self._later.issue_slurm_drain()
23
24     def _set_node_state(self, state, *args):
25         cmd = ['scontrol', 'update', 'NodeName=' + self._nodename,
26                'State=' + state]
27         cmd.extend(args)
28         subprocess.check_output(cmd)
29
30     @ShutdownActorBase._retry((subprocess.CalledProcessError,))
31     def cancel_shutdown(self):
32         self._set_node_state('RESUME')
33         return super(ComputeNodeShutdownActor, self).cancel_shutdown()
34
35     @ShutdownActorBase._stop_if_window_closed
36     @ShutdownActorBase._retry((subprocess.CalledProcessError,))
37     def issue_slurm_drain(self):
38         self._set_node_state('DRAIN', 'Reason=Node Manager shutdown')
39         self._logger.info("Waiting for SLURM node %s to drain", self._nodename)
40         self._later.await_slurm_drain()
41
42     @ShutdownActorBase._stop_if_window_closed
43     @ShutdownActorBase._retry((subprocess.CalledProcessError,))
44     def await_slurm_drain(self):
45         output = subprocess.check_output(
46             ['sinfo', '--noheader', '-o', '%t', '-n', self._nodename])
47         if output in self.SLURM_END_STATES:
48             self._later.shutdown_node()
49         else:
50             self._timer.schedule(time.time() + 10,
51                                  self._later.await_slurm_drain)