Option to enable/disble automatic timeline snapshots

Signed-off-by: Hanisha P<hanishap@thoughtworks.com>
Reviewed-by: Joseph Nuthalapati <njoseph@thoughtworks.com>
This commit is contained in:
hanisha 2017-12-08 14:55:25 +05:30 committed by Joseph Nuthalapati
parent a2997a0c70
commit 76ffad7955
No known key found for this signature in database
GPG Key ID: 5398F00A2FA43C35
5 changed files with 126 additions and 25 deletions

View File

@ -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 = [

View File

@ -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"

View File

@ -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 <http://www.gnu.org/licenses/>.
#
"""
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).'))

View File

@ -23,27 +23,32 @@
{% block configuration %}
<p>
<div class="row">
<form class="form" method="post">
{% csrf_token %}
<form class="form" method="post">
{% csrf_token %}
<h3>{% trans "Configuration" %}</h3>
{{ form|bootstrap }}
<input type="submit" class="btn btn-primary" name="update"
value="{% trans "Update setup" %}"/>
<hr>
<div class="row">
<div class="col-xs-6 text-left">
<input type="submit" class="btn btn-primary"
<input type="submit" class="btn btn-primary" name="create"
value="{% trans 'Create Snapshot' %}"/>
</div>
</form>
</form>
<div class="col-xs-6 text-right">
<a title="{% trans 'Delete all the snapshots' %}"
role="button" class="btn btn-danger"
{% if snapshots|length == 1 %}
disabled="disabled"
{% else %}
href="{% url 'snapshot:delete-all' %}"
{% endif %}>
{% trans 'Delete All' %}
</a>
</div>
<div class="col-xs-6 text-right">
<a title="{% trans 'Delete all the snapshots' %}"
role="button" class="btn btn-danger"
{% if snapshots|length == 1 %}
disabled="disabled"
{% else %}
href="{% url 'snapshot:delete-all' %}"
{% endif %}>
{% trans 'Delete All' %}
</a>
</div>
</div>
</p>
<div class="row">

View File

@ -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'))