Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support snapper #1491

Open
wants to merge 40 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
da73c8f
Update path to Underscore
sfranzen Oct 10, 2016
055221b
Update Backbone script link
sfranzen Oct 15, 2016
4eca949
Update all occurrences of this.options
sfranzen Oct 15, 2016
a4fd43c
Add snapper dependency and default root settings
sfranzen Oct 12, 2016
c061386
Create snapper root config only if not present
sfranzen Oct 12, 2016
5b81527
Introduce a snapper plugin for yum
sfranzen Oct 14, 2016
5d65c36
Add Backform.js dependency
sfranzen Oct 16, 2016
3b0242a
Introduce standard skeleton view for forms
sfranzen Oct 16, 2016
6ce42d5
Add API endpoints for snapper configuration
sfranzen Oct 18, 2016
d576fa4
Add snapper snapshot list view
sfranzen Oct 18, 2016
a6b3477
Handle snapper exceptions in viewer
sfranzen Oct 18, 2016
2af6177
Return snapshot list as a dictionary
sfranzen Oct 18, 2016
f24fafa
Revert "Update all occurrences of this.options"
sfranzen Oct 18, 2016
19def16
Update handling of Backbone view options
sfranzen Oct 18, 2016
6667d7b
Refactor snapshot data parsing
sfranzen Oct 19, 2016
598b862
Fix erroneous imports
sfranzen Oct 19, 2016
cefc991
Return config name with snapshot, sanitise code
sfranzen Oct 20, 2016
942820b
Implement snapshot detail view
sfranzen Oct 20, 2016
e194825
Refactor and define a generic API view
sfranzen Oct 20, 2016
4927abf
Update base class and exception handling
sfranzen Oct 20, 2016
e1d08ca
Improve HTTP response status
sfranzen Oct 20, 2016
aaa2012
Implement PUT for snapper configuration
sfranzen Oct 21, 2016
2f3baa2
Modify config and snapshot parsing
sfranzen Oct 21, 2016
03f9145
Implement PUT/DELETE for snapshots
sfranzen Oct 21, 2016
8bd70b1
Implement POST for snapshot creation
sfranzen Oct 21, 2016
f1338e1
Define new models for snapper
sfranzen Oct 22, 2016
1316268
Change list_snapshots to return all snapshots
sfranzen Oct 23, 2016
2c915a2
Set DataTables length menu globally
sfranzen Oct 23, 2016
3418ce6
Destroy snapshot on server upon removal
sfranzen Oct 24, 2016
b918bd5
Add dependency: DataTables select plugin
sfranzen Oct 24, 2016
1e924ea
Add initial UI components for snapper
sfranzen Oct 24, 2016
b4f0784
Backbonify the dynamic select view
sfranzen Oct 24, 2016
2ad02c8
Add a view for controlling modal dialogs
sfranzen Oct 24, 2016
5b2af6e
Add deletion warning dialog
sfranzen Oct 24, 2016
ac96fbb
Update Bootstrap to version 3.3.7
sfranzen Oct 25, 2016
275cafe
Add Bootstrap select component
sfranzen Oct 25, 2016
2c1b9b6
Finalise design of snapper button toolbar
sfranzen Oct 25, 2016
17809b7
Add warning dialog, improve options handling
sfranzen Oct 26, 2016
98faac1
Update select list event handling
sfranzen Oct 26, 2016
431ced5
Implement snapper config deletion handling
sfranzen Oct 26, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions base-buildout.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ command = (if [ -f ${stop-servers:ctl} ]; then ${stop-servers:ctl} shutdown; fi)
update-command = ${stop-servers:command}
stop-on-error = no

# Use this repo instead of default because it has a much more recent version
[snapper-repo]
recipe = hexagonit.recipe.download
url = http://download.opensuse.org/repositories/filesystems:snapper/CentOS_7/filesystems:snapper.repo
destination = /etc/yum.repos.d
download-only = true

[rpm-deps]
recipe = plone.recipe.command
stop-on-error = true
Expand All @@ -61,7 +68,7 @@ command =
postgresql-server postgresql-devel kernel-ml btrfs-progs rsync \
nfs-utils kernel-ml avahi netatalk smartmontools net-tools sos hdparm \
postfix cyrus-sasl-plain yum-cron nano usbutils pciutils shellinabox \
epel-release
epel-release snapper

