1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
5 from __future__ import absolute_import, print_function
6 from future import standard_library
15 from ._version import __version__
17 _logger = logging.getLogger('status.Handler')
20 class Server(socketserver.ThreadingMixIn, http.server.HTTPServer, object):
21 def __init__(self, config):
22 port = config.getint('Manage', 'port')
23 self.enabled = port >= 0
25 _logger.warning("Management server disabled. "+
26 "Use [Manage] config section to enable.")
29 self._tracker = tracker
30 self._tracker.update({'config_max_nodes': config.getint('Daemon', 'max_nodes')})
31 super(Server, self).__init__(
32 (config.get('Manage', 'address'), port), Handler)
33 self._thread = threading.Thread(target=self.serve_forever)
34 self._thread.daemon = True
41 class Handler(http.server.BaseHTTPRequestHandler, object):
43 if self.path == '/status.json':
44 self.send_response(200)
45 self.send_header('Content-type', 'application/json')
47 self.wfile.write(tracker.get_json())
48 elif self.path == '/_health/ping':
49 code, msg = self.check_auth()
52 self.send_response(code)
55 self.send_response(200)
56 self.send_header('Content-type', 'application/json')
58 self.wfile.write(json.dumps({"health":"OK"}))
60 self.send_response(404)
62 def log_message(self, fmt, *args, **kwargs):
63 _logger.info(fmt, *args, **kwargs)
66 mgmt_token = self.server._config.get('Manage', 'ManagementToken')
67 auth_header = self.headers.get('Authorization', None)
70 return 404, "disabled"
71 elif auth_header == None:
72 return 401, "authorization required"
73 elif auth_header != 'Bearer '+mgmt_token:
74 return 403, "authorization error"
77 class Tracker(object):
79 self._mtx = threading.Lock()
81 'list_nodes_errors': 0,
82 'create_node_errors': 0,
83 'destroy_node_errors': 0,
87 self._version = {'Version' : __version__}
92 times = {'idle_times' : {}}
94 for node, ts in self._idle_nodes.items():
95 times['idle_times'][node] = int(now - ts)
97 dict(dict(self._latest, **self._version), **times))
101 return self._latest.keys()
105 return self._latest.get(key)
107 def update(self, updates):
109 self._latest.update(updates)
111 def counter_add(self, counter, value=1):
113 self._latest.setdefault(counter, 0)
114 self._latest[counter] += value
116 def idle_in(self, nodename):
118 if self._idle_nodes.get(nodename):
120 self._idle_nodes[nodename] = time.time()
122 def idle_out(self, nodename):
125 del self._idle_nodes[nodename]