3 from __future__ import absolute_import, print_function
10 ARVADOS_TIMEFMT = '%Y-%m-%dT%H:%M:%SZ'
11 ARVADOS_TIMESUBSEC_RE = re.compile(r'(\.\d+)Z$')
13 def arvados_node_fqdn(arvados_node, default_hostname='dynamic.compute'):
14 hostname = arvados_node.get('hostname') or default_hostname
15 return '{}.{}'.format(hostname, arvados_node['domain'])
17 def arvados_node_mtime(node):
18 return arvados_timestamp(node['modified_at'])
20 def arvados_timestamp(timestr):
21 subsec_match = ARVADOS_TIMESUBSEC_RE.search(timestr)
22 if subsec_match is None:
25 subsecs = float(subsec_match.group(1))
26 timestr = timestr[:subsec_match.start()] + 'Z'
27 return calendar.timegm(time.strptime(timestr + 'UTC',
28 ARVADOS_TIMEFMT + '%Z'))
30 def timestamp_fresh(timestamp, fresh_time):
31 return (time.time() - timestamp) < fresh_time
33 class ShutdownTimer(object):
34 """Keep track of a cloud node's shutdown windows.
36 Instantiate this class with a timestamp of when a cloud node started,
37 and a list of durations (in minutes) of when the node must not and may
38 be shut down, alternating. The class will tell you when a shutdown
39 window is open, and when the next open window will start.
41 def __init__(self, start_time, shutdown_windows):
42 # The implementation is easiest if we have an even number of windows,
43 # because then windows always alternate between open and closed.
44 # Rig that up: calculate the first shutdown window based on what's
45 # passed in. Then, if we were given an odd number of windows, merge
46 # that first window into the last one, since they both# represent
48 first_window = shutdown_windows[0]
49 shutdown_windows = list(shutdown_windows[1:])
50 self._next_opening = start_time + (60 * first_window)
51 if len(shutdown_windows) % 2:
52 shutdown_windows.append(first_window)
54 shutdown_windows[-1] += first_window
55 self.shutdown_windows = itertools.cycle([60 * n
56 for n in shutdown_windows])
57 self._open_start = self._next_opening
58 self._open_for = next(self.shutdown_windows)
60 def _advance_opening(self):
61 while self._next_opening < time.time():
62 self._open_start = self._next_opening
63 self._next_opening += self._open_for + next(self.shutdown_windows)
64 self._open_for = next(self.shutdown_windows)
66 def next_opening(self):
67 self._advance_opening()
68 return self._next_opening
70 def window_open(self):
71 self._advance_opening()
72 return 0 < (time.time() - self._open_start) < self._open_for