summaryrefslogtreecommitdiff
path: root/lorrycontroller/status.py
diff options
context:
space:
mode:
Diffstat (limited to 'lorrycontroller/status.py')
-rw-r--r--lorrycontroller/status.py154
1 files changed, 154 insertions, 0 deletions
diff --git a/lorrycontroller/status.py b/lorrycontroller/status.py
new file mode 100644
index 0000000..9f42bef
--- /dev/null
+++ b/lorrycontroller/status.py
@@ -0,0 +1,154 @@
+# Copyright (C) 2014 Codethink Limited
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+import lorrycontroller
+
+
+class StatusRenderer(object):
+
+ '''Helper class for rendering service status as JSON/HTML'''
+
+ def get_status_as_dict(self, statedb, work_directory):
+ quotes = [
+ "Never get drunk unless you're willing to pay for it - "
+ "the next day.",
+ "I'm giving her all she's got, Captain!",
+ ]
+ import random
+ status = {
+ 'quote': '%s' % random.choice(quotes),
+ 'running_queue': statedb.get_running_queue(),
+ 'timestamp': time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime()),
+ 'run_queue': self.get_run_queue(statedb),
+ 'troves': self.get_troves(statedb),
+ 'warning_msg': '',
+ }
+ status.update(self.get_free_disk_space(work_directory))
+ return status
+
+ def render_status_as_html(self, template, status):
+ return bottle.template(template, **status)
+
+ def write_status_as_html(self, template, status, filename):
+ html = self.render_status_as_html(template, status)
+ try:
+ with open(filename, 'w') as f:
+ f.write(html)
+ except (OSError, IOError) as e:
+ status['warning_msg'] = (
+ 'ERROR WRITING STATUS HTML TO DISK: %s' % str(e))
+
+ def get_free_disk_space(self, dirname):
+ result = os.statvfs(dirname)
+ free_bytes = result.f_bavail * result.f_bsize
+ return {
+ 'disk_free': free_bytes,
+ 'disk_free_mib': free_bytes / 1024**2,
+ 'disk_free_gib': free_bytes / 1024**3,
+ }
+
+ def get_run_queue(self, statedb):
+ lorries = statedb.get_all_lorries_info()
+ now = time.time()
+ for lorry in lorries:
+ due = lorry['last_run'] + lorry['interval']
+ lorry['interval_nice'] = self.format_secs_nicely(lorry['interval'])
+ lorry['due_nice'] = self.format_due_nicely(due)
+ return lorries
+
+ def format_due_nicely(self, due):
+ now = int(time.time())
+ if due <= now:
+ return 'now'
+ else:
+ nice = self.format_secs_nicely(due - now)
+ return 'in %s' % nice
+
+ def format_secs_nicely(self, secs):
+ if secs <= 0:
+ return 'now'
+
+ result = []
+
+ hours = secs / 3600
+ secs %= 3600
+ mins = secs / 60
+ secs %= 60
+
+ if hours > 0:
+ result.append('%d h' % hours)
+ if mins > 0:
+ result.append('%d min' % mins)
+ elif mins > 0:
+ result.append('%d min' % mins)
+ if secs > 0:
+ result.append('%d s' % secs)
+ else:
+ result.append('%d s' % secs)
+
+ return ' '.join(result)
+
+ def get_troves(self, statedb):
+ troves = []
+ for trovehost in statedb.get_troves():
+ trove_info = statedb.get_trove_info(trovehost)
+
+ trove_info['ls_interval_nice'] = self.format_secs_nicely(
+ trove_info['ls_interval'])
+
+ ls_due = trove_info['ls_last_run'] + trove_info['ls_interval']
+ now = int(time.time())
+ trove_info['ls_due_nice'] = self.format_due_nicely(ls_due)
+
+ troves.append(trove_info)
+ return troves
+
+
+class Status(lorrycontroller.LorryControllerRoute):
+
+ http_method = 'GET'
+ path = '/1.0/status'
+
+ def run(self, **kwargs):
+ logging.info('%s %s called', self.http_method, self.path)
+ renderer = StatusRenderer()
+ statedb = self.open_statedb()
+ status = renderer.get_status_as_dict(
+ statedb, self.app_settings['statedb'])
+ renderer.write_status_as_html(
+ self._templates['status'],
+ status,
+ self.app_settings['status-html'])
+ return status
+
+
+class StatusHTML(lorrycontroller.LorryControllerRoute):
+
+ http_method = 'GET'
+ path = '/1.0/status-html'
+
+ def run(self, **kwargs):
+ logging.info('%s %s called', self.http_method, self.path)
+ renderer = StatusRenderer()
+ statedb = self.open_statedb()
+ status = renderer.get_status_as_dict(
+ statedb, self.app_settings['statedb'])
+ renderer.write_status_as_html(
+ self._templates['status'],
+ status,
+ self.app_settings['status-html'])
+ return renderer.render_status_as_html(
+ self._templates['status'], status)