diff --git a/app/extensions/storidge/__module.js b/app/extensions/storidge/__module.js
index 9fe339859..6c2c3a6e6 100644
--- a/app/extensions/storidge/__module.js
+++ b/app/extensions/storidge/__module.js
@@ -32,6 +32,28 @@ angular.module('extension.storidge', [])
}
};
+ var drives = {
+ name: 'storidge.drives',
+ url: '/drives',
+ views: {
+ 'content@': {
+ templateUrl: 'app/extensions/storidge/views/drives/drives.html',
+ controller: 'StoridgeDrivesController'
+ }
+ }
+ };
+
+ var drive = {
+ name: 'storidge.drives.drive',
+ url: '/:id',
+ views: {
+ 'content@': {
+ templateUrl: 'app/extensions/storidge/views/drives/inspect/drive.html',
+ controller: 'StoridgeDriveController'
+ }
+ }
+ };
+
var profileCreation = {
name: 'storidge.profiles.new',
url: '/new',
@@ -69,6 +91,8 @@ angular.module('extension.storidge', [])
};
$stateRegistryProvider.register(storidge);
+ $stateRegistryProvider.register(drives);
+ $stateRegistryProvider.register(drive);
$stateRegistryProvider.register(profiles);
$stateRegistryProvider.register(profile);
$stateRegistryProvider.register(profileCreation);
diff --git a/app/extensions/storidge/components/cluster-events-datatable/storidgeClusterEventsDatatable.js b/app/extensions/storidge/components/cluster-events-datatable/storidgeClusterEventsDatatable.js
index c97cc3ddc..9aabd5496 100644
--- a/app/extensions/storidge/components/cluster-events-datatable/storidgeClusterEventsDatatable.js
+++ b/app/extensions/storidge/components/cluster-events-datatable/storidgeClusterEventsDatatable.js
@@ -2,7 +2,7 @@ angular.module('extension.storidge').component('storidgeClusterEventsDatatable',
templateUrl: 'app/extensions/storidge/components/cluster-events-datatable/storidgeClusterEventsDatatable.html',
controller: 'GenericDatatableController',
bindings: {
- title: '@',
+ titleText: '@',
titleIcon: '@',
dataset: '<',
tableKey: '@',
diff --git a/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.html b/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.html
new file mode 100644
index 000000000..5da25e4f0
--- /dev/null
+++ b/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.html
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.js b/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.js
new file mode 100644
index 000000000..63e4e5994
--- /dev/null
+++ b/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.js
@@ -0,0 +1,14 @@
+angular.module('extension.storidge').component('storidgeDrivesDatatable', {
+ templateUrl: 'app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatable.html',
+ controller: 'StoridgeDrivesDatatableController',
+ bindings: {
+ titleText: '@',
+ titleIcon: '@',
+ dataset: '<',
+ tableKey: '@',
+ orderBy: '@',
+ reverseOrder: '<',
+ removeAction: '<',
+ addAction: '<'
+ }
+});
diff --git a/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatableController.js b/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatableController.js
new file mode 100644
index 000000000..65f44972b
--- /dev/null
+++ b/app/extensions/storidge/components/drives-datatable/storidgeDrivesDatatableController.js
@@ -0,0 +1,16 @@
+angular.module('portainer.docker')
+ .controller('StoridgeDrivesDatatableController', ['$scope', '$controller',
+ function ($scope, $controller) {
+ angular.extend(this, $controller('GenericDatatableController', {$scope: $scope}));
+
+ this.selectAll = function() {
+ for (var i = 0; i < this.state.filteredDataSet.length; i++) {
+ var item = this.state.filteredDataSet[i];
+ if (item.Status !== 'normal' && item.Checked !== this.state.selectAll) {
+ item.Checked = this.state.selectAll;
+ this.selectItem(item);
+ }
+ }
+ };
+ }
+]);
\ No newline at end of file
diff --git a/app/extensions/storidge/components/nodes-datatable/storidgeNodesDatatable.js b/app/extensions/storidge/components/nodes-datatable/storidgeNodesDatatable.js
index 3731350dd..8fb01f9c4 100644
--- a/app/extensions/storidge/components/nodes-datatable/storidgeNodesDatatable.js
+++ b/app/extensions/storidge/components/nodes-datatable/storidgeNodesDatatable.js
@@ -2,7 +2,7 @@ angular.module('extension.storidge').component('storidgeNodesDatatable', {
templateUrl: 'app/extensions/storidge/components/nodes-datatable/storidgeNodesDatatable.html',
controller: 'GenericDatatableController',
bindings: {
- title: '@',
+ titleText: '@',
titleIcon: '@',
dataset: '<',
tableKey: '@',
diff --git a/app/extensions/storidge/components/profiles-datatable/storidgeProfilesDatatable.js b/app/extensions/storidge/components/profiles-datatable/storidgeProfilesDatatable.js
index 0d0c60a83..1b68eb929 100644
--- a/app/extensions/storidge/components/profiles-datatable/storidgeProfilesDatatable.js
+++ b/app/extensions/storidge/components/profiles-datatable/storidgeProfilesDatatable.js
@@ -2,7 +2,7 @@ angular.module('extension.storidge').component('storidgeProfilesDatatable', {
templateUrl: 'app/extensions/storidge/components/profiles-datatable/storidgeProfilesDatatable.html',
controller: 'GenericDatatableController',
bindings: {
- title: '@',
+ titleText: '@',
titleIcon: '@',
dataset: '<',
tableKey: '@',
diff --git a/app/extensions/storidge/filters/filters.js b/app/extensions/storidge/filters/filters.js
new file mode 100644
index 000000000..82c9414e7
--- /dev/null
+++ b/app/extensions/storidge/filters/filters.js
@@ -0,0 +1,15 @@
+angular.module('extension.storidge')
+.filter('drivestatusbadge', function () {
+'use strict';
+ return function (text) {
+ var status = _.toLower(text);
+ if (includeString(status, ['normal'])) {
+ return 'success';
+ } else if (includeString(status, ['available'])) {
+ return 'info';
+ } else if (includeString(status, ['faulty'])) {
+ return 'danger';
+ }
+ return 'info';
+ };
+});
\ No newline at end of file
diff --git a/app/extensions/storidge/models/drive.js b/app/extensions/storidge/models/drive.js
new file mode 100644
index 000000000..32f20fa5c
--- /dev/null
+++ b/app/extensions/storidge/models/drive.js
@@ -0,0 +1,9 @@
+function StoridgeDriveModel(data) {
+ this.Id = data.driveid;
+ this.Node = data.node;
+ this.Use = data.use;
+ this.Status = data.drivestatus.toLowerCase();
+ this.Size = data.size;
+ this.Type = data.type;
+ this.Device = data.device;
+}
diff --git a/app/extensions/storidge/rest/storidge.js b/app/extensions/storidge/rest/storidge.js
index d4a7d0793..86a5b70ee 100644
--- a/app/extensions/storidge/rest/storidge.js
+++ b/app/extensions/storidge/rest/storidge.js
@@ -15,6 +15,11 @@ angular.module('extension.storidge')
getProfile: { method: 'GET', params: { resource: 'profiles' } },
createProfile: { method: 'POST', params: { resource: 'profiles' } },
updateProfile: { method: 'PUT', params: { resource: 'profiles', id: '@name' } },
- deleteProfile: { method: 'DELETE', params: { resource: 'profiles' } }
+ deleteProfile: { method: 'DELETE', params: { resource: 'profiles' } },
+ queryDrives: { method: 'GET', params: { resource: 'drives' } },
+ getDrive: { method: 'GET', params: { resource: 'drives', id: '@id' } },
+ addDrive: { method: 'POST', params: { resource: 'drives' } },
+ removeDrive: { method: 'DELETE', params: { resource: 'drives', id: '@id' } },
+ getNode: { method: 'GET', params: { resource: 'nodes', id: '@id' } }
});
}]);
diff --git a/app/extensions/storidge/services/driveService.js b/app/extensions/storidge/services/driveService.js
new file mode 100644
index 000000000..d10638c9c
--- /dev/null
+++ b/app/extensions/storidge/services/driveService.js
@@ -0,0 +1,73 @@
+angular.module('extension.storidge')
+.factory('StoridgeDriveService', ['$q', 'Storidge', function StoridgeDriveServiceFactory($q, Storidge) {
+ 'use strict';
+ var service = {};
+
+ service.drives = function () {
+ var deferred = $q.defer();
+
+ Storidge.queryDrives().$promise
+ .then(function success(data) {
+ var driveData = data.drives;
+ var drives = driveData.map(function (drive) {
+ return new StoridgeDriveModel(drive);
+ });
+
+ deferred.resolve(drives);
+ })
+ .catch(function error(err) {
+ deferred.reject({ msg: 'Unable to retrieve Storidge drives', err: err });
+ });
+
+ return deferred.promise;
+ };
+
+ service.drive = function (id) {
+ var deferred = $q.defer();
+
+ Storidge.getDrive({ id: id }).$promise
+ .then(function success(data) {
+ var drive = new StoridgeDriveModel(data);
+ Storidge.getNode({ id: data.nodeid }).$promise
+ .then(function (data) {
+ drive.Node = data.name;
+ deferred.resolve(drive);
+ });
+ })
+ .catch(function error(err) {
+ deferred.reject({ msg: 'Unable to retrieve Storidge drive', err: err });
+ });
+
+ return deferred.promise;
+ };
+
+ service.add = function (device, node) {
+ var deferred = $q.defer();
+
+ Storidge.addDrive({ device: device, node: node }).$promise
+ .then(function success() {
+ deferred.resolve();
+ })
+ .catch(function error(err) {
+ deferred.reject({ msg: 'Unable to add Storidge drive', err: err });
+ });
+
+ return deferred.promise;
+ };
+
+ service.remove = function (id) {
+ var deferred = $q.defer();
+
+ Storidge.removeDrive({ id: id }).$promise
+ .then(function success() {
+ deferred.resolve();
+ })
+ .catch(function error(err) {
+ deferred.reject({ msg: 'Unable to remove Storidge drive', err: err });
+ });
+
+ return deferred.promise;
+ };
+
+ return service;
+}]);
diff --git a/app/extensions/storidge/views/drives/drives.html b/app/extensions/storidge/views/drives/drives.html
new file mode 100644
index 000000000..8a35e8164
--- /dev/null
+++ b/app/extensions/storidge/views/drives/drives.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+ Storidge > Drives
+
+
+
+
diff --git a/app/extensions/storidge/views/drives/drivesController.js b/app/extensions/storidge/views/drives/drivesController.js
new file mode 100644
index 000000000..b41538068
--- /dev/null
+++ b/app/extensions/storidge/views/drives/drivesController.js
@@ -0,0 +1,73 @@
+angular.module('extension.storidge')
+.controller('StoridgeDrivesController', ['$q', '$scope', '$state', 'Notifications', 'ModalService', 'StoridgeDriveService',
+function ($q, $scope, $state, Notifications, ModalService, StoridgeDriveService) {
+
+ $scope.removeAction = function(selectedItems) {
+ ModalService.confirm({
+ title: 'Are you sure?',
+ message: 'Do you want really want to remove this drive from the storage pool?',
+ buttons: {
+ confirm: {
+ label: 'Remove',
+ className: 'btn-danger'
+ }
+ },
+ callback: function onConfirm(confirmed) {
+ if(!confirmed) { return; }
+ var actionCount = selectedItems.length;
+ selectedItems = selectedItems.filter(function (item) {
+ return item.Status === 'faulty';
+ });
+ angular.forEach(selectedItems, function (drive) {
+ StoridgeDriveService.delete(drive.Id)
+ .then(function success() {
+ Notifications.success('Drive successfully removed', drive.Id);
+ })
+ .catch(function error(err) {
+ Notifications.error('Failure', err, 'Unable to remove drive');
+ })
+ .finally(function final() {
+ --actionCount;
+ if (actionCount === 0) {
+ $state.reload();
+ }
+ });
+ });
+ }
+ });
+ };
+
+ $scope.addAction = function (selectedItems) {
+ var actionCount = selectedItems.length;
+ selectedItems = selectedItems.filter(function (item) {
+ return item.Status === 'available';
+ });
+ angular.forEach(selectedItems, function (drive) {
+ StoridgeDriveService.add(drive.Id)
+ .then(function success() {
+ Notifications.success('Drive successfully added', drive.Id);
+ })
+ .catch(function error(err) {
+ Notifications.error('Failure', err, 'Unable to add drive');
+ })
+ .finally(function final() {
+ --actionCount;
+ if (actionCount === 0) {
+ $state.reload();
+ }
+ });
+ });
+ };
+
+ function initView() {
+ StoridgeDriveService.drives()
+ .then(function success(data) {
+ $scope.drives = data;
+ })
+ .catch(function error(err) {
+ Notifications.error('Failure', err, 'Unable to retrieve drives');
+ });
+ }
+
+ initView();
+}]);
diff --git a/app/extensions/storidge/views/drives/inspect/drive.html b/app/extensions/storidge/views/drives/inspect/drive.html
new file mode 100644
index 000000000..e07dd12ca
--- /dev/null
+++ b/app/extensions/storidge/views/drives/inspect/drive.html
@@ -0,0 +1,58 @@
+
+
+
+ Storidge > Drives > {{ drive.Id }}
+
+
+
+
+
+
+
+
+
+
+
+ ID |
+
+ {{ drive.Id }}
+
+
+ |
+
+
+ Node |
+ {{ drive.Node }} |
+
+
+ Device |
+ {{ drive.Device }} |
+
+
+ Size |
+ {{ drive.Size }} |
+
+
+ Use |
+ {{ drive.Use }} |
+
+
+ Type |
+ {{ drive.Type }} |
+
+
+ Status |
+
+ {{ drive.Status|capitalize }}
+ |
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/extensions/storidge/views/drives/inspect/driveController.js b/app/extensions/storidge/views/drives/inspect/driveController.js
new file mode 100644
index 000000000..b2995c885
--- /dev/null
+++ b/app/extensions/storidge/views/drives/inspect/driveController.js
@@ -0,0 +1,54 @@
+angular.module('extension.storidge')
+.controller('StoridgeDriveController', ['$scope', '$state', '$transition$', 'Notifications', 'StoridgeDriveService',
+function ($scope, $state, $transition$, Notifications, StoridgeDriveService) {
+
+ $scope.addDrive = function () {
+ StoridgeDriveService.add($scope.drive.Device, $scope.drive.Node)
+ .then(function () {
+ Notifications.success('Success', 'Drive added to storage pool');
+ $state.reload();
+ })
+ .catch(function error(err) {
+ Notifications.error('Failure', err, 'Unable to add drive to storage pool');
+ });
+ };
+
+ $scope.removeDrive = function () {
+ ModalService.confirm({
+ title: 'Are you sure?',
+ message: 'Do you want really want to remove this drive from the storage pool?',
+ buttons: {
+ confirm: {
+ label: 'Remove',
+ className: 'btn-danger'
+ }
+ },
+ callback: function onConfirm(confirmed) {
+ if(!confirmed) { return; }
+ StoridgeDriveService.remove($scope.drive.Id)
+ .then(function () {
+ Notifications.success('Success', 'Drive removed from storage pool');
+ $state.reload();
+ })
+ .catch(function error(err) {
+ Notifications.error('Failure', err, 'Unable to remove drive from storage pool');
+ });
+ }
+ });
+ };
+
+ function initView() {
+ $scope.id = $transition$.params().id;
+
+ StoridgeDriveService.drive($scope.id)
+ .then(function success(data) {
+ $scope.drive = data;
+ })
+ .catch(function error(err) {
+ Notifications.error('Failure', err, 'Unable to retrieve drive details');
+ });
+ }
+
+ initView();
+
+}]);
diff --git a/app/portainer/views/sidebar/sidebar.html b/app/portainer/views/sidebar/sidebar.html
index 776a1e35c..e1df0cf0d 100644
--- a/app/portainer/views/sidebar/sidebar.html
+++ b/app/portainer/views/sidebar/sidebar.html
@@ -29,12 +29,15 @@