[rpm-deps-nut]
recipe = plone.recipe.command
Expand Down Expand Up @@ -219,4 +226,13 @@ schedulerport = 10001
reppubport = 10002
reprecvport = 10003
repsinkport = 10004
input = ${buildout:directory}/conf/settings.conf.in
input = ${buildout:directory}/conf/settings.conf.in

[snapper-conf]
recipe = plone.recipe.command
command =
cp -f ${buildout:directory}/conf/snapper-default-config /etc/snapper/config-templates/default
[ -f /etc/snapper/configs/root ] || snapper create-config /
cp -f ${buildout:directory}/conf/yum_snapper.py /usr/lib/yum-plugins
cp -f ${buildout:directory}/conf/yum_snapper.conf /etc/yum/pluginconf.d
update-command = ${:command}
2 changes: 2 additions & 0 deletions buildout.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ extends = base-buildout.cfg

parts =
stop-rockstor
snapper-repo
snapper-conf
rpm-deps
rpm-deps-nut
rpm-deps-ad
Expand Down
3 changes: 2 additions & 1 deletion conf/settings.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ PIPELINE_JS = {
'storageadmin/js/d3.slider2.js',
'storageadmin/js/models/models.js',
'storageadmin/js/views/common/*.js',
'storageadmin/js/views/snapper/*.js',
'storageadmin/js/views/*.js',
'storageadmin/js/views/pool/**/*.js',
'storageadmin/js/views/dashboard/*.js',
Expand Down Expand Up @@ -422,4 +423,4 @@ ZTASKD_URL = 'ipc:///var/run/rockon-ztaskd'

TASK_SCHEDULER = {
'max_log': 100 #max number of task log entries to keep
}
}
60 changes: 60 additions & 0 deletions conf/snapper-default-config
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@

# subvolume to snapshot
SUBVOLUME="/"

# filesystem type
FSTYPE="btrfs"


# btrfs qgroup for space aware cleanup algorithms
QGROUP="1/0"


# fraction of the filesystems space the snapshots may use
SPACE_LIMIT="0.5"


# users and groups allowed to work with config
ALLOW_USERS=""
ALLOW_GROUPS=""

# sync users and groups from ALLOW_USERS and ALLOW_GROUPS to .snapshots
# directory
SYNC_ACL="no"


# start comparing pre- and post-snapshot in background after creating
# post-snapshot
BACKGROUND_COMPARISON="yes"


# run daily number cleanup
NUMBER_CLEANUP="yes"

# limit for number cleanup
NUMBER_MIN_AGE="1800"
NUMBER_LIMIT="2-10"
NUMBER_LIMIT_IMPORTANT="4-10"


# create hourly snapshots
TIMELINE_CREATE="no"

# cleanup hourly snapshots after some time
TIMELINE_CLEANUP="yes"

# limits for timeline cleanup
TIMELINE_MIN_AGE="1800"
TIMELINE_LIMIT_HOURLY="10"
TIMELINE_LIMIT_DAILY="10"
TIMELINE_LIMIT_WEEKLY="0"
TIMELINE_LIMIT_MONTHLY="10"
TIMELINE_LIMIT_YEARLY="10"


# cleanup empty pre-post-pairs
EMPTY_PRE_POST_CLEANUP="yes"

# limits for empty pre-post-pair cleanup
EMPTY_PRE_POST_MIN_AGE="1800"

5 changes: 5 additions & 0 deletions conf/yum_snapper.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[main]
enabled=1
# Transactions starting with these patterns will have their snapshots marked
# as important
important=kernel-,dracut,glibc,systemd,udev,snapper
89 changes: 89 additions & 0 deletions conf/yum_snapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"""
This plugin creates snapper pre and post snapshots upon modifications by yum.
"""

from os import readlink, getppid
from os.path import basename
from dbus import SystemBus, Interface, DBusException
from yum.plugins import PluginYumExit, TYPE_CORE
import logging

"""
Copyright (c) 2016 RockStor, Inc. <http://rockstor.com>
This file is part of RockStor.

RockStor 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; either version 2 of the License,
or (at your option) any later version.

RockStor 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, see <http://www.gnu.org/licenses/>.
"""

# Yum
requires_api_version = '2.7'
plugin_type = (TYPE_CORE,)

# Own global variables
snapper = None
description = ''
pre_number = None
important = []
cleanup = 'number'
userdata = {'important': 'no'}


