From e5b0fe7198846d02bdc1bbbd9fb6a721fd7bafd0 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Wed, 9 Aug 2017 11:44:31 -0500 Subject: [PATCH] Add running display of stdout.log when executing upgrade --- tailbone/static/css/progress.css | 59 ++++++++++++++ tailbone/templates/progress.mako | 135 ++++++++++++------------------- tailbone/templates/upgrade.mako | 77 ++++++++++++++++++ tailbone/views/core.py | 7 +- tailbone/views/master.py | 12 ++- tailbone/views/upgrades.py | 45 ++++++++++- 6 files changed, 243 insertions(+), 92 deletions(-) create mode 100644 tailbone/static/css/progress.css create mode 100644 tailbone/templates/upgrade.mako diff --git a/tailbone/static/css/progress.css b/tailbone/static/css/progress.css new file mode 100644 index 00000000..84aab4e4 --- /dev/null +++ b/tailbone/static/css/progress.css @@ -0,0 +1,59 @@ + +/******************************************************************************** + * progress.css + * + * Styles for progress bar page. + ********************************************************************************/ + + +/****************************** + * general + ******************************/ + +#body-wrapper { + position: relative; +} + +#wrapper { + height: 60px; + left: 50%; + margin-top: -45px; + margin-left: -350px; + position: absolute; + top: 50%; + width: 700px; +} + +/****************************** + * progress bar + ******************************/ + +#progress-wrapper { + border-collapse: collapse; +} + +#progress { + border-collapse: collapse; + height: 25px; + width: 550px; +} + +#complete { + background-color: Gray; + width: 0px; +} + +#remaining { + background-color: LightGray; + width: 100%; +} + +#percentage { + padding-left: 3px; + min-width: 50px; + width: 50px; +} + +#cancel .ui-button-text { + white-space: nowrap; +} diff --git a/tailbone/templates/progress.mako b/tailbone/templates/progress.mako index 4bd2b4bd..c378a986 100644 --- a/tailbone/templates/progress.mako +++ b/tailbone/templates/progress.mako @@ -5,98 +5,19 @@ - Working... + ${initial_msg or "Working"}... ${core_javascript()} ${h.stylesheet_link(request.static_url('tailbone:static/css/normalize.css'))} ${jquery_theme()} ${h.stylesheet_link(request.static_url('tailbone:static/css/base.css'))} ${h.stylesheet_link(request.static_url('tailbone:static/css/layout.css'))} - - + + +<%def name="extra_styles()"> + +<%def name="after_progress()"> diff --git a/tailbone/templates/upgrade.mako b/tailbone/templates/upgrade.mako new file mode 100644 index 00000000..fad77dd3 --- /dev/null +++ b/tailbone/templates/upgrade.mako @@ -0,0 +1,77 @@ +## -*- coding: utf-8; -*- +<%inherit file="/progress.mako" /> + +<%def name="update_progress_func()"> + + + +<%def name="extra_styles()"> + ${parent.extra_styles()} + + + +<%def name="after_progress()"> +
+ + +${parent.body()} diff --git a/tailbone/views/core.py b/tailbone/views/core.py index c1a2f0fe..ba3d1f9b 100644 --- a/tailbone/views/core.py +++ b/tailbone/views/core.py @@ -90,12 +90,15 @@ class View(object): def progress_loop(self, func, items, factory, *args, **kwargs): return progress_loop(func, items, factory, *args, **kwargs) - def render_progress(self, progress, kwargs): + # TODO: this signature seems wonky + def render_progress(self, progress, kwargs, template=None): """ Render the progress page, with given kwargs as context. """ + if not template: + template = '/progress.mako' kwargs['progress'] = progress - return render_to_response('/progress.mako', kwargs, request=self.request) + return render_to_response(template, kwargs, request=self.request) def file_response(self, path): """ diff --git a/tailbone/views/master.py b/tailbone/views/master.py index 6163bd98..173d4ff8 100644 --- a/tailbone/views/master.py +++ b/tailbone/views/master.py @@ -71,8 +71,10 @@ class MasterView(View): bulk_deletable = False mergeable = False downloadable = False - executable = False cloneable = False + executable = False + execute_progress_template = None + execute_progress_initial_msg = None supports_mobile = False mobile_creatable = False @@ -841,20 +843,22 @@ class MasterView(View): model_title = self.get_model_title() if self.request.method == 'POST': - progress = self.make_execute_progress() + progress = self.make_execute_progress(obj) kwargs = {'progress': progress} thread = Thread(target=self.execute_thread, args=(obj.uuid, self.request.user.uuid), kwargs=kwargs) thread.start() return self.render_progress(progress, { + 'instance': obj, + 'initial_msg': self.execute_progress_initial_msg, 'cancel_url': self.get_action_url('view', obj), 'cancel_msg': "{} execution was canceled".format(model_title), - }) + }, template=self.execute_progress_template) self.request.session.flash("Sorry, you must POST to execute a {}.".format(model_title), 'error') return self.redirect(self.get_action_url('view', obj)) - def make_execute_progress(self): + def make_execute_progress(self, obj): key = '{}.execute'.format(self.get_grid_key()) return SessionProgress(self.request, key) diff --git a/tailbone/views/upgrades.py b/tailbone/views/upgrades.py index b02ac095..0ef43e5f 100644 --- a/tailbone/views/upgrades.py +++ b/tailbone/views/upgrades.py @@ -43,7 +43,7 @@ from deform import widget as dfwidget from webhelpers2.html import tags from tailbone.views import MasterView3 as MasterView -from tailbone.progress import SessionProgress +from tailbone.progress import SessionProgress, get_progress_session class UpgradeView(MasterView): @@ -51,9 +51,12 @@ class UpgradeView(MasterView): Master view for all user events """ model_class = model.Upgrade - executable = True downloadable = True cloneable = True + executable = True + execute_progress_template = '/upgrade.mako' + execute_progress_initial_msg = "Upgrading" + labels = { 'executed_by': "Executed by", 'status_code': "Status", @@ -281,6 +284,44 @@ class UpgradeView(MasterView): upgrade.executed = make_utc() upgrade.executed_by = user + def execute_progress(self): + upgrade = self.get_instance() + key = '{}.execute'.format(self.get_grid_key()) + session = get_progress_session(self.request, key) + if session.get('complete'): + msg = session.get('success_msg') + if msg: + self.request.session.flash(msg) + elif session.get('error'): + self.request.session.flash(session.get('error_msg', "An unspecified error occurred."), 'error') + data = dict(session) + + path = self.rattail_config.upgrade_filepath(upgrade.uuid, filename='stdout.log') + offset = session.get('stdout.offset', 0) + size = os.path.getsize(path) - offset + with open(path, 'rb') as f: + f.seek(offset) + chunk = f.read(size) + data['stdout'] = chunk.replace('\n', '
') + session['stdout.offset'] = offset + size + session.save() + + return data + + @classmethod + def defaults(cls, config): + route_prefix = cls.get_route_prefix() + url_prefix = cls.get_url_prefix() + permission_prefix = cls.get_permission_prefix() + model_key = cls.get_model_key() + + # execution progress + config.add_route('{}.execute_progress'.format(route_prefix), '{}/{{{}}}/execute/progress'.format(url_prefix, model_key)) + config.add_view(cls, attr='execute_progress', route_name='{}.execute_progress'.format(route_prefix), + permission='{}.execute'.format(permission_prefix), renderer='json') + + cls._defaults(config) + def includeme(config): UpgradeView.defaults(config)