From da73c8fb6bb350b93e5e60d86f2ef4c35d4c191b Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Mon, 10 Oct 2016 21:20:49 +0200 Subject: [PATCH 01/40] Update path to Underscore --- src/rockstor/storageadmin/templates/storageadmin/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rockstor/storageadmin/templates/storageadmin/base.html b/src/rockstor/storageadmin/templates/storageadmin/base.html index 145133602..d3f79f906 100644 --- a/src/rockstor/storageadmin/templates/storageadmin/base.html +++ b/src/rockstor/storageadmin/templates/storageadmin/base.html @@ -79,7 +79,7 @@ - + From 055221b7d71049bd04248635c7b24d17899cd67e Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Sat, 15 Oct 2016 20:46:41 +0200 Subject: [PATCH 02/40] Update Backbone script link --- src/rockstor/storageadmin/templates/storageadmin/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rockstor/storageadmin/templates/storageadmin/base.html b/src/rockstor/storageadmin/templates/storageadmin/base.html index d3f79f906..032fb4e9e 100644 --- a/src/rockstor/storageadmin/templates/storageadmin/base.html +++ b/src/rockstor/storageadmin/templates/storageadmin/base.html @@ -80,7 +80,7 @@ - + From 4eca94936d04819f3e63854594721b9fa659a489 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Sun, 16 Oct 2016 00:39:53 +0200 Subject: [PATCH 03/40] Update all occurrences of this.options New Backbone versions no longer automatically set this on the object, you have to pass it to initialize(). --- .../static/storageadmin/js/rockstor.js | 22 +++++++++---------- .../storageadmin/js/views/add_afp_share.js | 4 ++-- .../static/storageadmin/js/views/add_group.js | 4 ++-- .../js/views/add_replication_task.js | 4 ++-- .../storageadmin/js/views/add_samba_export.js | 4 ++-- .../js/views/add_scheduled_task.js | 4 ++-- .../static/storageadmin/js/views/add_share.js | 4 ++-- .../static/storageadmin/js/views/add_user.js | 4 ++-- .../storageadmin/js/views/blink_disks.js | 4 ++-- .../js/views/configure_service.js | 6 ++--- .../storageadmin/js/views/create_clone.js | 8 +++---- .../storageadmin/js/views/dashboard_config.js | 6 ++--- .../js/views/disk_details_layout_view.js | 4 ++-- .../storageadmin/js/views/docker_service.js | 4 ++-- .../js/views/edit_network_connection.js | 4 ++-- .../storageadmin/js/views/edit_nfs_export.js | 4 ++-- .../js/views/pool_details_layout_view.js | 6 ++--- .../js/views/pool_rebalance_table.js | 10 ++++----- .../storageadmin/js/views/pool_scrub_table.js | 10 ++++----- .../js/views/replica_receive_trails.js | 4 ++-- .../storageadmin/js/views/replica_trails.js | 4 ++-- .../static/storageadmin/js/views/rollback.js | 6 ++--- .../storageadmin/js/views/setup_system.js | 4 ++-- .../js/views/share_details_layout_view.js | 6 ++--- .../js/views/share_usage_module.js | 4 ++-- .../js/views/smartcustom_disks.js | 4 ++-- .../static/storageadmin/js/views/snapshots.js | 6 ++--- .../storageadmin/js/views/snapshots_table.js | 10 ++++----- .../storageadmin/js/views/spindown_disks.js | 4 ++-- .../static/storageadmin/js/views/tasks.js | 4 ++-- 30 files changed, 86 insertions(+), 86 deletions(-) diff --git a/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js b/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js index 06608af00..ad4ae7b7e 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js @@ -118,11 +118,11 @@ RockStorWidgetView = Backbone.View.extend({ 'click .download-widget': 'download' }, - initialize: function() { - this.maximized = this.options.maximized; - this.name = this.options.name; - this.displayName = this.options.displayName; - this.parentView = this.options.parentView; + initialize: function(options) { + this.maximized = options.maximized; + this.name = options.name; + this.displayName = options.displayName; + this.parentView = options.parentView; this.dependencies = []; }, @@ -455,9 +455,9 @@ var RockstorUtil = function() { RockstorWizardPage = Backbone.View.extend({ - initialize: function() { - this.evAgg = this.options.evAgg; - this.parent = this.options.parent; + initialize: function(options) { + this.evAgg = options.evAgg; + this.parent = options.parent; }, render: function() { @@ -480,7 +480,7 @@ WizardView = Backbone.View.extend({ 'click #prev-page': 'prevPage' }, - initialize: function() { + initialize: function(options) { this.template = window.JST.wizard_wizard; this.pages = null; this.currentPage = null; @@ -489,8 +489,8 @@ WizardView = Backbone.View.extend({ this.evAgg = _.extend({}, Backbone.Events); this.evAgg.bind('nextPage', this.nextPage, this); this.evAgg.bind('prevPage', this.prevPage, this); - this.parent = this.options.parent; - this.title = this.options.title; + this.parent = options.parent; + this.title = options.title; }, setPages: function(pages) { diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_afp_share.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_afp_share.js index 117709d25..aad7f1592 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_afp_share.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_afp_share.js @@ -29,14 +29,14 @@ AddAFPShareView = RockstorLayoutView.extend({ "click #cancel": "cancel" }, - initialize: function() { + initialize: function(options) { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.afp_add_afp_share; this.shares = new ShareCollection(); // dont paginate shares for now this.shares.pageSize = RockStorGlobals.maxPageSize; this.dependencies.push(this.shares); - this.afpShareId = this.options.afpShareId || null; + this.afpShareId = options.afpShareId || null; this.afpShares = new AFPCollection({afpShareId: this.afpShareId}); this.dependencies.push(this.afpShares); this.yes_no_choices = [ diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_group.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_group.js index dcee5c394..6f05510b1 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_group.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_group.js @@ -29,12 +29,12 @@ AddGroupView = RockstorLayoutView.extend({ "click #cancel": "cancel" }, - initialize: function() { + initialize: function(options) { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template this.template = window.JST.users_add_group; - this.groupname = this.options.groupname; + this.groupname = options.groupname; this.group = new Group({groupname: this.groupname}); this.dependencies.push(this.group); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_replication_task.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_replication_task.js index 46835e5d3..91de199ce 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_replication_task.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_replication_task.js @@ -31,7 +31,7 @@ AddReplicationTaskView = RockstorLayoutView.extend({ "change #appliance": "fetchRemotePools" }, - initialize: function() { + initialize: function(options) { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.replication_add_replication_task; this.shares = new ShareCollection(); @@ -44,7 +44,7 @@ AddReplicationTaskView = RockstorLayoutView.extend({ this.dependencies.push(this.replicas); this.remote_pools = []; - this.replicaId = this.options.replicaId; + this.replicaId = options.replicaId; if (!_.isUndefined(this.replicaId) && !_.isNull(this.replicaId)) { this.replica = new Replica({id: this.replicaId}); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_samba_export.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_samba_export.js index 8dfa71871..7956ff18e 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_samba_export.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_samba_export.js @@ -31,7 +31,7 @@ AddSambaExportView = RockstorLayoutView.extend({ 'click #shadow_copy': 'toggleSnapPrefix' }, - initialize: function() { + initialize: function(options) { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.samba_add_samba_export; this.shares = new ShareCollection(); @@ -41,7 +41,7 @@ AddSambaExportView = RockstorLayoutView.extend({ this.users.pageSize = RockStorGlobals.maxPageSize; this.dependencies.push(this.shares); this.dependencies.push(this.users); - this.sambaShareId = this.options.sambaShareId || null; + this.sambaShareId = options.sambaShareId || null; this.sambaShares = new SambaCollection({sambaShareId: this.sambaShareId}); this.dependencies.push(this.sambaShares); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_scheduled_task.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_scheduled_task.js index 3445e45c7..7e1ed9123 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_scheduled_task.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_scheduled_task.js @@ -31,7 +31,7 @@ AddScheduledTaskView = RockstorLayoutView.extend({ "change #task_type": "renderOptionalFields" }, - initialize: function() { + initialize: function(options) { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.scheduled_tasks_add_task; this.snapshotFieldsTemplate = window.JST.scheduled_tasks_snapshot_fields; @@ -42,7 +42,7 @@ AddScheduledTaskView = RockstorLayoutView.extend({ this.pools.pageSize = RockStorGlobals.maxPageSize; this.dependencies.push(this.shares); this.dependencies.push(this.pools); - this.taskDefId = this.options.taskDefId; + this.taskDefId = options.taskDefId; if (!_.isUndefined(this.taskDefId) && !_.isNull(this.taskDefId)) { this.taskDef = new TaskDef({id: this.taskDefId}); this.dependencies.push(this.taskDef); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_share.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_share.js index a2102b051..c69d42177 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_share.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_share.js @@ -33,11 +33,11 @@ AddShareView = Backbone.View.extend({ "click #js-cancel": "cancel" }, - initialize: function() { + initialize: function(options) { var _this = this; this.pools = new PoolCollection(); this.pools.pageSize = RockStorGlobals.maxPageSize; - this.preSelectedPoolName = this.options.poolName || null; + this.preSelectedPoolName = options.poolName || null; this.tickFormatter = function(d) { var formatter = d3.format(",.1f"); if (d > 1024) { diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_user.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_user.js index c658d3499..895107d95 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_user.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_user.js @@ -29,12 +29,12 @@ AddUserView = RockstorLayoutView.extend({ "click #cancel": "cancel" }, - initialize: function() { + initialize: function(options) { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template this.template = window.JST.users_add_user; - this.username = this.options.username; + this.username = options.username; if (!_.isUndefined(this.username)) { this.user = new User({username: this.username}); this.dependencies.push(this.user); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/blink_disks.js b/src/rockstor/storageadmin/static/storageadmin/js/views/blink_disks.js index 9258ec0f5..ff35a0db6 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/blink_disks.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/blink_disks.js @@ -29,11 +29,11 @@ BlinkDiskView = RockstorLayoutView.extend({ 'click #cancel': 'cancel' }, - initialize: function() { + initialize: function(options) { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.disk_blink_disks; this.disks = new DiskCollection(); - this.diskName = this.options.diskName; + this.diskName = options.diskName; this.dependencies.push(this.disks); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/configure_service.js b/src/rockstor/storageadmin/static/storageadmin/js/views/configure_service.js index 81115b764..794ab1d32 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/configure_service.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/configure_service.js @@ -32,12 +32,12 @@ ConfigureServiceView = RockstorLayoutView.extend({ "click #mode": "toggleNutFields" }, - initialize: function() { + initialize: function(options) { // call initialize of base var _this = this; this.constructor.__super__.initialize.apply(this, arguments); - this.serviceName = this.options.serviceName; - this.adStatus = this.options.adStatus; + this.serviceName = options.serviceName; + this.adStatus = options.adStatus; // set template this.template = window.JST['services_configure_' + this.serviceName]; this.rules = { diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/create_clone.js b/src/rockstor/storageadmin/static/storageadmin/js/views/create_clone.js index f34b22580..7aa2d38e1 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/create_clone.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/create_clone.js @@ -29,12 +29,12 @@ CreateCloneView = RockstorLayoutView.extend({ "click #js-cancel": "cancel" }, - initialize: function() { + initialize: function(options) { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.share_create_clone; - this.sourceType = this.options.sourceType; - this.shareName = this.options.shareName; - this.snapName = this.options.snapName; + this.sourceType = options.sourceType; + this.shareName = options.shareName; + this.snapName = options.snapName; }, render: function() { diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard_config.js b/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard_config.js index fe358e111..72bd42a52 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard_config.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard_config.js @@ -29,10 +29,10 @@ DashboardConfigView = Backbone.View.extend({ "click .widget-name": "widgetClicked" }, - initialize: function() { - this.dashboardconfig = this.options.dashboardconfig; + initialize: function(options) { + this.dashboardconfig = options.dashboardconfig; this.template = window.JST.dashboard_dashboard_config; - this.parentView = this.options.parentView; + this.parentView = options.parentView; this.initHandlebarHelpers(); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/disk_details_layout_view.js b/src/rockstor/storageadmin/static/storageadmin/js/views/disk_details_layout_view.js index 97972c6ef..708a1a9fb 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/disk_details_layout_view.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/disk_details_layout_view.js @@ -26,10 +26,10 @@ DiskDetailsLayoutView = RockstorLayoutView.extend({ - initialize: function () { + initialize: function (options) { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); - this.diskName = this.options.diskName; + this.diskName = options.diskName; this.template = window.JST.disk_disk_details_layout; this.disk = new Disk({diskName: this.diskName}); this.smartinfo = new SmartInfo({diskName: this.diskName}); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/docker_service.js b/src/rockstor/storageadmin/static/storageadmin/js/views/docker_service.js index f060b0ed6..5d26496ad 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/docker_service.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/docker_service.js @@ -29,11 +29,11 @@ DockerServiceView = Backbone.View.extend({ 'switchChange.bootstrapSwitch': 'switchStatus', }, - initialize: function() { + initialize: function(options) { this.template = window.JST.rockons_docker_service; this.serviceName = 'docker'; this.service = new Service({name: this.serviceName}); - this.parentView = this.options.parentView; + this.parentView = options.parentView; this.updateFreq = 30000; }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/edit_network_connection.js b/src/rockstor/storageadmin/static/storageadmin/js/views/edit_network_connection.js index 67e87aa19..9b980e285 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/edit_network_connection.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/edit_network_connection.js @@ -33,9 +33,9 @@ NetworkConnectionView = RockstorLayoutView.extend({ 'change #ctype': 'renderCTypeOptionalFields' }, - initialize: function() { + initialize: function(options) { this.constructor.__super__.initialize.apply(this, arguments); - this.connectionId = this.options.connectionId || null; + this.connectionId = options.connectionId || null; this.connection = null; this.template = window.JST.network_new_connection; this.devices = new NetworkDeviceCollection(); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/edit_nfs_export.js b/src/rockstor/storageadmin/static/storageadmin/js/views/edit_nfs_export.js index 801d62ea0..8aee2c093 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/edit_nfs_export.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/edit_nfs_export.js @@ -29,11 +29,11 @@ EditNFSExportView = RockstorLayoutView.extend({ 'click #cancel': 'cancel' }, - initialize: function() { + initialize: function(options) { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.nfs_edit_nfs_export; this.shares = new ShareCollection(); - this.nfsExportGroupId = this.options.nfsExportGroupId; + this.nfsExportGroupId = options.nfsExportGroupId; if(this.nfsExportGroupId > 0) { this.nfsExportGroup = new NFSExportGroup({id: this.nfsExportGroupId}); this.nfsExportNotEmpty = true; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_details_layout_view.js b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_details_layout_view.js index 12b7ad778..1f36d0b5d 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_details_layout_view.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_details_layout_view.js @@ -26,11 +26,11 @@ PoolDetailsLayoutView = RockstorLayoutView.extend({ - initialize: function() { + initialize: function(options) { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); - this.poolName = this.options.poolName; - this.cView = this.options.cView; + this.poolName = options.poolName; + this.cView = options.cView; this.template = window.JST.pool_pool_details_layout; this.resize_pool_info_template = window.JST.pool_resize_pool_info; this.compression_info_template = window.JST.pool_compression_info; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_rebalance_table.js b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_rebalance_table.js index 6078d8903..ae9793771 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_rebalance_table.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_rebalance_table.js @@ -30,15 +30,15 @@ PoolRebalanceTableModule = RockstorModuleView.extend({ "click #js-poolrebalance-cancel": "cancel" }, - initialize: function() { + initialize: function(options) { this.template = window.JST.pool_poolrebalance_table_template; this.startRebalanceTemplate = window.JST.pool_poolrebalance_start_template; this.module_name = 'poolrebalances'; - this.pool = this.options.pool; - this.poolrebalances = this.options.poolrebalances; - this.collection = this.options.poolrebalances; + this.pool = options.pool; + this.poolrebalances = options.poolrebalances; + this.collection = options.poolrebalances; this.collection.on("reset", this.render, this); - this.parentView = this.options.parentView; + this.parentView = options.parentView; this.initHandlebarHelpers(); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_scrub_table.js b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_scrub_table.js index 725ee577c..6815e584a 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_scrub_table.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_scrub_table.js @@ -30,15 +30,15 @@ PoolScrubTableModule = RockstorModuleView.extend({ "click #js-poolscrub-cancel": "cancel" }, - initialize: function() { + initialize: function(options) { this.template = window.JST.pool_poolscrub_table_template; this.startScrubTemplate = window.JST.pool_poolscrub_start_template; this.module_name = 'poolscrubs'; - this.pool = this.options.pool; - this.poolscrubs = this.options.poolscrubs; - this.collection = this.options.poolscrubs; + this.pool = options.pool; + this.poolscrubs = options.poolscrubs; + this.collection = options.poolscrubs; this.collection.on("reset", this.render, this); - this.parentView = this.options.parentView; + this.parentView = options.parentView; this.initHandlebarHelpers(); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/replica_receive_trails.js b/src/rockstor/storageadmin/static/storageadmin/js/views/replica_receive_trails.js index e2237e2d4..4e93ed9e0 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/replica_receive_trails.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/replica_receive_trails.js @@ -29,13 +29,13 @@ ReplicaReceiveTrailsView = RockstorLayoutView.extend({ events: { }, - initialize: function() { + initialize: function(options) { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template this.template = window.JST.replication_receive_trails; // add dependencies - this.replicaShareId = this.options.replicaShareId; + this.replicaShareId = options.replicaShareId; this.replicaShare = new ReplicaShare({id: this.replicaShareId}); this.dependencies.push(this.replicaShare); this.collection = new ReceiveTrailCollection(null, { diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/replica_trails.js b/src/rockstor/storageadmin/static/storageadmin/js/views/replica_trails.js index 6081ccfac..bd23d9dcd 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/replica_trails.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/replica_trails.js @@ -29,13 +29,13 @@ ReplicaTrailsView = RockstorLayoutView.extend({ events: { }, - initialize: function() { + initialize: function(options) { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template this.template = window.JST.replication_replica_trails; // add dependencies - this.replicaId = this.options.replicaId; + this.replicaId = options.replicaId; this.replica = new Replica({id: this.replicaId}); this.dependencies.push(this.replica); this.collection = new ReplicaTrailCollection(null, { diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/rollback.js b/src/rockstor/storageadmin/static/storageadmin/js/views/rollback.js index b21cd0715..dc6b776b5 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/rollback.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/rollback.js @@ -30,16 +30,16 @@ RollbackView = RockstorLayoutView.extend({ 'click #js-confirm-rollback-submit': 'confirmRollback' }, - initialize: function() { + initialize: function(options) { this.constructor.__super__.initialize.apply(this, arguments); // Templates this.template = window.JST.share_rollback; this.snapshot_list_template = window.JST.share_rollback_snapshot_list; // Dependencies - this.share = new Share({shareName: this.options.shareName}); + this.share = new Share({shareName: options.shareName}); this.collection = new SnapshotCollection(); this.collection.pageSize = 10; - this.collection.setUrl(this.options.shareName); + this.collection.setUrl(options.shareName); this.dependencies.push(this.share); this.dependencies.push(this.collection); this.collection.on('reset', this.renderSnapshotList, this); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/setup_system.js b/src/rockstor/storageadmin/static/storageadmin/js/views/setup_system.js index d2aff64db..72e38cafb 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/setup_system.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/setup_system.js @@ -27,9 +27,9 @@ SetupSystemView = Backbone.View.extend({ tagName: 'div', - initialize: function() { + initialize: function(options) { this.template = window.JST.setup_system; - this.sysinfo = this.options.sysinfo; + this.sysinfo = options.sysinfo; }, render: function() { diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/share_details_layout_view.js b/src/rockstor/storageadmin/static/storageadmin/js/views/share_details_layout_view.js index 7516118b9..b98272cd4 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/share_details_layout_view.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/share_details_layout_view.js @@ -38,10 +38,10 @@ ShareDetailsLayoutView = RockstorLayoutView.extend({ "click #js-confirm-share-delete": "confirmShareDelete", }, - initialize: function() { + initialize: function(options) { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); - this.shareName = this.options.shareName; + this.shareName = options.shareName; this.template = window.JST.share_share_details_layout; this.rollback_btn_template = window.JST.share_share_details_rollback_btn; this.shareAclTemplate = window.JST.share_share_acl; @@ -81,7 +81,7 @@ ShareDetailsLayoutView = RockstorLayoutView.extend({ ]; this.on('snapshotsModified', this.renderRollbackBtn, this); this.cOpts = {'no': 'Dont enable compression', 'zlib': 'zlib', 'lzo': 'lzo'}; - this.cView = this.options.cView; + this.cView = options.cView; this.initHandlebarHelpers(); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/share_usage_module.js b/src/rockstor/storageadmin/static/storageadmin/js/views/share_usage_module.js index 46f796ab5..d9393ed8d 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/share_usage_module.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/share_usage_module.js @@ -32,11 +32,11 @@ ShareUsageModule = RockstorModuleView.extend({ }, - initialize: function() { + initialize: function(options) { this.template = window.JST.share_share_usage_module; this.editTemplate = window.JST.share_share_usage_edit; this.module_name = 'share-usage'; - this.share = this.options.share; + this.share = options.share; this.initHandlebarHelpers(); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/smartcustom_disks.js b/src/rockstor/storageadmin/static/storageadmin/js/views/smartcustom_disks.js index f8e10b3cd..f4dbf09cb 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/smartcustom_disks.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/smartcustom_disks.js @@ -29,11 +29,11 @@ SmartcustomDiskView = RockstorLayoutView.extend({ 'click #cancel': 'cancel' }, - initialize: function () { + initialize: function (options) { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.disk_smartcustom_disks; this.disks = new DiskCollection(); - this.diskName = this.options.diskName; + this.diskName = options.diskName; this.dependencies.push(this.disks); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots.js b/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots.js index f23927361..0a529a413 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots.js @@ -34,12 +34,12 @@ SnapshotsView = SnapshotsCommonView.extend({ "click #js-snapshot-delete-multiple": "deleteMultipleSnapshots" }, - initialize: function() { + initialize: function(options) { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.share_snapshots; this.addTemplate = window.JST.share_snapshot_add_template; this.module_name = 'snapshots'; - this.snapshots = this.options.snapshots; + this.snapshots = options.snapshots; this.collection = new SnapshotsCollection(); this.shares = new ShareCollection(); this.dependencies.push(this.shares); @@ -52,7 +52,7 @@ SnapshotsView = SnapshotsCommonView.extend({ {name: 'yes', value: 'yes'}, {name: 'no', value: 'no'}, ]; - this.parentView = this.options.parentView; + this.parentView = options.parentView; this.collection.on("reset", this.renderSnapshots, this); this.initHandlebarHelpers(); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots_table.js b/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots_table.js index 478220317..152a91bba 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots_table.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots_table.js @@ -35,20 +35,20 @@ SnapshotsTableModule = SnapshotsCommonView.extend({ "click #js-snapshot-delete-multiple": "deleteMultipleSnapshots" }, - initialize: function() { + initialize: function(options) { this.template = window.JST.share_snapshots_table_template; this.addTemplate = window.JST.share_snapshot_add; this.module_name = 'snapshots'; - this.share = this.options.share; - this.snapshots = this.options.snapshots; - this.collection = this.options.snapshots; + this.share = options.share; + this.snapshots = options.snapshots; + this.collection = options.snapshots; this.collection.on("reset", this.render, this); this.selectedSnapshots = []; this.modify_choices = [ {name: 'yes', value: 'yes'}, {name: 'no', value: 'no'}, ]; - this.parentView = this.options.parentView; + this.parentView = options.parentView; this.initHandlebarHelpers(); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/spindown_disks.js b/src/rockstor/storageadmin/static/storageadmin/js/views/spindown_disks.js index aa908a6ab..97478fa7d 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/spindown_disks.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/spindown_disks.js @@ -29,12 +29,12 @@ SpindownDiskView = RockstorLayoutView.extend({ 'click #cancel': 'cancel' }, - initialize: function () { + initialize: function (options) { var _this = this; this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.disk_spindown_disks; this.disks = new DiskCollection(); - this.diskName = this.options.diskName; + this.diskName = options.diskName; this.dependencies.push(this.disks); this.tickFormatter = function (d) { var formatter = d3.format(",.0f"); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/tasks.js b/src/rockstor/storageadmin/static/storageadmin/js/views/tasks.js index 5c560c40d..bc9ba04cd 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/tasks.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/tasks.js @@ -29,13 +29,13 @@ TasksView = RockstorLayoutView.extend({ events: { }, - initialize: function() { + initialize: function(options) { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template this.template = window.JST.scheduled_tasks_tasks; // add dependencies - this.taskDefId = this.options.taskDefId; + this.taskDefId = options.taskDefId; this.taskDef = new TaskDef({id: this.taskDefId}); this.dependencies.push(this.taskDef); this.collection = new TaskCollection(null, { From a4fd43cdae9ec4c16ed8031c0c2f92f078f9de84 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Wed, 12 Oct 2016 15:15:55 +0200 Subject: [PATCH 04/40] Add snapper dependency and default root settings --- base-buildout.cfg | 16 +++++++++-- buildout.cfg | 2 ++ conf/snapper-root-config | 60 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 conf/snapper-root-config diff --git a/base-buildout.cfg b/base-buildout.cfg index 56cf37770..b725f0876 100644 --- a/base-buildout.cfg +++ b/base-buildout.cfg @@ -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 @@ -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 @@ -219,4 +226,9 @@ schedulerport = 10001 reppubport = 10002 reprecvport = 10003 repsinkport = 10004 -input = ${buildout:directory}/conf/settings.conf.in \ No newline at end of file +input = ${buildout:directory}/conf/settings.conf.in + +[snapper-conf] +recipe = plone.recipe.command +command = + cp ${buildout:directory}/conf/snapper-root-config /etc/snapper/configs/root diff --git a/buildout.cfg b/buildout.cfg index 6630c2197..029d5d8fe 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -18,6 +18,8 @@ extends = base-buildout.cfg parts = stop-rockstor + snapper-repo + snapper-conf rpm-deps rpm-deps-nut rpm-deps-ad diff --git a/conf/snapper-root-config b/conf/snapper-root-config new file mode 100644 index 000000000..ca6a4c180 --- /dev/null +++ b/conf/snapper-root-config @@ -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" + From c061386c0ef10241678a78d75f3f210c6ae221b9 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Wed, 12 Oct 2016 17:36:19 +0200 Subject: [PATCH 05/40] Create snapper root config only if not present Allows user modifications to persist. --- base-buildout.cfg | 5 ++++- conf/{snapper-root-config => snapper-default-config} | 0 2 files changed, 4 insertions(+), 1 deletion(-) rename conf/{snapper-root-config => snapper-default-config} (100%) diff --git a/base-buildout.cfg b/base-buildout.cfg index b725f0876..2cd274700 100644 --- a/base-buildout.cfg +++ b/base-buildout.cfg @@ -230,5 +230,8 @@ input = ${buildout:directory}/conf/settings.conf.in [snapper-conf] recipe = plone.recipe.command +location = /etc/snapper/config-templates/default command = - cp ${buildout:directory}/conf/snapper-root-config /etc/snapper/configs/root + cp ${buildout:directory}/conf/snapper-default-config ${:location} + [ -f /etc/snapper/configs/root ] || snapper create-config / +update-command = ${:command} diff --git a/conf/snapper-root-config b/conf/snapper-default-config similarity index 100% rename from conf/snapper-root-config rename to conf/snapper-default-config From 5b8152720243a70e6c1db538aca095f99c67c466 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Sat, 15 Oct 2016 00:10:14 +0200 Subject: [PATCH 06/40] Introduce a snapper plugin for yum Provides automatic pre/post snapshots for each yum transaction, just like the official plugin for zypper (SUSE systems). Related: #1432 --- base-buildout.cfg | 5 ++- conf/yum_snapper.conf | 5 +++ conf/yum_snapper.py | 89 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 conf/yum_snapper.conf create mode 100644 conf/yum_snapper.py diff --git a/base-buildout.cfg b/base-buildout.cfg index 2cd274700..6c03fb414 100644 --- a/base-buildout.cfg +++ b/base-buildout.cfg @@ -230,8 +230,9 @@ input = ${buildout:directory}/conf/settings.conf.in [snapper-conf] recipe = plone.recipe.command -location = /etc/snapper/config-templates/default command = - cp ${buildout:directory}/conf/snapper-default-config ${:location} + 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} diff --git a/conf/yum_snapper.conf b/conf/yum_snapper.conf new file mode 100644 index 000000000..3804b2284 --- /dev/null +++ b/conf/yum_snapper.conf @@ -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 diff --git a/conf/yum_snapper.py b/conf/yum_snapper.py new file mode 100644 index 000000000..31b2fdc38 --- /dev/null +++ b/conf/yum_snapper.py @@ -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. +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 . +""" + +# 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) From 5d65c365a4172562914783f14457baab430f0799 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Sun, 16 Oct 2016 22:08:24 +0200 Subject: [PATCH 07/40] Add Backform.js dependency --- src/rockstor/storageadmin/templates/storageadmin/base.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rockstor/storageadmin/templates/storageadmin/base.html b/src/rockstor/storageadmin/templates/storageadmin/base.html index 032fb4e9e..bc97fe219 100644 --- a/src/rockstor/storageadmin/templates/storageadmin/base.html +++ b/src/rockstor/storageadmin/templates/storageadmin/base.html @@ -82,6 +82,7 @@ + From 3b0242a7f79b7bd19de4160083e7675cc8dfed60 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Sun, 16 Oct 2016 22:14:49 +0200 Subject: [PATCH 08/40] Introduce standard skeleton view for forms Embeds a Backform form within our standard Bootstrap panel element. Can be used just like a Backform.Form view, because all constructor arguments are passed on to the form. --- .../storageadmin/js/templates/common/form.jst | 10 +++++ .../storageadmin/js/views/common/form.js | 44 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/rockstor/storageadmin/static/storageadmin/js/templates/common/form.jst create mode 100644 src/rockstor/storageadmin/static/storageadmin/js/views/common/form.js diff --git a/src/rockstor/storageadmin/static/storageadmin/js/templates/common/form.jst b/src/rockstor/storageadmin/static/storageadmin/js/templates/common/form.jst new file mode 100644 index 000000000..6a59e5306 --- /dev/null +++ b/src/rockstor/storageadmin/static/storageadmin/js/templates/common/form.jst @@ -0,0 +1,10 @@ +
+
+
+ {{title}} +
+
+
+
+
+
diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/common/form.js b/src/rockstor/storageadmin/static/storageadmin/js/views/common/form.js new file mode 100644 index 000000000..2e56cd3f0 --- /dev/null +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/common/form.js @@ -0,0 +1,44 @@ +/* + * + * @licstart The following is the entire license notice for the + * JavaScript code in this page. + * + * Copyright (c) 2016 RockStor, Inc. + * 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 . + * + * @licend The above is the entire license notice + * for the JavaScript code in this page. + * + */ + +// An "outer" view for our forms that embeds the actual form elements in a +// panel view with a title. +FormView = Backbone.View.extend({ + tagName: 'row', + + initialize: function(options) { + this.template = window.JST.common_form; + this.form = new Backform.Form(options); + this.title = options.title; + }, + + render: function() { + this.$el.html(this.template({title: this.title})); + this.form.setElement(this.$('form')); + this.form.render(); + return this; + } +}); From 6ce42d5b0e02b31d383f282184cf55b027d0b4be Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Tue, 18 Oct 2016 15:31:38 +0200 Subject: [PATCH 09/40] Add API endpoints for snapper configuration --- src/rockstor/storageadmin/urls/snapper.py | 27 +++++++++ src/rockstor/storageadmin/views/__init__.py | 1 + src/rockstor/storageadmin/views/snapper.py | 50 ++++++++++++++++ src/rockstor/system/snapper.py | 65 +++++++++++++++++++++ src/rockstor/urls.py | 1 + 5 files changed, 144 insertions(+) create mode 100644 src/rockstor/storageadmin/urls/snapper.py create mode 100644 src/rockstor/storageadmin/views/snapper.py create mode 100644 src/rockstor/system/snapper.py diff --git a/src/rockstor/storageadmin/urls/snapper.py b/src/rockstor/storageadmin/urls/snapper.py new file mode 100644 index 000000000..c4b4c2e85 --- /dev/null +++ b/src/rockstor/storageadmin/urls/snapper.py @@ -0,0 +1,27 @@ +""" +Copyright (c) 2016 RockStor, Inc. +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 . +""" + +from django.conf.urls import patterns, url +from storageadmin.views import SnapperConfigList, SnapperConfigDetail + + +urlpatterns = patterns( + '', + url(r'^$', SnapperConfigList.as_view()), + url(r'^/([\w-]+)$', SnapperConfigDetail.as_view()), +) diff --git a/src/rockstor/storageadmin/views/__init__.py b/src/rockstor/storageadmin/views/__init__.py index d32d5e226..eccc91c21 100644 --- a/src/rockstor/storageadmin/views/__init__.py +++ b/src/rockstor/storageadmin/views/__init__.py @@ -55,3 +55,4 @@ from email_client import EmailClientView from update_subscription import (UpdateSubscriptionListView, UpdateSubscriptionDetailView) +from snapper import SnapperConfigList, SnapperConfigDetail diff --git a/src/rockstor/storageadmin/views/snapper.py b/src/rockstor/storageadmin/views/snapper.py new file mode 100644 index 000000000..6f2310c90 --- /dev/null +++ b/src/rockstor/storageadmin/views/snapper.py @@ -0,0 +1,50 @@ +""" +Views for all things related to snapper +""" + +from storageadmin.models import SnapperConfig +from storageadmin.serializers import SnapperConfigSerializer +from rest_framework import views +from rest_framework.response import Response +from system.snapper import Snapper + +""" +Copyright (c) 2016 RockStor, Inc. +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 . +""" + +# Obtain snapper interface +snapper = Snapper() + + +class SnapperConfigList(views.APIView): + """List all snapper configurations or create a new one. + """ + def get(self, request): + return Response(snapper.config_list()) + + def put(self, request, name): + return + + +class SnapperConfigDetail(views.APIView): + """Create/edit/delete a snapper configuration. + """ + def get(self, request, name): + return Response(snapper.get_config(name)) + + def delete(self, request, name): + return diff --git a/src/rockstor/system/snapper.py b/src/rockstor/system/snapper.py new file mode 100644 index 000000000..4225a3261 --- /dev/null +++ b/src/rockstor/system/snapper.py @@ -0,0 +1,65 @@ +""" +Snapper DBus helper methods +""" + +from osi import run_command +from dbus import SystemBus, Interface, DBusException +from contextlib import contextmanager +from storageadmin.util import handle_exception +from rest_framework.exceptions import NotFound + +""" +Copyright (c) 2016 RockStor, Inc. +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 . +""" + + +class Snapper(Interface): + """Extend the default snapper DBus interface with some output conversion + methods. + """ + def __init__(self): + try: + bus = SystemBus() + super(Snapper, self).__init__( + bus.get_object('org.opensuse.Snapper', + '/org/opensuse/Snapper'), + dbus_interface='org.opensuse.Snapper') + except DBusException as e: + handle_exception(e, None, 'Could not connect to snapperd') + + def config_list(self): + return [self._parse_config(config) for config in self.ListConfigs()] + + def get_config(self, name): + """Apply some parsing to output of GetConfig, which returns a list of + str, str, {} representing the name, subvolume and settings. + """ + config = {} + try: + output = self.GetConfig(name) + except: + raise NotFound('Configuration \'%s\' not found.' % name) + else: + return self._parse_config(output) + + def _parse_config(self, raw): + """Return the relevant options as a dictionary. + """ + config = raw[2].copy() + config['NAME'] = raw[0] + config['SUBVOLUME'] = raw[1] + return config diff --git a/src/rockstor/urls.py b/src/rockstor/urls.py index d38107970..ab5cede87 100644 --- a/src/rockstor/urls.py +++ b/src/rockstor/urls.py @@ -76,6 +76,7 @@ (r'^api/pools', include('storageadmin.urls.pools')), (r'^api/shares', include('storageadmin.urls.share')), (r'^api/snapshots', SnapshotView.as_view()), + (r'^api/snapper', include('storageadmin.urls.snapper')), (r'^api/users', include('storageadmin.urls.users')), (r'^api/groups', include('storageadmin.urls.groups')), url(r'^api/nfs-exports$', NFSExportGroupListView.as_view()), From d576fa47d1ce5380ca3387feb2d4f59062905e74 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Tue, 18 Oct 2016 15:47:16 +0200 Subject: [PATCH 10/40] Add snapper snapshot list view --- src/rockstor/storageadmin/urls/snapper.py | 7 ++++--- src/rockstor/storageadmin/views/__init__.py | 2 +- src/rockstor/storageadmin/views/snapper.py | 11 +++++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/rockstor/storageadmin/urls/snapper.py b/src/rockstor/storageadmin/urls/snapper.py index c4b4c2e85..e2cc6d50b 100644 --- a/src/rockstor/storageadmin/urls/snapper.py +++ b/src/rockstor/storageadmin/urls/snapper.py @@ -17,11 +17,12 @@ """ from django.conf.urls import patterns, url -from storageadmin.views import SnapperConfigList, SnapperConfigDetail +from storageadmin import views urlpatterns = patterns( '', - url(r'^$', SnapperConfigList.as_view()), - url(r'^/([\w-]+)$', SnapperConfigDetail.as_view()), + url(r'^$', views.SnapperConfigList.as_view()), + url(r'^/([\w-]+)$', views.SnapperConfigDetail.as_view()), + url(r'^/([\w-]+)/$', views.SnapperSnapshotList.as_view()), ) diff --git a/src/rockstor/storageadmin/views/__init__.py b/src/rockstor/storageadmin/views/__init__.py index eccc91c21..022654e4e 100644 --- a/src/rockstor/storageadmin/views/__init__.py +++ b/src/rockstor/storageadmin/views/__init__.py @@ -55,4 +55,4 @@ from email_client import EmailClientView from update_subscription import (UpdateSubscriptionListView, UpdateSubscriptionDetailView) -from snapper import SnapperConfigList, SnapperConfigDetail +from snapper import SnapperConfigList, SnapperConfigDetail, SnapperSnapshotList diff --git a/src/rockstor/storageadmin/views/snapper.py b/src/rockstor/storageadmin/views/snapper.py index 6f2310c90..f5ffa74e1 100644 --- a/src/rockstor/storageadmin/views/snapper.py +++ b/src/rockstor/storageadmin/views/snapper.py @@ -6,6 +6,7 @@ from storageadmin.serializers import SnapperConfigSerializer from rest_framework import views from rest_framework.response import Response +from rest_framework.exceptions import NotFound from system.snapper import Snapper """ @@ -48,3 +49,13 @@ def get(self, request, name): def delete(self, request, name): return + + +class SnapperSnapshotList(views.APIView): + def get(self, request, name): + try: + snapshots = snapper.ListSnapshots(name) + except: + return NotFound + else: + return Response(snapshots) From a6b3477b68069e7df433cfee2813b384bf3518d1 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Tue, 18 Oct 2016 16:04:37 +0200 Subject: [PATCH 11/40] Handle snapper exceptions in viewer Looks a little cleaner and more appropriate to me. --- src/rockstor/storageadmin/views/snapper.py | 9 +++++++-- src/rockstor/system/snapper.py | 10 ++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/rockstor/storageadmin/views/snapper.py b/src/rockstor/storageadmin/views/snapper.py index f5ffa74e1..d73f602e3 100644 --- a/src/rockstor/storageadmin/views/snapper.py +++ b/src/rockstor/storageadmin/views/snapper.py @@ -45,7 +45,12 @@ class SnapperConfigDetail(views.APIView): """Create/edit/delete a snapper configuration. """ def get(self, request, name): - return Response(snapper.get_config(name)) + try: + config = snapper.get_config(name) + except: + raise NotFound('Configuration \'%s\' not found.' % name) + else: + return Response(config) def delete(self, request, name): return @@ -56,6 +61,6 @@ def get(self, request, name): try: snapshots = snapper.ListSnapshots(name) except: - return NotFound + raise NotFound else: return Response(snapshots) diff --git a/src/rockstor/system/snapper.py b/src/rockstor/system/snapper.py index 4225a3261..27b0fc998 100644 --- a/src/rockstor/system/snapper.py +++ b/src/rockstor/system/snapper.py @@ -6,7 +6,6 @@ from dbus import SystemBus, Interface, DBusException from contextlib import contextmanager from storageadmin.util import handle_exception -from rest_framework.exceptions import NotFound """ Copyright (c) 2016 RockStor, Inc. @@ -48,13 +47,8 @@ def get_config(self, name): """Apply some parsing to output of GetConfig, which returns a list of str, str, {} representing the name, subvolume and settings. """ - config = {} - try: - output = self.GetConfig(name) - except: - raise NotFound('Configuration \'%s\' not found.' % name) - else: - return self._parse_config(output) + output = self.GetConfig(name) + return self._parse_config(output) def _parse_config(self, raw): """Return the relevant options as a dictionary. From 2af61770bea6ac96229ccf1eb6e97a16f93b6a49 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Tue, 18 Oct 2016 18:47:19 +0200 Subject: [PATCH 12/40] Return snapshot list as a dictionary --- src/rockstor/storageadmin/views/snapper.py | 6 +-- src/rockstor/system/snapper.py | 55 +++++++++++++++++++++- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/rockstor/storageadmin/views/snapper.py b/src/rockstor/storageadmin/views/snapper.py index d73f602e3..315e09cca 100644 --- a/src/rockstor/storageadmin/views/snapper.py +++ b/src/rockstor/storageadmin/views/snapper.py @@ -59,8 +59,8 @@ def delete(self, request, name): class SnapperSnapshotList(views.APIView): def get(self, request, name): try: - snapshots = snapper.ListSnapshots(name) + snapshot_list = snapper.list_snapshots(name) except: - raise NotFound + raise NotFound('Configuration \'%s\' not found.' % name) else: - return Response(snapshots) + return Response(snapshot_list) diff --git a/src/rockstor/system/snapper.py b/src/rockstor/system/snapper.py index 27b0fc998..66f4a9319 100644 --- a/src/rockstor/system/snapper.py +++ b/src/rockstor/system/snapper.py @@ -4,7 +4,8 @@ from osi import run_command from dbus import SystemBus, Interface, DBusException -from contextlib import contextmanager +from time import gmtime, asctime +from pwd import getpwuid from storageadmin.util import handle_exception """ @@ -50,6 +51,58 @@ def get_config(self, name): output = self.GetConfig(name) return self._parse_config(output) + def list_snapshots(self, name): + """Return snapshot information as a dictionary. + + The output of ListSnapshots is a list with the following elements: + int: snapshot number + int: snapshot type (0 = single, 1 = pre, 2 = post) + int: pre-number if a post snapshot, else 0 + int: -1 or timestamp in seconds since Unix epoch + int: uid + str: description + str: cleanup algorithm + dict: userdata + + These are parsed into a more readable dictionary format, where pairs + of pre and post snapshots are combined into one listing. + """ + snapshots = self.ListSnapshots(name) + snapshot_list = [] + snapshot_types = ['single', 'pre', 'post'] + + def timestamp(t): + """Convert unix time to human-readable. + """ + return asctime(gmtime(t)) if t != -1 else '' + + for snapshot in snapshots: + # If this snapshot has a pre-number, combine its data with the + # previous snapshot and don't make a new entry. + if snapshot[2]: + data = snapshot_list[-1] + data['number'] += ', %s' % snapshot[0] + data['end_time'] = timestamp(snapshot[3]) + data['type'] += ', post' + continue + + userdata = ' '.join('%s=%s' % (key, value) + for key, value in snapshot[7].items()) + data = { + 'number': str(snapshot[0]), + 'type': snapshot_types[snapshot[1]], + 'start_time': timestamp(snapshot[3]), + 'end_time': '', + 'user': getpwuid(snapshot[4])[0], + 'description': snapshot[5], + 'cleanup': snapshot[6], + 'userdata': userdata + } + + snapshot_list.append(data) + + return snapshot_list + def _parse_config(self, raw): """Return the relevant options as a dictionary. """ From f24fafa360c14d1deaae182b6549f58f5f50fea3 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Tue, 18 Oct 2016 21:52:10 +0200 Subject: [PATCH 13/40] Revert "Update all occurrences of this.options" This reverts commit 4eca94936d04819f3e63854594721b9fa659a489. --- .../static/storageadmin/js/rockstor.js | 22 +++++++++---------- .../storageadmin/js/views/add_afp_share.js | 4 ++-- .../static/storageadmin/js/views/add_group.js | 4 ++-- .../js/views/add_replication_task.js | 4 ++-- .../storageadmin/js/views/add_samba_export.js | 4 ++-- .../js/views/add_scheduled_task.js | 4 ++-- .../static/storageadmin/js/views/add_share.js | 4 ++-- .../static/storageadmin/js/views/add_user.js | 4 ++-- .../storageadmin/js/views/blink_disks.js | 4 ++-- .../js/views/configure_service.js | 6 ++--- .../storageadmin/js/views/create_clone.js | 8 +++---- .../storageadmin/js/views/dashboard_config.js | 6 ++--- .../js/views/disk_details_layout_view.js | 4 ++-- .../storageadmin/js/views/docker_service.js | 4 ++-- .../js/views/edit_network_connection.js | 4 ++-- .../storageadmin/js/views/edit_nfs_export.js | 4 ++-- .../js/views/pool_details_layout_view.js | 6 ++--- .../js/views/pool_rebalance_table.js | 10 ++++----- .../storageadmin/js/views/pool_scrub_table.js | 10 ++++----- .../js/views/replica_receive_trails.js | 4 ++-- .../storageadmin/js/views/replica_trails.js | 4 ++-- .../static/storageadmin/js/views/rollback.js | 6 ++--- .../storageadmin/js/views/setup_system.js | 4 ++-- .../js/views/share_details_layout_view.js | 6 ++--- .../js/views/share_usage_module.js | 4 ++-- .../js/views/smartcustom_disks.js | 4 ++-- .../static/storageadmin/js/views/snapshots.js | 6 ++--- .../storageadmin/js/views/snapshots_table.js | 10 ++++----- .../storageadmin/js/views/spindown_disks.js | 4 ++-- .../static/storageadmin/js/views/tasks.js | 4 ++-- 30 files changed, 86 insertions(+), 86 deletions(-) diff --git a/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js b/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js index ad4ae7b7e..06608af00 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js @@ -118,11 +118,11 @@ RockStorWidgetView = Backbone.View.extend({ 'click .download-widget': 'download' }, - initialize: function(options) { - this.maximized = options.maximized; - this.name = options.name; - this.displayName = options.displayName; - this.parentView = options.parentView; + initialize: function() { + this.maximized = this.options.maximized; + this.name = this.options.name; + this.displayName = this.options.displayName; + this.parentView = this.options.parentView; this.dependencies = []; }, @@ -455,9 +455,9 @@ var RockstorUtil = function() { RockstorWizardPage = Backbone.View.extend({ - initialize: function(options) { - this.evAgg = options.evAgg; - this.parent = options.parent; + initialize: function() { + this.evAgg = this.options.evAgg; + this.parent = this.options.parent; }, render: function() { @@ -480,7 +480,7 @@ WizardView = Backbone.View.extend({ 'click #prev-page': 'prevPage' }, - initialize: function(options) { + initialize: function() { this.template = window.JST.wizard_wizard; this.pages = null; this.currentPage = null; @@ -489,8 +489,8 @@ WizardView = Backbone.View.extend({ this.evAgg = _.extend({}, Backbone.Events); this.evAgg.bind('nextPage', this.nextPage, this); this.evAgg.bind('prevPage', this.prevPage, this); - this.parent = options.parent; - this.title = options.title; + this.parent = this.options.parent; + this.title = this.options.title; }, setPages: function(pages) { diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_afp_share.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_afp_share.js index aad7f1592..117709d25 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_afp_share.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_afp_share.js @@ -29,14 +29,14 @@ AddAFPShareView = RockstorLayoutView.extend({ "click #cancel": "cancel" }, - initialize: function(options) { + initialize: function() { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.afp_add_afp_share; this.shares = new ShareCollection(); // dont paginate shares for now this.shares.pageSize = RockStorGlobals.maxPageSize; this.dependencies.push(this.shares); - this.afpShareId = options.afpShareId || null; + this.afpShareId = this.options.afpShareId || null; this.afpShares = new AFPCollection({afpShareId: this.afpShareId}); this.dependencies.push(this.afpShares); this.yes_no_choices = [ diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_group.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_group.js index 6f05510b1..dcee5c394 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_group.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_group.js @@ -29,12 +29,12 @@ AddGroupView = RockstorLayoutView.extend({ "click #cancel": "cancel" }, - initialize: function(options) { + initialize: function() { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template this.template = window.JST.users_add_group; - this.groupname = options.groupname; + this.groupname = this.options.groupname; this.group = new Group({groupname: this.groupname}); this.dependencies.push(this.group); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_replication_task.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_replication_task.js index 91de199ce..46835e5d3 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_replication_task.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_replication_task.js @@ -31,7 +31,7 @@ AddReplicationTaskView = RockstorLayoutView.extend({ "change #appliance": "fetchRemotePools" }, - initialize: function(options) { + initialize: function() { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.replication_add_replication_task; this.shares = new ShareCollection(); @@ -44,7 +44,7 @@ AddReplicationTaskView = RockstorLayoutView.extend({ this.dependencies.push(this.replicas); this.remote_pools = []; - this.replicaId = options.replicaId; + this.replicaId = this.options.replicaId; if (!_.isUndefined(this.replicaId) && !_.isNull(this.replicaId)) { this.replica = new Replica({id: this.replicaId}); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_samba_export.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_samba_export.js index 7956ff18e..8dfa71871 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_samba_export.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_samba_export.js @@ -31,7 +31,7 @@ AddSambaExportView = RockstorLayoutView.extend({ 'click #shadow_copy': 'toggleSnapPrefix' }, - initialize: function(options) { + initialize: function() { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.samba_add_samba_export; this.shares = new ShareCollection(); @@ -41,7 +41,7 @@ AddSambaExportView = RockstorLayoutView.extend({ this.users.pageSize = RockStorGlobals.maxPageSize; this.dependencies.push(this.shares); this.dependencies.push(this.users); - this.sambaShareId = options.sambaShareId || null; + this.sambaShareId = this.options.sambaShareId || null; this.sambaShares = new SambaCollection({sambaShareId: this.sambaShareId}); this.dependencies.push(this.sambaShares); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_scheduled_task.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_scheduled_task.js index 7e1ed9123..3445e45c7 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_scheduled_task.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_scheduled_task.js @@ -31,7 +31,7 @@ AddScheduledTaskView = RockstorLayoutView.extend({ "change #task_type": "renderOptionalFields" }, - initialize: function(options) { + initialize: function() { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.scheduled_tasks_add_task; this.snapshotFieldsTemplate = window.JST.scheduled_tasks_snapshot_fields; @@ -42,7 +42,7 @@ AddScheduledTaskView = RockstorLayoutView.extend({ this.pools.pageSize = RockStorGlobals.maxPageSize; this.dependencies.push(this.shares); this.dependencies.push(this.pools); - this.taskDefId = options.taskDefId; + this.taskDefId = this.options.taskDefId; if (!_.isUndefined(this.taskDefId) && !_.isNull(this.taskDefId)) { this.taskDef = new TaskDef({id: this.taskDefId}); this.dependencies.push(this.taskDef); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_share.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_share.js index c69d42177..a2102b051 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_share.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_share.js @@ -33,11 +33,11 @@ AddShareView = Backbone.View.extend({ "click #js-cancel": "cancel" }, - initialize: function(options) { + initialize: function() { var _this = this; this.pools = new PoolCollection(); this.pools.pageSize = RockStorGlobals.maxPageSize; - this.preSelectedPoolName = options.poolName || null; + this.preSelectedPoolName = this.options.poolName || null; this.tickFormatter = function(d) { var formatter = d3.format(",.1f"); if (d > 1024) { diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_user.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_user.js index 895107d95..c658d3499 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_user.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_user.js @@ -29,12 +29,12 @@ AddUserView = RockstorLayoutView.extend({ "click #cancel": "cancel" }, - initialize: function(options) { + initialize: function() { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template this.template = window.JST.users_add_user; - this.username = options.username; + this.username = this.options.username; if (!_.isUndefined(this.username)) { this.user = new User({username: this.username}); this.dependencies.push(this.user); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/blink_disks.js b/src/rockstor/storageadmin/static/storageadmin/js/views/blink_disks.js index ff35a0db6..9258ec0f5 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/blink_disks.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/blink_disks.js @@ -29,11 +29,11 @@ BlinkDiskView = RockstorLayoutView.extend({ 'click #cancel': 'cancel' }, - initialize: function(options) { + initialize: function() { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.disk_blink_disks; this.disks = new DiskCollection(); - this.diskName = options.diskName; + this.diskName = this.options.diskName; this.dependencies.push(this.disks); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/configure_service.js b/src/rockstor/storageadmin/static/storageadmin/js/views/configure_service.js index 794ab1d32..81115b764 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/configure_service.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/configure_service.js @@ -32,12 +32,12 @@ ConfigureServiceView = RockstorLayoutView.extend({ "click #mode": "toggleNutFields" }, - initialize: function(options) { + initialize: function() { // call initialize of base var _this = this; this.constructor.__super__.initialize.apply(this, arguments); - this.serviceName = options.serviceName; - this.adStatus = options.adStatus; + this.serviceName = this.options.serviceName; + this.adStatus = this.options.adStatus; // set template this.template = window.JST['services_configure_' + this.serviceName]; this.rules = { diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/create_clone.js b/src/rockstor/storageadmin/static/storageadmin/js/views/create_clone.js index 7aa2d38e1..f34b22580 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/create_clone.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/create_clone.js @@ -29,12 +29,12 @@ CreateCloneView = RockstorLayoutView.extend({ "click #js-cancel": "cancel" }, - initialize: function(options) { + initialize: function() { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.share_create_clone; - this.sourceType = options.sourceType; - this.shareName = options.shareName; - this.snapName = options.snapName; + this.sourceType = this.options.sourceType; + this.shareName = this.options.shareName; + this.snapName = this.options.snapName; }, render: function() { diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard_config.js b/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard_config.js index 72bd42a52..fe358e111 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard_config.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard_config.js @@ -29,10 +29,10 @@ DashboardConfigView = Backbone.View.extend({ "click .widget-name": "widgetClicked" }, - initialize: function(options) { - this.dashboardconfig = options.dashboardconfig; + initialize: function() { + this.dashboardconfig = this.options.dashboardconfig; this.template = window.JST.dashboard_dashboard_config; - this.parentView = options.parentView; + this.parentView = this.options.parentView; this.initHandlebarHelpers(); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/disk_details_layout_view.js b/src/rockstor/storageadmin/static/storageadmin/js/views/disk_details_layout_view.js index 708a1a9fb..97972c6ef 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/disk_details_layout_view.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/disk_details_layout_view.js @@ -26,10 +26,10 @@ DiskDetailsLayoutView = RockstorLayoutView.extend({ - initialize: function (options) { + initialize: function () { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); - this.diskName = options.diskName; + this.diskName = this.options.diskName; this.template = window.JST.disk_disk_details_layout; this.disk = new Disk({diskName: this.diskName}); this.smartinfo = new SmartInfo({diskName: this.diskName}); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/docker_service.js b/src/rockstor/storageadmin/static/storageadmin/js/views/docker_service.js index 5d26496ad..f060b0ed6 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/docker_service.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/docker_service.js @@ -29,11 +29,11 @@ DockerServiceView = Backbone.View.extend({ 'switchChange.bootstrapSwitch': 'switchStatus', }, - initialize: function(options) { + initialize: function() { this.template = window.JST.rockons_docker_service; this.serviceName = 'docker'; this.service = new Service({name: this.serviceName}); - this.parentView = options.parentView; + this.parentView = this.options.parentView; this.updateFreq = 30000; }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/edit_network_connection.js b/src/rockstor/storageadmin/static/storageadmin/js/views/edit_network_connection.js index 9b980e285..67e87aa19 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/edit_network_connection.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/edit_network_connection.js @@ -33,9 +33,9 @@ NetworkConnectionView = RockstorLayoutView.extend({ 'change #ctype': 'renderCTypeOptionalFields' }, - initialize: function(options) { + initialize: function() { this.constructor.__super__.initialize.apply(this, arguments); - this.connectionId = options.connectionId || null; + this.connectionId = this.options.connectionId || null; this.connection = null; this.template = window.JST.network_new_connection; this.devices = new NetworkDeviceCollection(); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/edit_nfs_export.js b/src/rockstor/storageadmin/static/storageadmin/js/views/edit_nfs_export.js index 8aee2c093..801d62ea0 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/edit_nfs_export.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/edit_nfs_export.js @@ -29,11 +29,11 @@ EditNFSExportView = RockstorLayoutView.extend({ 'click #cancel': 'cancel' }, - initialize: function(options) { + initialize: function() { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.nfs_edit_nfs_export; this.shares = new ShareCollection(); - this.nfsExportGroupId = options.nfsExportGroupId; + this.nfsExportGroupId = this.options.nfsExportGroupId; if(this.nfsExportGroupId > 0) { this.nfsExportGroup = new NFSExportGroup({id: this.nfsExportGroupId}); this.nfsExportNotEmpty = true; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_details_layout_view.js b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_details_layout_view.js index 1f36d0b5d..12b7ad778 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_details_layout_view.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_details_layout_view.js @@ -26,11 +26,11 @@ PoolDetailsLayoutView = RockstorLayoutView.extend({ - initialize: function(options) { + initialize: function() { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); - this.poolName = options.poolName; - this.cView = options.cView; + this.poolName = this.options.poolName; + this.cView = this.options.cView; this.template = window.JST.pool_pool_details_layout; this.resize_pool_info_template = window.JST.pool_resize_pool_info; this.compression_info_template = window.JST.pool_compression_info; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_rebalance_table.js b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_rebalance_table.js index ae9793771..6078d8903 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_rebalance_table.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_rebalance_table.js @@ -30,15 +30,15 @@ PoolRebalanceTableModule = RockstorModuleView.extend({ "click #js-poolrebalance-cancel": "cancel" }, - initialize: function(options) { + initialize: function() { this.template = window.JST.pool_poolrebalance_table_template; this.startRebalanceTemplate = window.JST.pool_poolrebalance_start_template; this.module_name = 'poolrebalances'; - this.pool = options.pool; - this.poolrebalances = options.poolrebalances; - this.collection = options.poolrebalances; + this.pool = this.options.pool; + this.poolrebalances = this.options.poolrebalances; + this.collection = this.options.poolrebalances; this.collection.on("reset", this.render, this); - this.parentView = options.parentView; + this.parentView = this.options.parentView; this.initHandlebarHelpers(); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_scrub_table.js b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_scrub_table.js index 6815e584a..725ee577c 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_scrub_table.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_scrub_table.js @@ -30,15 +30,15 @@ PoolScrubTableModule = RockstorModuleView.extend({ "click #js-poolscrub-cancel": "cancel" }, - initialize: function(options) { + initialize: function() { this.template = window.JST.pool_poolscrub_table_template; this.startScrubTemplate = window.JST.pool_poolscrub_start_template; this.module_name = 'poolscrubs'; - this.pool = options.pool; - this.poolscrubs = options.poolscrubs; - this.collection = options.poolscrubs; + this.pool = this.options.pool; + this.poolscrubs = this.options.poolscrubs; + this.collection = this.options.poolscrubs; this.collection.on("reset", this.render, this); - this.parentView = options.parentView; + this.parentView = this.options.parentView; this.initHandlebarHelpers(); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/replica_receive_trails.js b/src/rockstor/storageadmin/static/storageadmin/js/views/replica_receive_trails.js index 4e93ed9e0..e2237e2d4 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/replica_receive_trails.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/replica_receive_trails.js @@ -29,13 +29,13 @@ ReplicaReceiveTrailsView = RockstorLayoutView.extend({ events: { }, - initialize: function(options) { + initialize: function() { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template this.template = window.JST.replication_receive_trails; // add dependencies - this.replicaShareId = options.replicaShareId; + this.replicaShareId = this.options.replicaShareId; this.replicaShare = new ReplicaShare({id: this.replicaShareId}); this.dependencies.push(this.replicaShare); this.collection = new ReceiveTrailCollection(null, { diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/replica_trails.js b/src/rockstor/storageadmin/static/storageadmin/js/views/replica_trails.js index bd23d9dcd..6081ccfac 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/replica_trails.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/replica_trails.js @@ -29,13 +29,13 @@ ReplicaTrailsView = RockstorLayoutView.extend({ events: { }, - initialize: function(options) { + initialize: function() { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template this.template = window.JST.replication_replica_trails; // add dependencies - this.replicaId = options.replicaId; + this.replicaId = this.options.replicaId; this.replica = new Replica({id: this.replicaId}); this.dependencies.push(this.replica); this.collection = new ReplicaTrailCollection(null, { diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/rollback.js b/src/rockstor/storageadmin/static/storageadmin/js/views/rollback.js index dc6b776b5..b21cd0715 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/rollback.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/rollback.js @@ -30,16 +30,16 @@ RollbackView = RockstorLayoutView.extend({ 'click #js-confirm-rollback-submit': 'confirmRollback' }, - initialize: function(options) { + initialize: function() { this.constructor.__super__.initialize.apply(this, arguments); // Templates this.template = window.JST.share_rollback; this.snapshot_list_template = window.JST.share_rollback_snapshot_list; // Dependencies - this.share = new Share({shareName: options.shareName}); + this.share = new Share({shareName: this.options.shareName}); this.collection = new SnapshotCollection(); this.collection.pageSize = 10; - this.collection.setUrl(options.shareName); + this.collection.setUrl(this.options.shareName); this.dependencies.push(this.share); this.dependencies.push(this.collection); this.collection.on('reset', this.renderSnapshotList, this); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/setup_system.js b/src/rockstor/storageadmin/static/storageadmin/js/views/setup_system.js index 72e38cafb..d2aff64db 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/setup_system.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/setup_system.js @@ -27,9 +27,9 @@ SetupSystemView = Backbone.View.extend({ tagName: 'div', - initialize: function(options) { + initialize: function() { this.template = window.JST.setup_system; - this.sysinfo = options.sysinfo; + this.sysinfo = this.options.sysinfo; }, render: function() { diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/share_details_layout_view.js b/src/rockstor/storageadmin/static/storageadmin/js/views/share_details_layout_view.js index b98272cd4..7516118b9 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/share_details_layout_view.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/share_details_layout_view.js @@ -38,10 +38,10 @@ ShareDetailsLayoutView = RockstorLayoutView.extend({ "click #js-confirm-share-delete": "confirmShareDelete", }, - initialize: function(options) { + initialize: function() { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); - this.shareName = options.shareName; + this.shareName = this.options.shareName; this.template = window.JST.share_share_details_layout; this.rollback_btn_template = window.JST.share_share_details_rollback_btn; this.shareAclTemplate = window.JST.share_share_acl; @@ -81,7 +81,7 @@ ShareDetailsLayoutView = RockstorLayoutView.extend({ ]; this.on('snapshotsModified', this.renderRollbackBtn, this); this.cOpts = {'no': 'Dont enable compression', 'zlib': 'zlib', 'lzo': 'lzo'}; - this.cView = options.cView; + this.cView = this.options.cView; this.initHandlebarHelpers(); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/share_usage_module.js b/src/rockstor/storageadmin/static/storageadmin/js/views/share_usage_module.js index d9393ed8d..46f796ab5 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/share_usage_module.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/share_usage_module.js @@ -32,11 +32,11 @@ ShareUsageModule = RockstorModuleView.extend({ }, - initialize: function(options) { + initialize: function() { this.template = window.JST.share_share_usage_module; this.editTemplate = window.JST.share_share_usage_edit; this.module_name = 'share-usage'; - this.share = options.share; + this.share = this.options.share; this.initHandlebarHelpers(); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/smartcustom_disks.js b/src/rockstor/storageadmin/static/storageadmin/js/views/smartcustom_disks.js index f4dbf09cb..f8e10b3cd 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/smartcustom_disks.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/smartcustom_disks.js @@ -29,11 +29,11 @@ SmartcustomDiskView = RockstorLayoutView.extend({ 'click #cancel': 'cancel' }, - initialize: function (options) { + initialize: function () { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.disk_smartcustom_disks; this.disks = new DiskCollection(); - this.diskName = options.diskName; + this.diskName = this.options.diskName; this.dependencies.push(this.disks); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots.js b/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots.js index 0a529a413..f23927361 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots.js @@ -34,12 +34,12 @@ SnapshotsView = SnapshotsCommonView.extend({ "click #js-snapshot-delete-multiple": "deleteMultipleSnapshots" }, - initialize: function(options) { + initialize: function() { this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.share_snapshots; this.addTemplate = window.JST.share_snapshot_add_template; this.module_name = 'snapshots'; - this.snapshots = options.snapshots; + this.snapshots = this.options.snapshots; this.collection = new SnapshotsCollection(); this.shares = new ShareCollection(); this.dependencies.push(this.shares); @@ -52,7 +52,7 @@ SnapshotsView = SnapshotsCommonView.extend({ {name: 'yes', value: 'yes'}, {name: 'no', value: 'no'}, ]; - this.parentView = options.parentView; + this.parentView = this.options.parentView; this.collection.on("reset", this.renderSnapshots, this); this.initHandlebarHelpers(); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots_table.js b/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots_table.js index 152a91bba..478220317 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots_table.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots_table.js @@ -35,20 +35,20 @@ SnapshotsTableModule = SnapshotsCommonView.extend({ "click #js-snapshot-delete-multiple": "deleteMultipleSnapshots" }, - initialize: function(options) { + initialize: function() { this.template = window.JST.share_snapshots_table_template; this.addTemplate = window.JST.share_snapshot_add; this.module_name = 'snapshots'; - this.share = options.share; - this.snapshots = options.snapshots; - this.collection = options.snapshots; + this.share = this.options.share; + this.snapshots = this.options.snapshots; + this.collection = this.options.snapshots; this.collection.on("reset", this.render, this); this.selectedSnapshots = []; this.modify_choices = [ {name: 'yes', value: 'yes'}, {name: 'no', value: 'no'}, ]; - this.parentView = options.parentView; + this.parentView = this.options.parentView; this.initHandlebarHelpers(); }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/spindown_disks.js b/src/rockstor/storageadmin/static/storageadmin/js/views/spindown_disks.js index 97478fa7d..aa908a6ab 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/spindown_disks.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/spindown_disks.js @@ -29,12 +29,12 @@ SpindownDiskView = RockstorLayoutView.extend({ 'click #cancel': 'cancel' }, - initialize: function (options) { + initialize: function () { var _this = this; this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.disk_spindown_disks; this.disks = new DiskCollection(); - this.diskName = options.diskName; + this.diskName = this.options.diskName; this.dependencies.push(this.disks); this.tickFormatter = function (d) { var formatter = d3.format(",.0f"); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/tasks.js b/src/rockstor/storageadmin/static/storageadmin/js/views/tasks.js index bc9ba04cd..5c560c40d 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/tasks.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/tasks.js @@ -29,13 +29,13 @@ TasksView = RockstorLayoutView.extend({ events: { }, - initialize: function(options) { + initialize: function() { // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template this.template = window.JST.scheduled_tasks_tasks; // add dependencies - this.taskDefId = options.taskDefId; + this.taskDefId = this.options.taskDefId; this.taskDef = new TaskDef({id: this.taskDefId}); this.dependencies.push(this.taskDef); this.collection = new TaskCollection(null, { From 19def16710901cb715c4593a6bd5090dac66e028 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Tue, 18 Oct 2016 21:47:08 +0200 Subject: [PATCH 14/40] Update handling of Backbone view options Newer versions of Backbone no longer implicitly attach these to the view, so the relevant initialize functions now do so explicitly. --- .../static/storageadmin/js/rockstor.js | 535 +++++++++--------- .../storageadmin/js/views/add_afp_share.js | 3 +- .../static/storageadmin/js/views/add_group.js | 3 +- .../js/views/add_replication_task.js | 1 + .../storageadmin/js/views/add_samba_export.js | 3 +- .../static/storageadmin/js/views/add_share.js | 3 +- .../static/storageadmin/js/views/add_user.js | 3 +- .../storageadmin/js/views/blink_disks.js | 3 +- .../js/views/configure_service.js | 3 +- .../storageadmin/js/views/dashboard_config.js | 3 +- .../js/views/disk_details_layout_view.js | 3 +- .../storageadmin/js/views/docker_service.js | 3 +- .../js/views/edit_network_connection.js | 3 +- .../storageadmin/js/views/edit_nfs_export.js | 3 +- .../js/views/pool_details_layout_view.js | 3 +- .../js/views/pool_rebalance_table.js | 3 +- .../storageadmin/js/views/pool_scrub_table.js | 3 +- .../js/views/replica_receive_trails.js | 3 +- .../storageadmin/js/views/replica_trails.js | 3 +- .../static/storageadmin/js/views/rollback.js | 3 +- .../storageadmin/js/views/setup_system.js | 3 +- .../js/views/share_details_layout_view.js | 3 +- .../js/views/share_usage_module.js | 3 +- .../js/views/smartcustom_disks.js | 3 +- .../static/storageadmin/js/views/snapshots.js | 3 +- .../storageadmin/js/views/snapshots_table.js | 3 +- .../storageadmin/js/views/spindown_disks.js | 3 +- .../static/storageadmin/js/views/tasks.js | 3 +- 28 files changed, 322 insertions(+), 292 deletions(-) diff --git a/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js b/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js index 06608af00..2bfa748c5 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js @@ -26,21 +26,21 @@ PaginationMixin = { events: { - "click .go-to-page": "goToPage", - "click .prev-page": "prevPage", - "click .next-page": "nextPage" + "click .go-to-page": "goToPage", + "click .prev-page": "prevPage", + "click .next-page": "nextPage" }, goToPage: function(event) { - if (event) event.preventDefault(); - this.collection.goToPage(parseInt($(event.currentTarget).attr("data-page"))); + if (event) event.preventDefault(); + this.collection.goToPage(parseInt($(event.currentTarget).attr("data-page"))); }, prevPage: function(event) { - if (event) event.preventDefault(); - this.collection.prevPage(); + if (event) event.preventDefault(); + this.collection.prevPage(); }, nextPage: function(event) { - if (event) event.preventDefault(); - this.collection.nextPage(); + if (event) event.preventDefault(); + this.collection.nextPage(); } }; @@ -49,26 +49,26 @@ RockstorLayoutView = Backbone.View.extend({ className: 'layout', initialize: function() { - this.subviews = {}; - this.dependencies = []; + this.subviews = {}; + this.dependencies = []; }, fetch: function(callback, context) { - var allDependencies = []; - _.each(this.dependencies, function(dep) { - allDependencies.push(dep.fetch({silent: true})); - }); - $.when.apply($, allDependencies).done(function () { - if (callback) callback.apply(context); - }); + var allDependencies = []; + _.each(this.dependencies, function(dep) { + allDependencies.push(dep.fetch({silent: true})); + }); + $.when.apply($, allDependencies).done(function () { + if (callback) callback.apply(context); + }); }, renderDataTables: function(){ - $('table.data-table').DataTable({ - "iDisplayLength": 15, - "aLengthMenu": [[15, 30, 45, -1], [15, 30, 45, "All"]], - }); - }, + $('table.data-table').DataTable({ + "iDisplayLength": 15, + "aLengthMenu": [[15, 30, 45, -1], [15, 30, 45, "All"]], + }); + }, }); @@ -82,28 +82,28 @@ RockstorModuleView = Backbone.View.extend({ requestCount: 0, initialize: function() { - this.subviews = {}; - this.dependencies = []; + this.subviews = {}; + this.dependencies = []; }, fetch: function(callback, context) { - var allDependencies = []; - _.each(this.dependencies, function(dep) { - allDependencies.push(dep.fetch({silent: true})); - }); - $.when.apply($, allDependencies).done(function () { - if (callback) callback.apply(context); - }); + var allDependencies = []; + _.each(this.dependencies, function(dep) { + allDependencies.push(dep.fetch({silent: true})); + }); + $.when.apply($, allDependencies).done(function () { + if (callback) callback.apply(context); + }); }, render: function() { - $(this.el).html(this.template({ - module_name: this.module_name, - model: this.model, - collection: this.collection - })); + $(this.el).html(this.template({ + module_name: this.module_name, + model: this.model, + collection: this.collection + })); - return this; + return this; } }); @@ -112,118 +112,119 @@ RockStorWidgetView = Backbone.View.extend({ className: 'widget', events: { - 'click .configure-widget': 'configure', - 'click .resize-widget': 'resize', - 'click .close-widget': 'close', - 'click .download-widget': 'download' + 'click .configure-widget': 'configure', + 'click .resize-widget': 'resize', + 'click .close-widget': 'close', + 'click .download-widget': 'download' }, - initialize: function() { - this.maximized = this.options.maximized; - this.name = this.options.name; - this.displayName = this.options.displayName; - this.parentView = this.options.parentView; - this.dependencies = []; + initialize: function(options) { + this.options = options || {} + this.maximized = this.options.maximized; + this.name = this.options.name; + this.displayName = this.options.displayName; + this.parentView = this.options.parentView; + this.dependencies = []; }, render: function() { - $(this.el).attr('id', this.name + '_widget'); + $(this.el).attr('id', this.name + '_widget'); }, configure: function(event) { - if (!_.isUndefined(event) && !_.isNull(event)) { - event.preventDefault(); - } + if (!_.isUndefined(event) && !_.isNull(event)) { + event.preventDefault(); + } }, resize: function(event) { - if (!_.isUndefined(event) && !_.isNull(event)) { - event.preventDefault(); - } - var c = $(this.el).closest('div.widgets-container'); - var w = $(this.el).closest('div.widget-ph'); // current widget - var widgetDef = RockStorWidgets.findByName(this.name); - if (!this.maximized) { - // Maximizing - // Remember current position - this.originalPosition = w.index(); - // remove list item from current position - w.detach(); - // insert at first position in the list - c.prepend(w); - // resize to max - w.attr('data-ss-colspan',widgetDef.maxCols); - w.attr('data-ss-rowspan',widgetDef.maxRows); - this.maximized = true; - } else { - // Restoring - w.detach(); - w.attr('data-ss-colspan',widgetDef.cols); - w.attr('data-ss-rowspan',widgetDef.rows); - // find current list item at original index - if (_.isNull(this.originalPosition) || - _.isUndefined(this.originalPosition)) { - this.originalPosition = 0; - } - curr_w = c.find("div.widget-ph:eq("+this.originalPosition+")"); - // insert widget at original position - if (curr_w.length > 0) { - // if not last widget - curr_w.before(w); - } else { - c.append(w); - } - this.maximized = false; - } - // trigger rearrange so shapeshift can do its job - c.trigger('ss-rearrange'); - this.parentView.saveWidgetConfiguration(); + if (!_.isUndefined(event) && !_.isNull(event)) { + event.preventDefault(); + } + var c = $(this.el).closest('div.widgets-container'); + var w = $(this.el).closest('div.widget-ph'); // current widget + var widgetDef = RockStorWidgets.findByName(this.name); + if (!this.maximized) { + // Maximizing + // Remember current position + this.originalPosition = w.index(); + // remove list item from current position + w.detach(); + // insert at first position in the list + c.prepend(w); + // resize to max + w.attr('data-ss-colspan',widgetDef.maxCols); + w.attr('data-ss-rowspan',widgetDef.maxRows); + this.maximized = true; + } else { + // Restoring + w.detach(); + w.attr('data-ss-colspan',widgetDef.cols); + w.attr('data-ss-rowspan',widgetDef.rows); + // find current list item at original index + if (_.isNull(this.originalPosition) || + _.isUndefined(this.originalPosition)) { + this.originalPosition = 0; + } + curr_w = c.find("div.widget-ph:eq("+this.originalPosition+")"); + // insert widget at original position + if (curr_w.length > 0) { + // if not last widget + curr_w.before(w); + } else { + c.append(w); + } + this.maximized = false; + } + // trigger rearrange so shapeshift can do its job + c.trigger('ss-rearrange'); + this.parentView.saveWidgetConfiguration(); }, close: function(event) { - if (!_.isUndefined(event) && !_.isNull(event)) { - event.preventDefault(); - } - this.parentView.removeWidget(this.name, this); + if (!_.isUndefined(event) && !_.isNull(event)) { + event.preventDefault(); + } + this.parentView.removeWidget(this.name, this); }, download: function(event) { - if (!_.isUndefined(event) && !_.isNull(event)) { - event.preventDefault(); - } + if (!_.isUndefined(event) && !_.isNull(event)) { + event.preventDefault(); + } }, cleanup: function() { - logger.debug("In RockStorWidgetView close"); + logger.debug("In RockStorWidgetView close"); }, fetch: function(callback, context) { - var allDependencies = []; - _.each(this.dependencies, function(dep) { - allDependencies.push(dep.fetch({silent: true})); - }); - $.when.apply($, allDependencies).done(function () { - if (callback) callback.apply(context); - }); + var allDependencies = []; + _.each(this.dependencies, function(dep) { + allDependencies.push(dep.fetch({silent: true})); + }); + $.when.apply($, allDependencies).done(function () { + if (callback) callback.apply(context); + }); } }); function getCookie(name) { - var cookieValue = null; - if (document.cookie && document.cookie != '') { - var cookies = document.cookie.split(';'); - for (var i = 0; i < cookies.length; i++) { - var cookie = jQuery.trim(cookies[i]); - // Does this cookie string begin with the name we want? - if (cookie.substring(0, name.length + 1) == (name + '=')) { - cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); - break; - } - } - } - return cookieValue; + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; } function csrfSafeMethod(method) { @@ -234,16 +235,16 @@ function csrfSafeMethod(method) { $.ajaxSetup({ crossDomain: false, // obviates need for sameOrigin test beforeSend: function(xhr, settings) { - if (!csrfSafeMethod(settings.type)) { - var csrftoken = getCookie('csrftoken'); - xhr.setRequestHeader("X-CSRFToken", csrftoken); - } + if (!csrfSafeMethod(settings.type)) { + var csrftoken = getCookie('csrftoken'); + xhr.setRequestHeader("X-CSRFToken", csrftoken); + } } }); function showApplianceList() { var applianceSelectPopup = $('#appliance-select-popup').modal({ - show: false + show: false }); $('#appliance-select-content').html((new AppliancesView()).render().el); $('#appliance-select-popup').modal('show'); @@ -296,32 +297,32 @@ function enableButton(button) { function buttonDisabled(button) { if (button.data("executing")) { - return true; + return true; } else { - return false; + return false; } } function refreshNavbar() { $.ajax({ - url: "api/commands/current-user", - type: "POST", - dataType: "json", - global: false, // dont show global loading indicator - success: function(data, status, xhr) { - var currentUser= data; - $('#user-name').css({textTransform: 'none'}); - $('#user-name').html(currentUser+' '); - }, - error: function(xhr, status, error) { - // $('#user-name').html("Hello, Admin! "); - } + url: "api/commands/current-user", + type: "POST", + dataType: "json", + global: false, // dont show global loading indicator + success: function(data, status, xhr) { + var currentUser= data; + $('#user-name').css({textTransform: 'none'}); + $('#user-name').html(currentUser+' '); + }, + error: function(xhr, status, error) { + // $('#user-name').html("Hello, Admin! "); + } }); var navbarTemplate = window.JST.common_navbar; $("#navbar-links").html(navbarTemplate({ - logged_in: logged_in + logged_in: logged_in })); @@ -334,14 +335,14 @@ function refreshNavbar() { function parseXhrError(xhr) { var msg = xhr.responseText; try { - msg = JSON.parse(msg).detail; + msg = JSON.parse(msg).detail; } catch(err) { } if (typeof(msg)=="string") { - try { - msg = JSON.parse(msg); - } catch(err) { - } + try { + msg = JSON.parse(msg); + } catch(err) { + } } return msg; } @@ -355,48 +356,48 @@ function getXhrErrorJson(xhr) { function setApplianceName() { var appliances = new ApplianceCollection(); appliances.fetch({ - success: function(request) { - if (appliances.length > 0) { - RockStorGlobals.currentAppliance = - appliances.find(function(appliance) { - return appliance.get('current_appliance') == true; - }); - $('#appliance-name').html(' Hostname: ' + RockStorGlobals.currentAppliance.get('hostname') + '    Mgmt IP: ' + RockStorGlobals.currentAppliance.get('ip')); - } - }, - error: function(request, response) { - } + success: function(request) { + if (appliances.length > 0) { + RockStorGlobals.currentAppliance = + appliances.find(function(appliance) { + return appliance.get('current_appliance') == true; + }); + $('#appliance-name').html(' Hostname: ' + RockStorGlobals.currentAppliance.get('hostname') + '    Mgmt IP: ' + RockStorGlobals.currentAppliance.get('ip')); + } + }, + error: function(request, response) { + } }); } function fetchDependencies(dependencies, callback, context) { if (dependencies.length == 0) { - if (callback) callback.apply(context); + if (callback) callback.apply(context); } var requestCount = dependencies.length; _.each(dependencies, function(dependency) { - dependency.fetch({ - success: function(request){ - requestCount -= 1; - if (requestCount == 0) { - if (callback) callback.apply(context); - } - }, - error: function(request, response) { - requestCount -= 1; - if (requestCount == 0) { - if (callback) callback.apply(context); - } - } - }); + dependency.fetch({ + success: function(request){ + requestCount -= 1; + if (requestCount == 0) { + if (callback) callback.apply(context); + } + }, + error: function(request, response) { + requestCount -= 1; + if (requestCount == 0) { + if (callback) callback.apply(context); + } + } + }); }); } function checkBrowser() { var userAgent = navigator.userAgent; if (!/firefox/i.test(userAgent) && !/chrome/i.test(userAgent)) { - $('#browsermsg').html('
The RockStor WebUI is supported only on Firefox or Chrome. Some features may not work correctly.
'); + $('#browsermsg').html('
The RockStor WebUI is supported only on Firefox or Chrome. Some features may not work correctly.
'); } RockStorGlobals.browserChecked = true; } @@ -423,52 +424,53 @@ probeStates = { var RockstorUtil = function() { var util = { - // maintain selected object list - // list is an array of contains models - - // does the list contain a model with attr 'name' with value 'value' - listContains: function(list, name, value) { - return _.find(list, function(obj) { - return obj.get(name) == value; - }); - }, - - // add obj from collection with attr 'name' and value 'value' to list - addToList: function(list, collection, name, value) { - list.push(collection.find(function(obj) { - return obj.get(name) == value; - })); - }, - - // remove obj with attr 'name' and value 'value' - removeFromList: function(list, name, value) { - var i = _.indexOf(_.map(list, function(obj) { - return obj.get(name); - }), value); - if (i != -1) { - list.splice(i,1); - } - } + // maintain selected object list + // list is an array of contains models + + // does the list contain a model with attr 'name' with value 'value' + listContains: function(list, name, value) { + return _.find(list, function(obj) { + return obj.get(name) == value; + }); + }, + + // add obj from collection with attr 'name' and value 'value' to list + addToList: function(list, collection, name, value) { + list.push(collection.find(function(obj) { + return obj.get(name) == value; + })); + }, + + // remove obj with attr 'name' and value 'value' + removeFromList: function(list, name, value) { + var i = _.indexOf(_.map(list, function(obj) { + return obj.get(name); + }), value); + if (i != -1) { + list.splice(i,1); + } + } }; return util; }(); RockstorWizardPage = Backbone.View.extend({ - initialize: function() { - this.evAgg = this.options.evAgg; - this.parent = this.options.parent; + initialize: function(options) { + this.options = options || {} + this.evAgg = this.options.evAgg; + this.parent = this.options.parent; }, render: function() { - $(this.el).html(this.template({ - model: this.model - })); - return this; + $(this.el).html(this.template({ + model: this.model + })); + return this; }, save: function() { - return $.Deferred().resolve(); + return $.Deferred().resolve(); } }); @@ -476,108 +478,109 @@ WizardView = Backbone.View.extend({ tagName: 'div', events: { - 'click #next-page': 'nextPage', - 'click #prev-page': 'prevPage' + 'click #next-page': 'nextPage', + 'click #prev-page': 'prevPage' }, - initialize: function() { - this.template = window.JST.wizard_wizard; - this.pages = null; - this.currentPage = null; - this.currentPageNum = -1; - this.contentEl = '#ph-wizard-contents'; - this.evAgg = _.extend({}, Backbone.Events); - this.evAgg.bind('nextPage', this.nextPage, this); - this.evAgg.bind('prevPage', this.prevPage, this); - this.parent = this.options.parent; - this.title = this.options.title; + initialize: function(options) { + this.options = options || {} + this.template = window.JST.wizard_wizard; + this.pages = null; + this.currentPage = null; + this.currentPageNum = -1; + this.contentEl = '#ph-wizard-contents'; + this.evAgg = _.extend({}, Backbone.Events); + this.evAgg.bind('nextPage', this.nextPage, this); + this.evAgg.bind('prevPage', this.prevPage, this); + this.parent = this.options.parent; + this.title = this.options.title; }, setPages: function(pages) { - this.pages = pages; + this.pages = pages; }, render: function() { - $(this.el).html(this.template({ - title: this.title, - model: this.model - })); - this.nextPage(); - return this; + $(this.el).html(this.template({ + title: this.title, + model: this.model + })); + this.nextPage(); + return this; }, nextPage: function() { - var _this = this; - var promise = !_.isNull(this.currentPage) ? - this.currentPage.save() : - $.Deferred().resolve(); - promise.done(function(result, status, jqXHR) { - _this.incrementPage(); - }); - promise.fail(function(jqXHR, status, error) { - console.log(error); - }); + var _this = this; + var promise = !_.isNull(this.currentPage) ? + this.currentPage.save() : + $.Deferred().resolve(); + promise.done(function(result, status, jqXHR) { + _this.incrementPage(); + }); + promise.fail(function(jqXHR, status, error) { + console.log(error); + }); }, incrementPageNum: function() { - this.currentPageNum = this.currentPageNum + 1; + this.currentPageNum = this.currentPageNum + 1; }, decrementPageNum: function() { - this.currentPageNum = this.currentPageNum - 1; + this.currentPageNum = this.currentPageNum - 1; }, incrementPage: function() { - if (!this.lastPage()) { - this.incrementPageNum(); - this.setCurrentPage(); - this.renderCurrentPage(); - } else { - this.finish(); - } + if (!this.lastPage()) { + this.incrementPageNum(); + this.setCurrentPage(); + this.renderCurrentPage(); + } else { + this.finish(); + } }, decrementPage: function() { - if (!this.firstPage()) { - this.decrementPageNum(); - this.setCurrentPage(); - this.renderCurrentPage(); - } + if (!this.firstPage()) { + this.decrementPageNum(); + this.setCurrentPage(); + this.renderCurrentPage(); + } }, setCurrentPage: function() { - this.currentPage = new this.pages[this.currentPageNum]({ - model: this.model, - evAgg: this.evAgg - }); + this.currentPage = new this.pages[this.currentPageNum]({ + model: this.model, + evAgg: this.evAgg + }); }, renderCurrentPage: function() { - this.$(this.contentEl).html(this.currentPage.render().el); - this.modifyButtonText(); + this.$(this.contentEl).html(this.currentPage.render().el); + this.modifyButtonText(); }, prevPage: function() { - this.decrementPage(); + this.decrementPage(); }, modifyButtonText: function() { - if (this.lastPage()) { - this.$('#next-page').html('Finish'); - } else { - this.$('#next-page').html('Next'); - } + if (this.lastPage()) { + this.$('#next-page').html('Finish'); + } else { + this.$('#next-page').html('Next'); + } }, firstPage: function() { - return (this.currentPageNum == 0); + return (this.currentPageNum == 0); }, lastPage: function() { - return (this.currentPageNum == (this.pages.length - 1)); + return (this.currentPageNum == (this.pages.length - 1)); }, finish: function() { - console.log('finish'); + console.log('finish'); } }); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_afp_share.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_afp_share.js index 117709d25..8d40f78af 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_afp_share.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_afp_share.js @@ -29,7 +29,8 @@ AddAFPShareView = RockstorLayoutView.extend({ "click #cancel": "cancel" }, - initialize: function() { + initialize: function(options) { + this.options = options || {} this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.afp_add_afp_share; this.shares = new ShareCollection(); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_group.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_group.js index dcee5c394..504359d76 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_group.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_group.js @@ -29,7 +29,8 @@ AddGroupView = RockstorLayoutView.extend({ "click #cancel": "cancel" }, - initialize: function() { + initialize: function(options) { + this.options = options || {} // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_replication_task.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_replication_task.js index 46835e5d3..488ea989f 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_replication_task.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_replication_task.js @@ -32,6 +32,7 @@ AddReplicationTaskView = RockstorLayoutView.extend({ }, initialize: function() { + this.options = options || {} this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.replication_add_replication_task; this.shares = new ShareCollection(); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_samba_export.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_samba_export.js index 8dfa71871..02d1d737e 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_samba_export.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_samba_export.js @@ -31,7 +31,8 @@ AddSambaExportView = RockstorLayoutView.extend({ 'click #shadow_copy': 'toggleSnapPrefix' }, - initialize: function() { + initialize: function(options) { + this.options = options || {} this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.samba_add_samba_export; this.shares = new ShareCollection(); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_share.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_share.js index a2102b051..dfda086d4 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_share.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_share.js @@ -33,7 +33,8 @@ AddShareView = Backbone.View.extend({ "click #js-cancel": "cancel" }, - initialize: function() { + initialize: function(options) { + this.options = options || {} var _this = this; this.pools = new PoolCollection(); this.pools.pageSize = RockStorGlobals.maxPageSize; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/add_user.js b/src/rockstor/storageadmin/static/storageadmin/js/views/add_user.js index c658d3499..7413276db 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/add_user.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/add_user.js @@ -29,7 +29,8 @@ AddUserView = RockstorLayoutView.extend({ "click #cancel": "cancel" }, - initialize: function() { + initialize: function(options) { + this.options = options || {} // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/blink_disks.js b/src/rockstor/storageadmin/static/storageadmin/js/views/blink_disks.js index 9258ec0f5..3dfbd0cb9 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/blink_disks.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/blink_disks.js @@ -29,7 +29,8 @@ BlinkDiskView = RockstorLayoutView.extend({ 'click #cancel': 'cancel' }, - initialize: function() { + initialize: function(options) { + this.options = options || {} this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.disk_blink_disks; this.disks = new DiskCollection(); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/configure_service.js b/src/rockstor/storageadmin/static/storageadmin/js/views/configure_service.js index 81115b764..c4640d179 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/configure_service.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/configure_service.js @@ -32,7 +32,8 @@ ConfigureServiceView = RockstorLayoutView.extend({ "click #mode": "toggleNutFields" }, - initialize: function() { + initialize: function(options) { + this.options = options || {} // call initialize of base var _this = this; this.constructor.__super__.initialize.apply(this, arguments); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard_config.js b/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard_config.js index fe358e111..fd19c0075 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard_config.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/dashboard_config.js @@ -29,7 +29,8 @@ DashboardConfigView = Backbone.View.extend({ "click .widget-name": "widgetClicked" }, - initialize: function() { + initialize: function(options) { + this.options = options || {} this.dashboardconfig = this.options.dashboardconfig; this.template = window.JST.dashboard_dashboard_config; this.parentView = this.options.parentView; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/disk_details_layout_view.js b/src/rockstor/storageadmin/static/storageadmin/js/views/disk_details_layout_view.js index 97972c6ef..d7f036d1b 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/disk_details_layout_view.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/disk_details_layout_view.js @@ -26,7 +26,8 @@ DiskDetailsLayoutView = RockstorLayoutView.extend({ - initialize: function () { + initialize: function (options) { + this.options = options || {} // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); this.diskName = this.options.diskName; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/docker_service.js b/src/rockstor/storageadmin/static/storageadmin/js/views/docker_service.js index f060b0ed6..840adef74 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/docker_service.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/docker_service.js @@ -29,7 +29,8 @@ DockerServiceView = Backbone.View.extend({ 'switchChange.bootstrapSwitch': 'switchStatus', }, - initialize: function() { + initialize: function(options) { + this.options = options || {} this.template = window.JST.rockons_docker_service; this.serviceName = 'docker'; this.service = new Service({name: this.serviceName}); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/edit_network_connection.js b/src/rockstor/storageadmin/static/storageadmin/js/views/edit_network_connection.js index 67e87aa19..f48a79e19 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/edit_network_connection.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/edit_network_connection.js @@ -33,7 +33,8 @@ NetworkConnectionView = RockstorLayoutView.extend({ 'change #ctype': 'renderCTypeOptionalFields' }, - initialize: function() { + initialize: function(options) { + this.options = options || {} this.constructor.__super__.initialize.apply(this, arguments); this.connectionId = this.options.connectionId || null; this.connection = null; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/edit_nfs_export.js b/src/rockstor/storageadmin/static/storageadmin/js/views/edit_nfs_export.js index 801d62ea0..c718fd8f4 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/edit_nfs_export.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/edit_nfs_export.js @@ -29,7 +29,8 @@ EditNFSExportView = RockstorLayoutView.extend({ 'click #cancel': 'cancel' }, - initialize: function() { + initialize: function(options) { + this.options = options || {} this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.nfs_edit_nfs_export; this.shares = new ShareCollection(); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_details_layout_view.js b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_details_layout_view.js index 12b7ad778..a32b0e783 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_details_layout_view.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_details_layout_view.js @@ -26,7 +26,8 @@ PoolDetailsLayoutView = RockstorLayoutView.extend({ - initialize: function() { + initialize: function(options) { + this.options = options || {} // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); this.poolName = this.options.poolName; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_rebalance_table.js b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_rebalance_table.js index 6078d8903..17b16cba1 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_rebalance_table.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_rebalance_table.js @@ -30,7 +30,8 @@ PoolRebalanceTableModule = RockstorModuleView.extend({ "click #js-poolrebalance-cancel": "cancel" }, - initialize: function() { + initialize: function(options) { + this.options = options || {} this.template = window.JST.pool_poolrebalance_table_template; this.startRebalanceTemplate = window.JST.pool_poolrebalance_start_template; this.module_name = 'poolrebalances'; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_scrub_table.js b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_scrub_table.js index 725ee577c..498971c6c 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/pool_scrub_table.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/pool_scrub_table.js @@ -30,7 +30,8 @@ PoolScrubTableModule = RockstorModuleView.extend({ "click #js-poolscrub-cancel": "cancel" }, - initialize: function() { + initialize: function(options) { + this.options = options || {} this.template = window.JST.pool_poolscrub_table_template; this.startScrubTemplate = window.JST.pool_poolscrub_start_template; this.module_name = 'poolscrubs'; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/replica_receive_trails.js b/src/rockstor/storageadmin/static/storageadmin/js/views/replica_receive_trails.js index e2237e2d4..907a13a75 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/replica_receive_trails.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/replica_receive_trails.js @@ -29,7 +29,8 @@ ReplicaReceiveTrailsView = RockstorLayoutView.extend({ events: { }, - initialize: function() { + initialize: function(options) { + this.options = options || {} // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/replica_trails.js b/src/rockstor/storageadmin/static/storageadmin/js/views/replica_trails.js index 6081ccfac..e016f3410 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/replica_trails.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/replica_trails.js @@ -29,7 +29,8 @@ ReplicaTrailsView = RockstorLayoutView.extend({ events: { }, - initialize: function() { + initialize: function(options) { + this.options = options || {} // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/rollback.js b/src/rockstor/storageadmin/static/storageadmin/js/views/rollback.js index b21cd0715..8a2bf4a55 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/rollback.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/rollback.js @@ -30,7 +30,8 @@ RollbackView = RockstorLayoutView.extend({ 'click #js-confirm-rollback-submit': 'confirmRollback' }, - initialize: function() { + initialize: function(option) { + this.options = options || {} this.constructor.__super__.initialize.apply(this, arguments); // Templates this.template = window.JST.share_rollback; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/setup_system.js b/src/rockstor/storageadmin/static/storageadmin/js/views/setup_system.js index d2aff64db..ee45c153f 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/setup_system.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/setup_system.js @@ -27,7 +27,8 @@ SetupSystemView = Backbone.View.extend({ tagName: 'div', - initialize: function() { + initialize: function(options) { + this.options = options || {} this.template = window.JST.setup_system; this.sysinfo = this.options.sysinfo; }, diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/share_details_layout_view.js b/src/rockstor/storageadmin/static/storageadmin/js/views/share_details_layout_view.js index 7516118b9..5f63bfe9a 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/share_details_layout_view.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/share_details_layout_view.js @@ -38,7 +38,8 @@ ShareDetailsLayoutView = RockstorLayoutView.extend({ "click #js-confirm-share-delete": "confirmShareDelete", }, - initialize: function() { + initialize: function(options) { + this.options = options || {} // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); this.shareName = this.options.shareName; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/share_usage_module.js b/src/rockstor/storageadmin/static/storageadmin/js/views/share_usage_module.js index 46f796ab5..a37dafb7b 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/share_usage_module.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/share_usage_module.js @@ -32,7 +32,8 @@ ShareUsageModule = RockstorModuleView.extend({ }, - initialize: function() { + initialize: function(options) { + this.options = options || {} this.template = window.JST.share_share_usage_module; this.editTemplate = window.JST.share_share_usage_edit; this.module_name = 'share-usage'; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/smartcustom_disks.js b/src/rockstor/storageadmin/static/storageadmin/js/views/smartcustom_disks.js index f8e10b3cd..56a1567de 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/smartcustom_disks.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/smartcustom_disks.js @@ -29,7 +29,8 @@ SmartcustomDiskView = RockstorLayoutView.extend({ 'click #cancel': 'cancel' }, - initialize: function () { + initialize: function (options) { + this.options = options || {} this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.disk_smartcustom_disks; this.disks = new DiskCollection(); diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots.js b/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots.js index f23927361..77115303a 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots.js @@ -34,7 +34,8 @@ SnapshotsView = SnapshotsCommonView.extend({ "click #js-snapshot-delete-multiple": "deleteMultipleSnapshots" }, - initialize: function() { + initialize: function(options) { + this.options = options || {} this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.share_snapshots; this.addTemplate = window.JST.share_snapshot_add_template; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots_table.js b/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots_table.js index 478220317..03f54f303 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots_table.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/snapshots_table.js @@ -35,7 +35,8 @@ SnapshotsTableModule = SnapshotsCommonView.extend({ "click #js-snapshot-delete-multiple": "deleteMultipleSnapshots" }, - initialize: function() { + initialize: function(options) { + this.options = options || {} this.template = window.JST.share_snapshots_table_template; this.addTemplate = window.JST.share_snapshot_add; this.module_name = 'snapshots'; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/spindown_disks.js b/src/rockstor/storageadmin/static/storageadmin/js/views/spindown_disks.js index aa908a6ab..0fa1def73 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/spindown_disks.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/spindown_disks.js @@ -29,7 +29,8 @@ SpindownDiskView = RockstorLayoutView.extend({ 'click #cancel': 'cancel' }, - initialize: function () { + initialize: function (options) { + this.options = options || {} var _this = this; this.constructor.__super__.initialize.apply(this, arguments); this.template = window.JST.disk_spindown_disks; diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/tasks.js b/src/rockstor/storageadmin/static/storageadmin/js/views/tasks.js index 5c560c40d..16314a9e2 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/views/tasks.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/tasks.js @@ -29,7 +29,8 @@ TasksView = RockstorLayoutView.extend({ events: { }, - initialize: function() { + initialize: function(options) { + this.options = options || {} // call initialize of base this.constructor.__super__.initialize.apply(this, arguments); // set template From 6667d7b3db50afba26a4dc55cca6c7fbae824daa Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Wed, 19 Oct 2016 12:58:42 +0200 Subject: [PATCH 15/40] Refactor snapshot data parsing Allow retrieving individual snapshots as well as full list. --- src/rockstor/system/snapper.py | 49 +++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/rockstor/system/snapper.py b/src/rockstor/system/snapper.py index 66f4a9319..aed5d5001 100644 --- a/src/rockstor/system/snapper.py +++ b/src/rockstor/system/snapper.py @@ -69,12 +69,6 @@ def list_snapshots(self, name): """ snapshots = self.ListSnapshots(name) snapshot_list = [] - snapshot_types = ['single', 'pre', 'post'] - - def timestamp(t): - """Convert unix time to human-readable. - """ - return asctime(gmtime(t)) if t != -1 else '' for snapshot in snapshots: # If this snapshot has a pre-number, combine its data with the @@ -82,27 +76,17 @@ def timestamp(t): if snapshot[2]: data = snapshot_list[-1] data['number'] += ', %s' % snapshot[0] - data['end_time'] = timestamp(snapshot[3]) + data['end_time'] = self._parse_timestamp(snapshot[3]) data['type'] += ', post' continue - userdata = ' '.join('%s=%s' % (key, value) - for key, value in snapshot[7].items()) - data = { - 'number': str(snapshot[0]), - 'type': snapshot_types[snapshot[1]], - 'start_time': timestamp(snapshot[3]), - 'end_time': '', - 'user': getpwuid(snapshot[4])[0], - 'description': snapshot[5], - 'cleanup': snapshot[6], - 'userdata': userdata - } - - snapshot_list.append(data) + snapshot_list.append(self._parse_snapshot(snapshot)) return snapshot_list + def get_snapshot(self, config, number): + return self._parse_snapshot(self.GetSnapshot(config, number)) + def _parse_config(self, raw): """Return the relevant options as a dictionary. """ @@ -110,3 +94,26 @@ def _parse_config(self, raw): config['NAME'] = raw[0] config['SUBVOLUME'] = raw[1] return config + + def _parse_snapshot(self, snapshot): + snapshot_types = ['single', 'pre', 'post'] + userdata = ' '.join('%s=%s' % (key, value) + for key, value in snapshot[7].items()) + return { + 'number': str(snapshot[0]), + 'type': snapshot_types[snapshot[1]], + 'start_time': self._parse_timestamp(snapshot[3]), + 'end_time': '', + 'user': getpwuid(snapshot[4])[0], + 'description': snapshot[5], + 'cleanup': snapshot[6], + 'userdata': userdata + } + + def _parse_timestamp(self, t): + """Convert a snapshot timestamp to human-readable format. + + Snapper reports either an integer representing seconds since UNIX + epoch, or -1 for the "current" snapshot. + """ + return asctime(gmtime(t)) if t != -1 else '' From 598b862375146b6d7ac0acede1d810bd637ff44a Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Wed, 19 Oct 2016 18:26:37 +0200 Subject: [PATCH 16/40] Fix erroneous imports --- src/rockstor/storageadmin/views/snapper.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/rockstor/storageadmin/views/snapper.py b/src/rockstor/storageadmin/views/snapper.py index 315e09cca..6bb909242 100644 --- a/src/rockstor/storageadmin/views/snapper.py +++ b/src/rockstor/storageadmin/views/snapper.py @@ -2,8 +2,6 @@ Views for all things related to snapper """ -from storageadmin.models import SnapperConfig -from storageadmin.serializers import SnapperConfigSerializer from rest_framework import views from rest_framework.response import Response from rest_framework.exceptions import NotFound From cefc991b5c3cbc59988df313ba685c547dab898b Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Thu, 20 Oct 2016 15:15:53 +0200 Subject: [PATCH 17/40] Return config name with snapshot, sanitise code This allows the collections of snapshots to be nested below their configuration name in the web API. --- src/rockstor/system/snapper.py | 54 ++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/rockstor/system/snapper.py b/src/rockstor/system/snapper.py index aed5d5001..514c450c0 100644 --- a/src/rockstor/system/snapper.py +++ b/src/rockstor/system/snapper.py @@ -44,30 +44,17 @@ def __init__(self): def config_list(self): return [self._parse_config(config) for config in self.ListConfigs()] - def get_config(self, name): + def get_config(self, config): """Apply some parsing to output of GetConfig, which returns a list of str, str, {} representing the name, subvolume and settings. """ - output = self.GetConfig(name) + output = self.GetConfig(config) return self._parse_config(output) - def list_snapshots(self, name): - """Return snapshot information as a dictionary. - - The output of ListSnapshots is a list with the following elements: - int: snapshot number - int: snapshot type (0 = single, 1 = pre, 2 = post) - int: pre-number if a post snapshot, else 0 - int: -1 or timestamp in seconds since Unix epoch - int: uid - str: description - str: cleanup algorithm - dict: userdata - - These are parsed into a more readable dictionary format, where pairs - of pre and post snapshots are combined into one listing. + def list_snapshots(self, config): + """Return snapshot information as a list of dictionaries. """ - snapshots = self.ListSnapshots(name) + snapshots = self.ListSnapshots(config) snapshot_list = [] for snapshot in snapshots: @@ -80,12 +67,15 @@ def list_snapshots(self, name): data['type'] += ', post' continue - snapshot_list.append(self._parse_snapshot(snapshot)) + snapshot_list.append(self._parse_snapshot(config, snapshot)) return snapshot_list def get_snapshot(self, config, number): - return self._parse_snapshot(self.GetSnapshot(config, number)) + """Return single snapshot information. + """ + snapshot = self.GetSnapshot(config, number) + return self._parse_snapshot(config, snapshot) def _parse_config(self, raw): """Return the relevant options as a dictionary. @@ -95,19 +85,31 @@ def _parse_config(self, raw): config['SUBVOLUME'] = raw[1] return config - def _parse_snapshot(self, snapshot): - snapshot_types = ['single', 'pre', 'post'] - userdata = ' '.join('%s=%s' % (key, value) - for key, value in snapshot[7].items()) + def _parse_snapshot(self, config, snapshot): + """Parse raw snapshot data. + + The output produced by snapper is a list with the following elements: + int: snapshot number + int: snapshot type (0 = single, 1 = pre, 2 = post) + int: pre-number if a post snapshot, else 0 + int: -1 or timestamp in seconds since Unix epoch + int: uid + str: description + str: cleanup algorithm + dict: userdata + Also append the config name to make it function as a nested resource. + """ return { 'number': str(snapshot[0]), - 'type': snapshot_types[snapshot[1]], + 'type': ['single', 'pre', 'post'][snapshot[1]], 'start_time': self._parse_timestamp(snapshot[3]), 'end_time': '', 'user': getpwuid(snapshot[4])[0], 'description': snapshot[5], 'cleanup': snapshot[6], - 'userdata': userdata + 'userdata': ' '.join('%s=%s' % (key, value) + for key, value in snapshot[7].items()), + 'config': config } def _parse_timestamp(self, t): From 942820b76889f39b0d878f51ee1ef37e43625fac Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Thu, 20 Oct 2016 15:21:45 +0200 Subject: [PATCH 18/40] Implement snapshot detail view --- src/rockstor/storageadmin/urls/snapper.py | 4 +++- src/rockstor/storageadmin/views/__init__.py | 3 ++- src/rockstor/storageadmin/views/snapper.py | 14 ++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/rockstor/storageadmin/urls/snapper.py b/src/rockstor/storageadmin/urls/snapper.py index e2cc6d50b..72ee446fe 100644 --- a/src/rockstor/storageadmin/urls/snapper.py +++ b/src/rockstor/storageadmin/urls/snapper.py @@ -24,5 +24,7 @@ '', url(r'^$', views.SnapperConfigList.as_view()), url(r'^/([\w-]+)$', views.SnapperConfigDetail.as_view()), - url(r'^/([\w-]+)/$', views.SnapperSnapshotList.as_view()), + url(r'^/([\w-]+)/snapshots$', views.SnapperSnapshotList.as_view()), + url(r'^/([\w-]+)/snapshots/([0-9]+)$', + views.SnapperSnapshotDetail.as_view()), ) diff --git a/src/rockstor/storageadmin/views/__init__.py b/src/rockstor/storageadmin/views/__init__.py index 022654e4e..0b3eb4efe 100644 --- a/src/rockstor/storageadmin/views/__init__.py +++ b/src/rockstor/storageadmin/views/__init__.py @@ -55,4 +55,5 @@ from email_client import EmailClientView from update_subscription import (UpdateSubscriptionListView, UpdateSubscriptionDetailView) -from snapper import SnapperConfigList, SnapperConfigDetail, SnapperSnapshotList +from snapper import (SnapperConfigList, SnapperConfigDetail, + SnapperSnapshotList, SnapperSnapshotDetail) diff --git a/src/rockstor/storageadmin/views/snapper.py b/src/rockstor/storageadmin/views/snapper.py index 6bb909242..6a196694b 100644 --- a/src/rockstor/storageadmin/views/snapper.py +++ b/src/rockstor/storageadmin/views/snapper.py @@ -55,6 +55,8 @@ def delete(self, request, name): class SnapperSnapshotList(views.APIView): + """Return the list of snapshots for the given snapper configuration. + """ def get(self, request, name): try: snapshot_list = snapper.list_snapshots(name) @@ -62,3 +64,15 @@ def get(self, request, name): raise NotFound('Configuration \'%s\' not found.' % name) else: return Response(snapshot_list) + + +class SnapperSnapshotDetail(views.APIView): + """Return information about a specific snapshot. + """ + def get(self, request, name, number): + try: + snapshot = snapper.get_snapshot(name, number) + except Exception as e: + raise NotFound(e) + else: + return Response(snapshot) From e19482539fdf215273c9e17df04ad31aa3333a88 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Thu, 20 Oct 2016 17:35:21 +0200 Subject: [PATCH 19/40] Refactor and define a generic API view This is better suited to snapper than the ListCreateAPIView, since snapper's interface does not return Django models or querysets. --- .../rest_framework_custom/__init__.py | 2 +- .../rest_framework_custom/generic_view.py | 23 ++++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/rockstor/rest_framework_custom/__init__.py b/src/rockstor/rest_framework_custom/__init__.py index 010976d07..d0e616db3 100644 --- a/src/rockstor/rest_framework_custom/__init__.py +++ b/src/rockstor/rest_framework_custom/__init__.py @@ -16,5 +16,5 @@ along with this program. If not, see . """ -from generic_view import GenericView +from generic_view import GenericView, GenericAPIView from renderers import IgnoreClient diff --git a/src/rockstor/rest_framework_custom/generic_view.py b/src/rockstor/rest_framework_custom/generic_view.py index 3f55c01cc..6ac9accea 100644 --- a/src/rockstor/rest_framework_custom/generic_view.py +++ b/src/rockstor/rest_framework_custom/generic_view.py @@ -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 @@ -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 @@ -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 From 4927abf7cde6c3fe42bc4970852a8c8fa014df13 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Thu, 20 Oct 2016 17:58:21 +0200 Subject: [PATCH 20/40] Update base class and exception handling --- src/rockstor/storageadmin/views/snapper.py | 29 ++++++++++++++-------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/rockstor/storageadmin/views/snapper.py b/src/rockstor/storageadmin/views/snapper.py index 6a196694b..265c202fa 100644 --- a/src/rockstor/storageadmin/views/snapper.py +++ b/src/rockstor/storageadmin/views/snapper.py @@ -2,10 +2,11 @@ Views for all things related to snapper """ -from rest_framework import views +from dbus import DBusException from rest_framework.response import Response from rest_framework.exceptions import NotFound from system.snapper import Snapper +import rest_framework_custom as rfc """ Copyright (c) 2016 RockStor, Inc. @@ -29,50 +30,56 @@ snapper = Snapper() -class SnapperConfigList(views.APIView): +class SnapperConfigList(rfc.GenericAPIView): """List all snapper configurations or create a new one. """ def get(self, request): return Response(snapper.config_list()) - def put(self, request, name): - return + def post(self, request): + with self._handle_exception('Failed to create configuration'): + name = request.data.get('NAME') + subvolume = request.data.get('SUBVOLUME') + snapper.CreateConfig(name, subvolume, 'btrfs', 'default') + return Response(request.data) -class SnapperConfigDetail(views.APIView): +class SnapperConfigDetail(rfc.GenericAPIView): """Create/edit/delete a snapper configuration. """ def get(self, request, name): try: config = snapper.get_config(name) - except: + except DBusException: raise NotFound('Configuration \'%s\' not found.' % name) else: return Response(config) def delete(self, request, name): - return + with self._handle_exception('Failed to delete configuration'): + snapper.DeleteConfig(name) + return Response() -class SnapperSnapshotList(views.APIView): +class SnapperSnapshotList(rfc.GenericAPIView): """Return the list of snapshots for the given snapper configuration. """ def get(self, request, name): try: snapshot_list = snapper.list_snapshots(name) - except: + except DBusException: raise NotFound('Configuration \'%s\' not found.' % name) else: return Response(snapshot_list) -class SnapperSnapshotDetail(views.APIView): +class SnapperSnapshotDetail(rfc.GenericAPIView): """Return information about a specific snapshot. """ def get(self, request, name, number): try: snapshot = snapper.get_snapshot(name, number) - except Exception as e: + except DBusException as e: raise NotFound(e) else: return Response(snapshot) From e1d08ca9d3ec9cf8a2fc9a1318cfa4bc5fb139b3 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Thu, 20 Oct 2016 18:11:52 +0200 Subject: [PATCH 21/40] Improve HTTP response status --- src/rockstor/storageadmin/views/snapper.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rockstor/storageadmin/views/snapper.py b/src/rockstor/storageadmin/views/snapper.py index 265c202fa..8380d9eeb 100644 --- a/src/rockstor/storageadmin/views/snapper.py +++ b/src/rockstor/storageadmin/views/snapper.py @@ -5,6 +5,7 @@ from dbus import DBusException from rest_framework.response import Response from rest_framework.exceptions import NotFound +from rest_framework import status from system.snapper import Snapper import rest_framework_custom as rfc @@ -41,7 +42,7 @@ def post(self, request): name = request.data.get('NAME') subvolume = request.data.get('SUBVOLUME') snapper.CreateConfig(name, subvolume, 'btrfs', 'default') - return Response(request.data) + return Response(request.data, status=status.HTTP_201_CREATED) class SnapperConfigDetail(rfc.GenericAPIView): @@ -58,7 +59,7 @@ def get(self, request, name): def delete(self, request, name): with self._handle_exception('Failed to delete configuration'): snapper.DeleteConfig(name) - return Response() + return Response(status=status.HTTP_204_NO_CONTENT) class SnapperSnapshotList(rfc.GenericAPIView): From aaa2012a91dbde458fa1b5bb90a9d2c94b6ba1df Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Fri, 21 Oct 2016 12:49:42 +0200 Subject: [PATCH 22/40] Implement PUT for snapper configuration --- src/rockstor/storageadmin/views/snapper.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/rockstor/storageadmin/views/snapper.py b/src/rockstor/storageadmin/views/snapper.py index 8380d9eeb..7d92e245c 100644 --- a/src/rockstor/storageadmin/views/snapper.py +++ b/src/rockstor/storageadmin/views/snapper.py @@ -56,6 +56,21 @@ def get(self, request, name): else: return Response(config) + def put(self, request, name): + try: + config = snapper.get_config(name) + except DBusException: + # Config does not exist + with self._handle_exception(request): + subvolume = request.data.get('SUBVOLUME') + snapper.CreateConfig(name, subvolume, 'btrfs', 'default') + + # Ignore the read-only properties + config = {key: value for key, value in request.data.items() + if key not in ['NAME', 'SUBVOLUME', 'FSTYPE']} + snapper.SetConfig(name, config) + return Response(request.data) + def delete(self, request, name): with self._handle_exception('Failed to delete configuration'): snapper.DeleteConfig(name) From 2f3baa24b4231c53b60247897555a9a2d27c1088 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Fri, 21 Oct 2016 15:17:55 +0200 Subject: [PATCH 23/40] Modify config and snapshot parsing Configured subvolume is already returned by snapper. Return snapshot userdata as a dict because that's what SetSnapshot accepts. --- src/rockstor/system/snapper.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/rockstor/system/snapper.py b/src/rockstor/system/snapper.py index 514c450c0..eb3db0187 100644 --- a/src/rockstor/system/snapper.py +++ b/src/rockstor/system/snapper.py @@ -82,7 +82,6 @@ def _parse_config(self, raw): """ config = raw[2].copy() config['NAME'] = raw[0] - config['SUBVOLUME'] = raw[1] return config def _parse_snapshot(self, config, snapshot): @@ -107,8 +106,7 @@ def _parse_snapshot(self, config, snapshot): 'user': getpwuid(snapshot[4])[0], 'description': snapshot[5], 'cleanup': snapshot[6], - 'userdata': ' '.join('%s=%s' % (key, value) - for key, value in snapshot[7].items()), + 'userdata': snapshot[7].copy(), 'config': config } From 03f9145de994f61d20d247261ff16982bdb78514 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Fri, 21 Oct 2016 15:18:24 +0200 Subject: [PATCH 24/40] Implement PUT/DELETE for snapshots --- src/rockstor/storageadmin/views/snapper.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/rockstor/storageadmin/views/snapper.py b/src/rockstor/storageadmin/views/snapper.py index 7d92e245c..2bcf76156 100644 --- a/src/rockstor/storageadmin/views/snapper.py +++ b/src/rockstor/storageadmin/views/snapper.py @@ -8,6 +8,7 @@ from rest_framework import status from system.snapper import Snapper import rest_framework_custom as rfc +import logging """ Copyright (c) 2016 RockStor, Inc. @@ -90,7 +91,7 @@ def get(self, request, name): class SnapperSnapshotDetail(rfc.GenericAPIView): - """Return information about a specific snapshot. + """Retrieve, update or delete a particular snapshot. """ def get(self, request, name, number): try: @@ -99,3 +100,19 @@ def get(self, request, name, number): raise NotFound(e) else: return Response(snapshot) + + def put(self, request, name, number): + with self._handle_exception(request): + args = [request.data.get(item) for item in + ['description', 'cleanup', 'userdata']] + snapper.SetSnapshot(name, number, args[0], args[1], args[2]) + return Response(request.data) + + def delete(self, request, name, number): + try: + snapper.DeleteSnapshots(name, [number]) + snapper.Sync(name) + except DBusException as e: + raise NotFound(e) + else: + return Response(status=status.HTTP_204_NO_CONTENT) From 8bd70b1cbae3f17e613706d358227df72542b90a Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Fri, 21 Oct 2016 16:16:32 +0200 Subject: [PATCH 25/40] Implement POST for snapshot creation --- src/rockstor/storageadmin/views/snapper.py | 26 +++++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/rockstor/storageadmin/views/snapper.py b/src/rockstor/storageadmin/views/snapper.py index 2bcf76156..2e8a19c61 100644 --- a/src/rockstor/storageadmin/views/snapper.py +++ b/src/rockstor/storageadmin/views/snapper.py @@ -8,7 +8,6 @@ from rest_framework import status from system.snapper import Snapper import rest_framework_custom as rfc -import logging """ Copyright (c) 2016 RockStor, Inc. @@ -78,8 +77,16 @@ def delete(self, request, name): return Response(status=status.HTTP_204_NO_CONTENT) +def extract_snapshot_data(request): + """Extract the right data for creating/updating snapshots from a request. + """ + return [request.data.get(item) for item in + ('description', 'cleanup', 'userdata')] + + class SnapperSnapshotList(rfc.GenericAPIView): - """Return the list of snapshots for the given snapper configuration. + """Return the list of snapshots for the given snapper configuration, or + create a new snapshot. """ def get(self, request, name): try: @@ -89,6 +96,15 @@ def get(self, request, name): else: return Response(snapshot_list) + def post(self, request, name): + number = 0 + with self._handle_exception(request): + number = snapper.CreateSingleSnapshot( + name, *extract_snapshot_data(request) + ) + return Response(snapper.get_snapshot(name, number), + status=status.HTTP_201_CREATED) + class SnapperSnapshotDetail(rfc.GenericAPIView): """Retrieve, update or delete a particular snapshot. @@ -103,10 +119,8 @@ def get(self, request, name, number): def put(self, request, name, number): with self._handle_exception(request): - args = [request.data.get(item) for item in - ['description', 'cleanup', 'userdata']] - snapper.SetSnapshot(name, number, args[0], args[1], args[2]) - return Response(request.data) + snapper.SetSnapshot(name, number, *extract_snapshot_data(request)) + return Response(request.data, status=status.HTTP_201_CREATED) def delete(self, request, name, number): try: From f1338e1ad5905f43765552fe3c67df8c046e8bab Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Sun, 23 Oct 2016 00:07:38 +0200 Subject: [PATCH 26/40] Define new models for snapper --- .../static/storageadmin/js/models/models.js | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/rockstor/storageadmin/static/storageadmin/js/models/models.js b/src/rockstor/storageadmin/static/storageadmin/js/models/models.js index 4443a95d9..7775558c2 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/models/models.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/models/models.js @@ -706,3 +706,31 @@ 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, 'reset', this.onReset); + }, + + onReset: function() { + this.trigger('change:snapshots', this); + } +}); + +var SnapperConfigCollection = Backbone.Collection.extend({ + model: SnapperConfig, + url: '/api/snapper' +}); From 1316268a5077720fddf822fe7598940cb29b8664 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Sun, 23 Oct 2016 21:55:01 +0200 Subject: [PATCH 27/40] Change list_snapshots to return all snapshots Necessary to make deletions function appropriately. --- src/rockstor/system/snapper.py | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/src/rockstor/system/snapper.py b/src/rockstor/system/snapper.py index eb3db0187..50dfd3d42 100644 --- a/src/rockstor/system/snapper.py +++ b/src/rockstor/system/snapper.py @@ -54,28 +54,14 @@ def get_config(self, config): def list_snapshots(self, config): """Return snapshot information as a list of dictionaries. """ - snapshots = self.ListSnapshots(config) - snapshot_list = [] - - for snapshot in snapshots: - # If this snapshot has a pre-number, combine its data with the - # previous snapshot and don't make a new entry. - if snapshot[2]: - data = snapshot_list[-1] - data['number'] += ', %s' % snapshot[0] - data['end_time'] = self._parse_timestamp(snapshot[3]) - data['type'] += ', post' - continue - - snapshot_list.append(self._parse_snapshot(config, snapshot)) - - return snapshot_list + return [self._parse_snapshot(snapshot) for snapshot + in self.ListSnapshots(config)] def get_snapshot(self, config, number): """Return single snapshot information. """ snapshot = self.GetSnapshot(config, number) - return self._parse_snapshot(config, snapshot) + return self._parse_snapshot(snapshot) def _parse_config(self, raw): """Return the relevant options as a dictionary. @@ -84,7 +70,7 @@ def _parse_config(self, raw): config['NAME'] = raw[0] return config - def _parse_snapshot(self, config, snapshot): + def _parse_snapshot(self, snapshot): """Parse raw snapshot data. The output produced by snapper is a list with the following elements: @@ -96,18 +82,16 @@ def _parse_snapshot(self, config, snapshot): str: description str: cleanup algorithm dict: userdata - Also append the config name to make it function as a nested resource. """ return { - 'number': str(snapshot[0]), + 'number': snapshot[0], 'type': ['single', 'pre', 'post'][snapshot[1]], - 'start_time': self._parse_timestamp(snapshot[3]), - 'end_time': '', + 'pre_number': snapshot[2], + 'timestamp': self._parse_timestamp(snapshot[3]), 'user': getpwuid(snapshot[4])[0], 'description': snapshot[5], 'cleanup': snapshot[6], - 'userdata': snapshot[7].copy(), - 'config': config + 'userdata': snapshot[7].copy() } def _parse_timestamp(self, t): From 2c915a2fe1174063cd1655791a91d4137a7d4d59 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Mon, 24 Oct 2016 01:39:42 +0200 Subject: [PATCH 28/40] Set DataTables length menu globally --- .../static/storageadmin/js/rockstor.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js b/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js index 2bfa748c5..41c1bc1ce 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/rockstor.js @@ -44,6 +44,11 @@ PaginationMixin = { } }; +// Set global DataTables defaults +$.extend($.fn.dataTable.defaults, { + lengthMenu: [[15, 30, 45, -1], [15, 30, 45, "All"]] +}); + RockstorLayoutView = Backbone.View.extend({ tagName: 'div', className: 'layout', @@ -63,16 +68,11 @@ RockstorLayoutView = Backbone.View.extend({ }); }, - renderDataTables: function(){ - $('table.data-table').DataTable({ - "iDisplayLength": 15, - "aLengthMenu": [[15, 30, 45, -1], [15, 30, 45, "All"]], - }); + renderDataTables: function() { + $('table.data-table').DataTable(); }, - }); - // RockstorModuleView RockstorModuleView = Backbone.View.extend({ From 3418ce6baad1b0b10dad87ed22bfc2dbc2fd2b59 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Mon, 24 Oct 2016 13:56:42 +0200 Subject: [PATCH 29/40] Destroy snapshot on server upon removal --- .../storageadmin/static/storageadmin/js/models/models.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/rockstor/storageadmin/static/storageadmin/js/models/models.js b/src/rockstor/storageadmin/static/storageadmin/js/models/models.js index 7775558c2..6b40250ea 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/models/models.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/models/models.js @@ -722,11 +722,17 @@ var SnapperConfig = Backbone.Model.extend({ initialize: function() { this.snapshots = new SnapperSnapshotCollection(); this.snapshots.url = this.url() + '/snapshots'; - this.listenTo(this.snapshots, 'reset', this.onReset); + 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); } }); From b918bd5133a683e400a4791303c17ee8fecbc3b9 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Mon, 24 Oct 2016 14:03:50 +0200 Subject: [PATCH 30/40] Add dependency: DataTables select plugin --- src/rockstor/storageadmin/templates/storageadmin/base.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rockstor/storageadmin/templates/storageadmin/base.html b/src/rockstor/storageadmin/templates/storageadmin/base.html index bc97fe219..5349692b9 100644 --- a/src/rockstor/storageadmin/templates/storageadmin/base.html +++ b/src/rockstor/storageadmin/templates/storageadmin/base.html @@ -35,6 +35,7 @@ + @@ -112,6 +113,7 @@ + From 1e924ea8f7f1b4dd76a143839c1087739affeb80 Mon Sep 17 00:00:00 2001 From: Steven Franzen Date: Mon, 24 Oct 2016 14:18:04 +0200 Subject: [PATCH 31/40] Add initial UI components for snapper --- conf/settings.conf.in | 3 +- .../static/storageadmin/js/router.js | 7 + .../js/templates/snapper/main.jst | 74 +++++++++++ .../js/views/common/bootstrap_select.js | 49 +++++++ .../static/storageadmin/js/views/snapper.js | 120 ++++++++++++++++++ 5 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 src/rockstor/storageadmin/static/storageadmin/js/templates/snapper/main.jst create mode 100644 src/rockstor/storageadmin/static/storageadmin/js/views/common/bootstrap_select.js create mode 100644 src/rockstor/storageadmin/static/storageadmin/js/views/snapper.js diff --git a/conf/settings.conf.in b/conf/settings.conf.in index f9c86f0b0..530c656a0 100644 --- a/conf/settings.conf.in +++ b/conf/settings.conf.in @@ -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', @@ -422,4 +423,4 @@ ZTASKD_URL = 'ipc:///var/run/rockon-ztaskd' TASK_SCHEDULER = { 'max_log': 100 #max number of task log entries to keep -} \ No newline at end of file +} diff --git a/src/rockstor/storageadmin/static/storageadmin/js/router.js b/src/rockstor/storageadmin/static/storageadmin/js/router.js index 9708ab7d9..6a6d432a8 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/router.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/router.js @@ -52,6 +52,7 @@ var AppRouter = Backbone.Router.extend({ "shares/:shareName/rollback": "rollbackShare", "shares/:shareName/?cView=:cView": "showShare", "snapshots": "showSnapshots", + "snapper": "showSnapper", "services": "showServices", "services/:serviceName/edit": "configureService", "services/:serviceName/edit/?adStatus=:adStatus": "configureService", @@ -752,6 +753,12 @@ var AppRouter = Backbone.Router.extend({ $('#maincontent').empty(); $('#maincontent').append(this.currentLayout.render().el); }, + + showSnapper: function() { + this.renderSidebar('storage', 'snapshots'); + this.currentLayout = new SnapperMainView({el: $('#maincontent')}); + this.currentLayout.render(); + }, showShell: function() { //Special router function for shell diff --git a/src/rockstor/storageadmin/static/storageadmin/js/templates/snapper/main.jst b/src/rockstor/storageadmin/static/storageadmin/js/templates/snapper/main.jst new file mode 100644 index 000000000..b6d3e28f7 --- /dev/null +++ b/src/rockstor/storageadmin/static/storageadmin/js/templates/snapper/main.jst @@ -0,0 +1,74 @@ +{{!}} + +
+
+ + + + Edit + + + Create New + +
+
+
+ + +
+ +
+
+ + + + Run + +
+
{{! /row }} +
+

List of Snapshots

+ + +
+
diff --git a/src/rockstor/storageadmin/static/storageadmin/js/views/common/bootstrap_select.js b/src/rockstor/storageadmin/static/storageadmin/js/views/common/bootstrap_select.js new file mode 100644 index 000000000..e4bc7daf0 --- /dev/null +++ b/src/rockstor/storageadmin/static/storageadmin/js/views/common/bootstrap_select.js @@ -0,0 +1,49 @@ +/* + * + * @licstart The following is the entire license notice for the + * JavaScript code in this page. + * + * Copyright (c) 2016 RockStor, Inc. + * 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 . + * + * @licend The above is the entire license notice + * for the JavaScript code in this page. + * + */ + +// Construct using a collection of models with a 'label' property to populate +// the options list. +var BootstrapSelect = Backbone.View.extend({ + tagName: 'select', + + className: 'selectpicker', + + initialize: function() { + this.listenTo(this.collection, 'reset', this.render); + }, + + render: function() { + this.collection.each(function(element, index) { + this.$el.append($('