def init_hook(conduit):
"""Set up global settings for the other hooks.
"""
global important, description, snapper
important = conduit.confList('main', 'important', [])
description = 'yum(%s)' % basename(readlink('/proc/%d/exe' % getppid()))
try:
bus = SystemBus()
snapper = Interface(bus.get_object('org.opensuse.Snapper',
'/org/opensuse/Snapper'),
dbus_interface='org.opensuse.Snapper')
except DBusException as e:
message = 'Could not connect to snapperd:\n %s' % e
raise PluginYumExit(message)


def pretrans_hook(conduit):
"""Take a snapper pre snapshot, which is marked as important depending on
patterns specified in yum_snapper.conf.
"""
global userdata, pre_number
transaction = conduit.getTsInfo()
for name in {item.name for item in transaction}:
if any(name.startswith(item) for item in important):
userdata['important'] = 'yes'
break
try:
logging.info('Creating pre snapshot')
pre_number = snapper.CreatePreSnapshot('root', description, cleanup,
userdata)
logging.debug('Created pre snapshot %d' % pre_number)
except DBusException as e:
logging.error('Pre snapshot creation failed:')
logging.error(' %s' % e)


def posttrans_hook(conduit):
"""Take a snapper post snapshot if the pre snapshot exists.
"""
if pre_number:
try:
logging.info('Creating post snapshot')
post_number = snapper.CreatePostSnapshot('root', pre_number, '',
cleanup, userdata)
logging.debug('Created post snapshot %d' % post_number)
except DBusException as e:
logging.error('Post snapshot creation failed:')
logging.error(' %s' % e)
2 changes: 1 addition & 1 deletion src/rockstor/rest_framework_custom/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""

from generic_view import GenericView
from generic_view import GenericView, GenericAPIView
from renderers import IgnoreClient
23 changes: 17 additions & 6 deletions src/rockstor/rest_framework_custom/generic_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"""

from rest_framework.generics import ListCreateAPIView
from rest_framework.views import APIView
from rest_framework.authentication import (BasicAuthentication,
SessionAuthentication,)
from storageadmin.auth import DigestAuthentication
Expand All @@ -27,11 +28,12 @@
from storageadmin.exceptions import RockStorAPIException


# TODO: Only allow put, and patch where necessary. This works right now
class GenericView(ListCreateAPIView):
authentication_classes = (DigestAuthentication, SessionAuthentication,
BasicAuthentication, RockstorOAuth2Authentication,)
permission_classes = (IsAuthenticated, )
class GenericMixin:
authentication_classes = [DigestAuthentication,
SessionAuthentication,
BasicAuthentication,
RockstorOAuth2Authentication]
permission_classes = [IsAuthenticated]

@staticmethod
@contextmanager
Expand All @@ -40,5 +42,14 @@ def _handle_exception(request, msg=None):
yield
except RockStorAPIException:
raise
except Exception, e:
except Exception as e:
handle_exception(e, request, msg)


# TODO: Only allow put, and patch where necessary. This works right now
class GenericView(GenericMixin, ListCreateAPIView):
pass


class GenericAPIView(GenericMixin, APIView):
pass

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

34 changes: 34 additions & 0 deletions src/rockstor/storageadmin/static/storageadmin/js/models/models.js
Original file line number Diff line number Diff line change
Expand Up @@ -706,3 +706,37 @@ var UpdateSubscriptionCollection = RockStorPaginatedCollection.extend({
model: UpdateSubscription,
baseUrl: '/api/update-subscriptions'
});

var SnapperSnapshot = Backbone.Model.extend({
idAttribute: 'number'
});

// The Snapshot collection does not have predefined URL as it is nested below a config
var SnapperSnapshotCollection = Backbone.Collection.extend({
model: SnapperSnapshot
});

var SnapperConfig = Backbone.Model.extend({
idAttribute: 'NAME',

initialize: function() {
this.snapshots = new SnapperSnapshotCollection();
this.snapshots.url = this.url() + '/snapshots';
this.listenTo(this.snapshots, 'sync', this.onReset);
this.listenTo(this.snapshots, 'remove', this.onRemove);
},

onReset: function() {
this.trigger('change:snapshots', this);
},

onRemove: function(snapshot) {
snapshot.destroy();
this.trigger('change:snapshots', this);
}
});

var SnapperConfigCollection = Backbone.Collection.extend({
model: SnapperConfig,
url: '/api/snapper'
});
Loading