2853: Merge branch 'master' into 2853-rendezvous
[arvados.git] / services / nodemanager / arvnodeman / computenode / __init__.py
1 #!/usr/bin/env python
2
3 from __future__ import absolute_import, print_function
4
5 import itertools
6 import time
7
8 def arvados_node_fqdn(arvados_node, default_hostname='dynamic.compute'):
9     hostname = arvados_node.get('hostname') or default_hostname
10     return '{}.{}'.format(hostname, arvados_node['domain'])
11
12 def arvados_node_mtime(node):
13     return time.mktime(time.strptime(node['modified_at'] + 'UTC',
14                                      '%Y-%m-%dT%H:%M:%SZ%Z')) - time.timezone
15
16 def timestamp_fresh(timestamp, fresh_time):
17     return (time.time() - timestamp) < fresh_time
18
19 class ShutdownTimer(object):
20     """Keep track of a cloud node's shutdown windows.
21
22     Instantiate this class with a timestamp of when a cloud node started,
23     and a list of durations (in minutes) of when the node must not and may
24     be shut down, alternating.  The class will tell you when a shutdown
25     window is open, and when the next open window will start.
26     """
27     def __init__(self, start_time, shutdown_windows):
28         # The implementation is easiest if we have an even number of windows,
29         # because then windows always alternate between open and closed.
30         # Rig that up: calculate the first shutdown window based on what's
31         # passed in.  Then, if we were given an odd number of windows, merge
32         # that first window into the last one, since they both# represent
33         # closed state.
34         first_window = shutdown_windows[0]
35         shutdown_windows = list(shutdown_windows[1:])
36         self._next_opening = start_time + (60 * first_window)
37         if len(shutdown_windows) % 2:
38             shutdown_windows.append(first_window)
39         else:
40             shutdown_windows[-1] += first_window
41         self.shutdown_windows = itertools.cycle([60 * n
42                                                  for n in shutdown_windows])
43         self._open_start = self._next_opening
44         self._open_for = next(self.shutdown_windows)
45
46     def _advance_opening(self):
47         while self._next_opening < time.time():
48             self._open_start = self._next_opening
49             self._next_opening += self._open_for + next(self.shutdown_windows)
50             self._open_for = next(self.shutdown_windows)
51
52     def next_opening(self):
53         self._advance_opening()
54         return self._next_opening
55
56     def window_open(self):
57         self._advance_opening()
58         return 0 < (time.time() - self._open_start) < self._open_for