From 24cd095c6e95779b32fcf28a5d9727ea7c59133e Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Fri, 20 Nov 2015 20:16:24 -0500 Subject: [PATCH] upgrades: Run as background task (Closes: #285). --- .../modules/upgrades/templates/upgrades.html | 88 ++++++++++++++++--- .../upgrades/templates/upgrades_run.html | 68 -------------- plinth/modules/upgrades/views.py | 61 +++++++++---- 3 files changed, 121 insertions(+), 96 deletions(-) delete mode 100644 plinth/modules/upgrades/templates/upgrades_run.html diff --git a/plinth/modules/upgrades/templates/upgrades.html b/plinth/modules/upgrades/templates/upgrades.html index c68a03656..f347d23fc 100644 --- a/plinth/modules/upgrades/templates/upgrades.html +++ b/plinth/modules/upgrades/templates/upgrades.html @@ -20,23 +20,87 @@ {% load i18n %} +{% block page_head %} + + {% if running %} + + {% endif %} + +{% endblock %} + + {% block content %}

{{ title }}

-

- {% blocktrans trimmed %} - This will run unattended-upgrades, which will attempt to upgrade - your system with the latest Debian packages. It may take a few - minutes to complete. - {% endblocktrans %} -

+ {% if result %} -
- {% csrf_token %} + {% if result.error %} + - -
+
{% trans "Output from unattended-upgrades:" %}
+ +
{{ result.error }}
+ {% endif %} + + {% if result.output %} +
+
+ +
+
+ +
+
{% trans "Output from unattended-upgrades:" %}
+
{{ result.output }}
+
+ + {% endif %} + + {% endif %} + + + {% if not result and not running %} +

+ {% blocktrans trimmed %} + This will run unattended-upgrades, which will attempt to upgrade + your system with the latest Debian packages. It may take a few + minutes to complete. + {% endblocktrans %} +

+ +
+ {% csrf_token %} + + +
+ {% endif %} + + {% if running %} +

+ + {% trans "Upgrade is running" %} +

+ {% endif %} {% endblock %} + +{% block page_js %} + +{% endblock %} diff --git a/plinth/modules/upgrades/templates/upgrades_run.html b/plinth/modules/upgrades/templates/upgrades_run.html deleted file mode 100644 index aa904c28b..000000000 --- a/plinth/modules/upgrades/templates/upgrades_run.html +++ /dev/null @@ -1,68 +0,0 @@ -{% extends 'base.html' %} -{% comment %} -# -# This file is part of Plinth. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -{% endcomment %} - -{% load i18n %} - -{% block content %} - -

{{title}}

- - {% if upgrades_error %} - - -
{% trans "Output from unattended-upgrades:" %}
- -
{{ upgrades_error }}
- {% endif %} - - {% if upgrades_output %} -
-
- -
-
- -
-
{% trans "Output from unattended-upgrades:" %}
-
{{ upgrades_output }}
-
- - {% endif %} - -{% endblock %} - -{% block page_js %} - -{% endblock %} diff --git a/plinth/modules/upgrades/views.py b/plinth/modules/upgrades/views.py index 6a077949d..4d1d9bccc 100644 --- a/plinth/modules/upgrades/views.py +++ b/plinth/modules/upgrades/views.py @@ -21,6 +21,7 @@ Plinth module for upgrades from django.contrib import messages from django.core.urlresolvers import reverse_lazy +from django.shortcuts import redirect from django.template.response import TemplateResponse from django.utils.translation import ugettext as _, ugettext_lazy from django.views.decorators.http import require_POST @@ -35,6 +36,8 @@ subsubmenu = [{'url': reverse_lazy('upgrades:index'), {'url': reverse_lazy('upgrades:upgrade'), 'text': ugettext_lazy('Upgrade Packages')}] +upgrade_process = None + def on_install(): """Enable automatic upgrades after install.""" @@ -66,29 +69,28 @@ def index(request): @package.required(['unattended-upgrades'], on_install=on_install) def upgrade(request): """Serve the upgrade page.""" + if upgrade_process: + result = _collect_upgrade_result(request) + else: + result = None + return TemplateResponse(request, 'upgrades.html', {'title': _('Package Upgrades'), - 'subsubmenu': subsubmenu}) + 'subsubmenu': subsubmenu, + 'running': bool(upgrade_process), + 'result': result}) @require_POST @package.required(['unattended-upgrades'], on_install=on_install) -def run(request): - """Run upgrades and show the output page.""" - output = '' - error = '' - try: - output = actions.superuser_run('upgrades', ['run']) - except ActionError as exception: - output, error = exception.args[1:] - except Exception as exception: - error = str(exception) +def run(_): + """Start the upgrade process.""" + global upgrade_process + if not upgrade_process: + upgrade_process = actions.superuser_run( + 'upgrades', ['run'], async=True) - return TemplateResponse(request, 'upgrades_run.html', - {'title': _('Package Upgrades'), - 'subsubmenu': subsubmenu, - 'upgrades_output': output, - 'upgrades_error': error}) + return redirect('upgrades:upgrade') def get_status(): @@ -122,3 +124,30 @@ def _apply_changes(request, old_status, new_status): messages.success(request, _('Automatic upgrades enabled')) else: messages.success(request, _('Automatic upgrades disabled')) + + +def _collect_upgrade_result(request): + """Handle upgrade process completion.""" + global upgrade_process + if not upgrade_process: + return + + return_code = upgrade_process.poll() + + # Upgrade process is not complete yet + if return_code == None: + return + + output, error = upgrade_process.communicate() + output, error = output.decode(), error.decode() + + if not return_code: + messages.success(request, _('Upgrade completed.')) + else: + messages.info(request, _('Upgrade failed.')) + + upgrade_process = None + + return {'return_code': return_code, + 'output': output, + 'error': error}