From 76ffad7955cc61e01b7df90cd0d6d32f38207f97 Mon Sep 17 00:00:00 2001 From: hanisha Date: Fri, 8 Dec 2017 14:55:25 +0530 Subject: [PATCH] Option to enable/disble automatic timeline snapshots Signed-off-by: Hanisha P Reviewed-by: Joseph Nuthalapati --- actions/snapshot | 21 +++++++ plinth/modules/snapshot/__init__.py | 9 +++ plinth/modules/snapshot/forms.py | 29 ++++++++++ .../modules/snapshot/templates/snapshot.html | 37 +++++++------ plinth/modules/snapshot/views.py | 55 ++++++++++++++++--- 5 files changed, 126 insertions(+), 25 deletions(-) create mode 100644 plinth/modules/snapshot/forms.py diff --git a/actions/snapshot b/actions/snapshot index 778f54de0..69445cec9 100755 --- a/actions/snapshot +++ b/actions/snapshot @@ -38,6 +38,7 @@ def parse_arguments(): subparsers.add_parser('setup', help='Configure snapper') subparsers.add_parser('list', help='List snapshots') subparsers.add_parser('create', help='Create snapshot') + subparsers.add_parser('get-config', help='Configurations of snapshot') subparser = subparsers.add_parser('delete', help='Delete a snapshot by number') @@ -46,6 +47,10 @@ def parse_arguments(): subparser = subparsers.add_parser('delete-all', help='Delete all the snapshots') + subparser = subparsers.add_parser('configure', + help='Configure automatic snapshots') + subparser.add_argument('config') + subparser = subparsers.add_parser('rollback', help='Rollback to snapshot') subparser.add_argument('number', help='Number of snapshot to rollback to') @@ -163,6 +168,22 @@ def subcommand_delete_all(_): subprocess.run(command, check=True) +def subcommand_configure(arguments): + command = ['snapper', 'set-config', arguments.config] + subprocess.run(command, check=True) + + +def subcommand_get_config(_): + command = ['snapper', 'get-config'] + process = subprocess.run(command, stdout=subprocess.PIPE, check=True) + lines = process.stdout.decode().splitlines() + config = {} + for line in lines[2:]: + parts = [part.strip() for part in line.split('|')] + config[parts[0]] = parts[1] + print(json.dumps(config)) + + def subcommand_rollback(arguments): """Rollback to snapshot.""" command = [ diff --git a/plinth/modules/snapshot/__init__.py b/plinth/modules/snapshot/__init__.py index 647e47f33..d19bc4d92 100644 --- a/plinth/modules/snapshot/__init__.py +++ b/plinth/modules/snapshot/__init__.py @@ -23,6 +23,7 @@ from django.utils.translation import ugettext_lazy as _ from plinth import actions from plinth.menu import main_menu +import json version = 1 @@ -58,3 +59,11 @@ def setup(helper, old_version=None): """Install and configure the module.""" helper.install(managed_packages) helper.call('post', actions.superuser_run, 'snapshot', ['setup']) + + +def is_timeline_snapshots_enabled(): + """Return whether timeline snapshots are enabled.""" + output = actions.superuser_run('snapshot', ['get-config']) + output = json.loads(output) + return output['TIMELINE_CREATE'] == "yes" + diff --git a/plinth/modules/snapshot/forms.py b/plinth/modules/snapshot/forms.py new file mode 100644 index 000000000..60d7a31e0 --- /dev/null +++ b/plinth/modules/snapshot/forms.py @@ -0,0 +1,29 @@ +# +# 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 . +# +""" +Forms for snapshot module. +""" + +from django import forms +from django.utils.translation import ugettext_lazy as _ + + +class SnapshotForm(forms.Form): + enable_timeline_snapshots = forms.BooleanField( + label=_('Enable Timeline Snapshots'), required=False, help_text=_( + 'Uncheck this to disable timeline snapshots ' + '(hourly, daily, monthly and yearly).')) diff --git a/plinth/modules/snapshot/templates/snapshot.html b/plinth/modules/snapshot/templates/snapshot.html index 72c60005c..5de3fef4e 100644 --- a/plinth/modules/snapshot/templates/snapshot.html +++ b/plinth/modules/snapshot/templates/snapshot.html @@ -23,27 +23,32 @@ {% block configuration %}

-

-
- {% csrf_token %} + + {% csrf_token %} +

{% trans "Configuration" %}

+ {{ form|bootstrap }} + +
+

diff --git a/plinth/modules/snapshot/views.py b/plinth/modules/snapshot/views.py index 0a714be4c..ffaf1fb31 100644 --- a/plinth/modules/snapshot/views.py +++ b/plinth/modules/snapshot/views.py @@ -27,14 +27,27 @@ from django.urls import reverse from django.utils.translation import ugettext as _ from plinth import actions +from plinth.errors import ActionError from plinth.modules import snapshot as snapshot_module +from . import is_timeline_snapshots_enabled +from .forms import SnapshotForm + def index(request): """Show snapshot list.""" + status = get_status() if request.method == 'POST': - actions.superuser_run('snapshot', ['create']) - messages.success(request, _('Created snapshot.')) + form = SnapshotForm(request.POST, prefix='snapshot') + if 'create' in request.POST: + actions.superuser_run('snapshot', ['create']) + messages.success(request, _('Created snapshot.')) + if 'update' in request.POST and form.is_valid(): + _apply_changes(request, status, form.cleaned_data) + status = get_status() + form = SnapshotForm(initial=status, prefix='snapshot') + else: + form = SnapshotForm(initial=status, prefix='snapshot') output = actions.superuser_run('snapshot', ['list']) snapshots = json.loads(output) @@ -42,7 +55,8 @@ def index(request): return TemplateResponse(request, 'snapshot.html', { 'title': snapshot_module.name, 'description': snapshot_module.description, - 'snapshots': snapshots + 'snapshots': snapshots, + 'form': form }) @@ -50,9 +64,8 @@ def delete(request, number): """Show confirmation to delete a snapshot.""" if request.method == 'POST': actions.superuser_run('snapshot', ['delete', number]) - messages.success(request, - _('Deleted snapshot #{number}.').format( - number=number)) + messages.success( + request, _('Deleted snapshot #{number}.').format(number=number)) return redirect(reverse('snapshot:index')) output = actions.superuser_run('snapshot', ['list']) @@ -85,9 +98,9 @@ def rollback(request, number): """Show confirmation to rollback to a snapshot.""" if request.method == 'POST': actions.superuser_run('snapshot', ['rollback', number]) - messages.success(request, - _('Rolled back to snapshot #{number}.').format( - number=number)) + messages.success( + request, + _('Rolled back to snapshot #{number}.').format(number=number)) messages.warning( request, _('The system must be restarted to complete the rollback.')) @@ -105,3 +118,27 @@ def rollback(request, number): 'title': _('Rollback to Snapshot'), 'snapshot': snapshot }) + + +def get_status(): + return {'enable_timeline_snapshots': is_timeline_snapshots_enabled()} + + +def _apply_changes(request, old_status, new_status): + """Try to apply changes and handle errors.""" + try: + __apply_changes(request, old_status, new_status) + except ActionError as exception: + messages.error(request, + _('Action error: {0} [{1}] [{2}]').format( + exception.args[0], exception.args[1], + exception.args[2])) + + +def __apply_changes(request, old_status, new_status): + if old_status['enable_timeline_snapshots'] != new_status['enable_timeline_snapshots']: + timeline_create = "TIMELINE_CREATE=yes" if new_status[ + 'enable_timeline_snapshots'] else "TIMELINE_CREATE=no" + actions.superuser_run('snapshot', ['configure', timeline_create]) + messages.success(request, + _('Timeline Snapshots configuration updated'))