mirror of https://github.com/portainer/portainer
feat(storidge): add volume and snapshot details
parent
6a5e0ea2a8
commit
48c79f7fce
|
@ -45,6 +45,24 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" ng-if="isCioDriver">
|
||||
<div class="col-sm-12">
|
||||
<volume-storidge-info volume="storidgeVolume">
|
||||
</volume-storidge-info>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" ng-if="isCioDriver">
|
||||
<div class="col-sm-12">
|
||||
<storidge-snapshots-datatable
|
||||
title-text="Snapshots" title-icon="fa-camera"
|
||||
dataset="storidgeSnapshots" table-key="storidgeSnapshots"
|
||||
order-by="Id"
|
||||
remove-action="removeSnapshot">
|
||||
</storidge-snapshots-datatable>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- access-control-panel -->
|
||||
<por-access-control-panel
|
||||
ng-if="volume && applicationState.application.authentication"
|
||||
|
|
|
@ -1,6 +1,43 @@
|
|||
angular.module('portainer.docker')
|
||||
.controller('VolumeController', ['$scope', '$state', '$transition$', 'VolumeService', 'ContainerService', 'Notifications', 'HttpRequestHelper',
|
||||
function ($scope, $state, $transition$, VolumeService, ContainerService, Notifications, HttpRequestHelper) {
|
||||
.controller('VolumeController', ['$scope', '$state', '$transition$', '$q', 'ModalService', 'VolumeService', 'ContainerService', 'Notifications', 'HttpRequestHelper', 'StoridgeVolumeService', 'StoridgeSnapshotService',
|
||||
function ($scope, $state, $transition$, $q, ModalService, VolumeService, ContainerService, Notifications, HttpRequestHelper, StoridgeVolumeService, StoridgeSnapshotService) {
|
||||
|
||||
$scope.storidgeSnapshots = [];
|
||||
$scope.storidgeVolume = {};
|
||||
|
||||
$scope.removeSnapshot = function (selectedItems) {
|
||||
ModalService.confirm({
|
||||
title: 'Are you sure?',
|
||||
message: 'Do you want really want to remove this snapshot?',
|
||||
buttons: {
|
||||
confirm: {
|
||||
label: 'Remove',
|
||||
className: 'btn-danger'
|
||||
}
|
||||
},
|
||||
callback: function onConfirm(confirmed) {
|
||||
if(!confirmed) { return; }
|
||||
var actionCount = selectedItems.length;
|
||||
angular.forEach(selectedItems, function (item) {
|
||||
StoridgeSnapshotService.remove(item.Id)
|
||||
.then(function success() {
|
||||
Notifications.success('Snapshot successfully removed', item.Id);
|
||||
var index = $scope.containerGroups.indexOf(item);
|
||||
$scope.storidgeSnapshots.splice(index, 1);
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove snapshot');
|
||||
})
|
||||
.finally(function final() {
|
||||
--actionCount;
|
||||
if (actionCount === 0) {
|
||||
$state.reload();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeVolume = function removeVolume() {
|
||||
VolumeService.remove($scope.volume)
|
||||
|
@ -21,19 +58,39 @@ function ($scope, $state, $transition$, VolumeService, ContainerService, Notific
|
|||
|
||||
function initView() {
|
||||
HttpRequestHelper.setPortainerAgentTargetHeader($transition$.params().nodeName);
|
||||
|
||||
VolumeService.volume($transition$.params().id)
|
||||
.then(function success(data) {
|
||||
var volume = data;
|
||||
$scope.volume = volume;
|
||||
var containerFilter = { volume: [volume.Id] };
|
||||
return ContainerService.containers(1, containerFilter);
|
||||
|
||||
$scope.isCioDriver = volume.Driver.includes('cio');
|
||||
if ($scope.isCioDriver) {
|
||||
return $q.all({
|
||||
containers: ContainerService.containers(1, containerFilter),
|
||||
storidgeVolume: StoridgeVolumeService.volume($transition$.params().id)
|
||||
});
|
||||
} else {
|
||||
return ContainerService.containers(1, containerFilter);
|
||||
}
|
||||
})
|
||||
.then(function success(data) {
|
||||
var containers = data.map(function(container) {
|
||||
var dataContainers = $scope.isCioDriver ? data.containers : data;
|
||||
|
||||
var containers = dataContainers.map(function(container) {
|
||||
container.volumeData = getVolumeDataFromContainer(container, $scope.volume.Id);
|
||||
return container;
|
||||
});
|
||||
$scope.containersUsingVolume = containers;
|
||||
|
||||
if ($scope.isCioDriver) {
|
||||
$scope.storidgeVolume = data.storidgeVolume;
|
||||
return StoridgeSnapshotService.snapshots(data.storidgeVolume.Vdisk);
|
||||
}
|
||||
})
|
||||
.then(function success(data) {
|
||||
$scope.storidgeSnapshots = data;
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve volume details');
|
||||
|
|
|
@ -54,6 +54,17 @@ angular.module('extension.storidge', [])
|
|||
}
|
||||
};
|
||||
|
||||
var snapshot = {
|
||||
name: 'docker.volumes.volume.snapshot',
|
||||
url: '/:snapshotId',
|
||||
views: {
|
||||
'content@': {
|
||||
templateUrl: 'app/extensions/storidge/views/snapshots/inspect/snapshot.html',
|
||||
controller: 'StoridgeSnapshotController'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var profileCreation = {
|
||||
name: 'storidge.profiles.new',
|
||||
url: '/new',
|
||||
|
@ -104,6 +115,7 @@ angular.module('extension.storidge', [])
|
|||
$stateRegistryProvider.register(storidge);
|
||||
$stateRegistryProvider.register(drives);
|
||||
$stateRegistryProvider.register(drive);
|
||||
$stateRegistryProvider.register(snapshot);
|
||||
$stateRegistryProvider.register(profiles);
|
||||
$stateRegistryProvider.register(profile);
|
||||
$stateRegistryProvider.register(profileCreation);
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
<div class="datatable">
|
||||
<rd-widget>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<div class="toolBar">
|
||||
<div class="toolBarTitle">
|
||||
<i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px;"></i> {{ $ctrl.titleText }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="actionBar">
|
||||
<button type="button" class="btn btn-sm btn-danger"
|
||||
ng-disabled="$ctrl.state.selectedItemCount === 0" ng-click="$ctrl.removeSnapshot($ctrl.state.selectedItems)">
|
||||
<i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Remove
|
||||
</button>
|
||||
</div>
|
||||
<div class="searchBar">
|
||||
<i class="fa fa-search searchIcon" aria-hidden="true"></i>
|
||||
<input type="text" class="searchInput" ng-model="$ctrl.state.textFilter" ng-change="$ctrl.onTextFilterChange()" placeholder="Search...">
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<span class="md-checkbox">
|
||||
<input id="select_all" type="checkbox" ng-model="$ctrl.state.selectAll" ng-change="$ctrl.selectAll()" />
|
||||
<label for="select_all"></label>
|
||||
</span>
|
||||
<a ng-click="$ctrl.changeOrderBy('Id')">
|
||||
Id
|
||||
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Id' && !$ctrl.state.reverseOrder"></i>
|
||||
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Id' && $ctrl.state.reverseOrder"></i>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a ng-click="$ctrl.changeOrderBy('Date')">
|
||||
Date
|
||||
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Date' && !$ctrl.state.reverseOrder"></i>
|
||||
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Date' && $ctrl.state.reverseOrder"></i>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a ng-click="$ctrl.changeOrderBy('Description')">
|
||||
Description
|
||||
<i class="fa fa-sort-alpha-down" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Description' && !$ctrl.state.reverseOrder"></i>
|
||||
<i class="fa fa-sort-alpha-up" aria-hidden="true" ng-if="$ctrl.state.orderBy === 'Description' && $ctrl.state.reverseOrder"></i>
|
||||
</a>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr dir-paginate="item in ($ctrl.state.filteredDataSet = ($ctrl.dataset | filter:$ctrl.state.textFilter | orderBy:$ctrl.state.orderBy:$ctrl.state.reverseOrder | itemsPerPage: $ctrl.state.paginatedItemLimit))" ng-class="{active: item.Checked}">
|
||||
<td>
|
||||
<span class="md-checkbox">
|
||||
<input id="select_{{ $index }}" type="checkbox" ng-model="item.Checked" ng-change="$ctrl.selectItem(item)" ng-disabled="item.Status === 'normal'"/>
|
||||
<label for="select_{{ $index }}"></label>
|
||||
</span>
|
||||
<!-- <a ui-sref="storidge.drives.drive({id: item.Id})"> {{ item.Id }}</a> -->
|
||||
</td>
|
||||
<td>{{ item.Date }}</td>
|
||||
<td>{{ item.Description }}</td>
|
||||
</tr>
|
||||
<tr ng-if="!$ctrl.dataset">
|
||||
<td colspan="7" class="text-center text-muted">Loading...</td>
|
||||
</tr>
|
||||
<tr ng-if="$ctrl.state.filteredDataSet.length === 0">
|
||||
<td colspan="3" class="text-center text-muted">No snapshots available.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="footer" ng-if="$ctrl.dataset">
|
||||
<div class="infoBar" ng-if="$ctrl.state.selectedItemCount !== 0">
|
||||
{{ $ctrl.state.selectedItemCount }} item(s) selected
|
||||
</div>
|
||||
<div class="paginationControls">
|
||||
<form class="form-inline">
|
||||
<span class="limitSelector">
|
||||
<span style="margin-right: 5px;">
|
||||
Items per page
|
||||
</span>
|
||||
<select class="form-control" ng-model="$ctrl.state.paginatedItemLimit" ng-change="$ctrl.changePaginationLimit()">
|
||||
<option value="0">All</option>
|
||||
<option value="10">10</option>
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
</span>
|
||||
<dir-pagination-controls max-size="5"></dir-pagination-controls>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
|
@ -0,0 +1,13 @@
|
|||
angular.module('extension.storidge').component('storidgeSnapshotsDatatable', {
|
||||
templateUrl: 'app/extensions/storidge/components/snapshots-datatable/storidgeSnapshotsDatatable.html',
|
||||
controller: 'StoridgeSnapshotsDatatableController',
|
||||
bindings: {
|
||||
titleText: '@',
|
||||
titleIcon: '@',
|
||||
dataset: '<',
|
||||
tableKey: '@',
|
||||
orderBy: '@',
|
||||
reverseOrder: '<',
|
||||
removeAction: '<'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
angular.module('portainer.docker')
|
||||
.controller('StoridgeSnapshotsDatatableController', ['$scope', '$controller',
|
||||
function ($scope, $controller) {
|
||||
angular.extend(this, $controller('GenericDatatableController', {$scope: $scope}));
|
||||
|
||||
}
|
||||
]);
|
|
@ -0,0 +1,174 @@
|
|||
<rd-widget>
|
||||
<rd-widget-header icon="fa-cube" title-text="Storidge details">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-click="$ctrl.updateVolume()" ng-if="!$ctrl.state.updateInProgress">
|
||||
<span>Update the volume</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary btn-sm" ng-click="$ctrl.confirmUpdate()" ng-if="$ctrl.state.updateInProgress" button-spinner="$ctrl.state.isUpdating">
|
||||
<span ng-hide="$ctrl.state.isUpdating">Confirm</span>
|
||||
<span ng-show="$ctrl.state.isUpdating">Updating the volume...</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger btn-sm" ng-click="$ctrl.cancelUpdate()" ng-if="$ctrl.state.updateInProgress" ng-disabled="$ctrl.state.isUpdating">
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</rd-widget-header>
|
||||
<rd-widget-body classes="no-padding" ng-if="!$ctrl.state.updateInProgress">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>{{ $ctrl.volume.Name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Uuid</td>
|
||||
<td>{{ $ctrl.volume.Uuid }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Node</td>
|
||||
<td>{{ $ctrl.volume.Node }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Node ID</td>
|
||||
<td>{{ $ctrl.volume.NodeID }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Directory</td>
|
||||
<td>{{ $ctrl.volume.Directory }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Capacity</td>
|
||||
<td>{{ $ctrl.volume.Capacity }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Allocated</td>
|
||||
<td>{{ $ctrl.volume.Allocated }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>IOPS Max</td>
|
||||
<td>{{ $ctrl.volume.IOPSMax }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>IOPS Min</td>
|
||||
<td>{{ $ctrl.volume.IOPSMin }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Local Drive Only</td>
|
||||
<td>{{ $ctrl.volume.LocalDriveOnly }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Provisioning</td>
|
||||
<td>{{ $ctrl.volume.Provisioning }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Redundancy</td>
|
||||
<td>{{ $ctrl.volume.Redundancy }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Type</td>
|
||||
<td>{{ $ctrl.volume.Type }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Vdisk</td>
|
||||
<td>{{ $ctrl.volume.Vdisk }}</td>
|
||||
</tr>
|
||||
<tr ng-if="$ctrl.volume.Labels">
|
||||
<td>Labels</td>
|
||||
<td>
|
||||
<table class="table table-bordered table-condensed">
|
||||
<tr ng-repeat="var in $ctrl.volume.Labels">
|
||||
<td>{{ var|key: '=' }}</td>
|
||||
<td>{{ var|value: '=' }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
<rd-widget-body ng-if="$ctrl.state.updateInProgress">
|
||||
<form class="form-horizontal" name="storidgeUpdateVolumeForm">
|
||||
<!-- Node -->
|
||||
<div class="form-group">
|
||||
<label for="volume_node" class="col-sm-2 col-lg-1 control-label text-left">Node</label>
|
||||
<div class="col-sm-10 col-lg-11">
|
||||
<input type="text" class="form-control" ng-model="$ctrl.formValues.Node" name="volume_node" placeholder="2">
|
||||
</div>
|
||||
</div>
|
||||
<!-- !Node -->
|
||||
<!-- Node ID -->
|
||||
<div class="form-group">
|
||||
<label for="volume_nodeid" class="col-sm-2 col-lg-1 control-label text-left">Node ID</label>
|
||||
<div class="col-sm-10 col-lg-11">
|
||||
<input type="text" class="form-control" ng-model="$ctrl.formValues.NodeID" name="volume_nodeid" placeholder="2">
|
||||
</div>
|
||||
</div>
|
||||
<!-- !Node ID -->
|
||||
<!-- Capacity -->
|
||||
<div class="form-group">
|
||||
<label for="volume_capacity" class="col-sm-2 col-lg-1 control-label text-left">Capacity</label>
|
||||
<div class="col-sm-10 col-lg-11">
|
||||
<input type="text" class="form-control" ng-model="$ctrl.formValues.Capacity" name="volume_capacity" placeholder="2">
|
||||
</div>
|
||||
</div>
|
||||
<!-- !Capacity -->
|
||||
<!-- IOPS -->
|
||||
<div class="form-group">
|
||||
<label for="min_iops" class="col-sm-2 col-lg-1 control-label text-left">Min IOPS</label>
|
||||
<div class="col-sm-10 col-lg-11">
|
||||
<input type="number" class="form-control" ng-model="$ctrl.formValues.IOPSMin" name="min_iops" placeholder="100">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="max_iops" class="col-sm-2 col-lg-1 control-label text-left">Max IOPS</label>
|
||||
<div class="col-sm-10 col-lg-11">
|
||||
<input type="number" class="form-control" ng-model="$ctrl.formValues.IOPSMax" name="max_iops" placeholder="2000">
|
||||
</div>
|
||||
</div>
|
||||
<!-- !IOPS -->
|
||||
<!-- Bandwidth -->
|
||||
<div class="form-group">
|
||||
<label for="min_bandwidth" class="col-sm-2 col-lg-1 control-label text-left">Min Bandwidth</label>
|
||||
<div class="col-sm-10 col-lg-11">
|
||||
<input type="number" class="form-control" ng-model="$ctrl.formValues.BandwidthMin" name="min_bandwidth" placeholder="100">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="max_bandwidth" class="col-sm-2 col-lg-1 control-label text-left">Max Bandwidth</label>
|
||||
<div class="col-sm-10 col-lg-11">
|
||||
<input type="number" class="form-control" ng-model="$ctrl.formValues.BandwidthMax" name="max_bandwidth" placeholder="2000">
|
||||
</div>
|
||||
</div>
|
||||
<!-- !Bandwidth -->
|
||||
<!-- labels -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12" style="margin-top: 5px;">
|
||||
<label class="control-label text-left">Labels</label>
|
||||
<span class="label label-default interactive" style="margin-left: 10px;" ng-click="$ctrl.addLabel()">
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i> add label
|
||||
</span>
|
||||
</div>
|
||||
<!-- labels-input-list -->
|
||||
<div class="col-sm-12 form-inline" style="margin-top: 10px;">
|
||||
<div ng-repeat="label in $ctrl.formValues.Labels" style="margin-top: 2px;">
|
||||
<div class="input-group col-sm-5 input-group-sm">
|
||||
<span class="input-group-addon">name</span>
|
||||
<input type="text" class="form-control" ng-model="label.name" placeholder="e.g. com.example.foo">
|
||||
</div>
|
||||
<div class="input-group col-sm-5 input-group-sm">
|
||||
<span class="input-group-addon">value</span>
|
||||
<input type="text" class="form-control" ng-model="label.value" placeholder="e.g. bar">
|
||||
</div>
|
||||
<button class="btn btn-sm btn-danger" type="button" ng-click="$ctrl.removeLabel($index)">
|
||||
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !labels-input-list -->
|
||||
</div>
|
||||
<!-- !labels -->
|
||||
</form>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
|
@ -0,0 +1,7 @@
|
|||
angular.module('portainer.docker').component('volumeStoridgeInfo', {
|
||||
templateUrl: 'app/extensions/storidge/components/volume-storidge-info/volumeStoridgeInfo.html',
|
||||
controller: 'VolumeStoridgeInfoController',
|
||||
bindings: {
|
||||
volume: '<'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,104 @@
|
|||
angular.module('portainer.docker')
|
||||
.controller('VolumeStoridgeInfoController', ['$state', 'StoridgeVolumeService', 'Notifications',
|
||||
function ($state, StoridgeVolumeService, Notifications) {
|
||||
var ctrl = this;
|
||||
|
||||
this.state = {
|
||||
updateInProgress: false,
|
||||
isUpdating: false
|
||||
};
|
||||
|
||||
this.addLabel = function() {
|
||||
this.formValues.Labels.push({ name: '', value: ''});
|
||||
};
|
||||
|
||||
this.removeLabel = function(index) {
|
||||
this.formValues.Labels.splice(index, 1);
|
||||
};
|
||||
|
||||
this.initLabels = function() {
|
||||
var labels = this.volume.Labels;
|
||||
this.formValues.Labels = Object.keys(labels).map(function(key) {
|
||||
return { name:key, value:labels[key] };
|
||||
});
|
||||
};
|
||||
|
||||
this.updateVolume = function() {
|
||||
this.state.updateInProgress = true;
|
||||
this.formValues = {
|
||||
IOPSMin: this.volume.IOPSMin,
|
||||
IOPSMax: this.volume.IOPSMax,
|
||||
Node: this.volume.Node,
|
||||
NodeID: this.volume.NodeID,
|
||||
Capacity: this.volume.Capacity,
|
||||
BandwidthMin: this.volume.BandwidthMin,
|
||||
BandwidthMax: this.volume.BandwidthMax,
|
||||
Labels: []
|
||||
};
|
||||
this.initLabels();
|
||||
};
|
||||
|
||||
this.cancelUpdate = function() {
|
||||
this.state.updateInProgress = false;
|
||||
this.formValues = {};
|
||||
};
|
||||
|
||||
this.prepareLabels = function(volume) {
|
||||
var labels = {};
|
||||
this.formValues.Labels.forEach(function (label) {
|
||||
if (label.name && label.value) {
|
||||
labels[label.name] = label.value;
|
||||
}
|
||||
});
|
||||
volume.Labels = labels;
|
||||
};
|
||||
|
||||
this.prepareVolume = function() {
|
||||
var volume = angular.copy(this.formValues);
|
||||
var data = this.volume;
|
||||
|
||||
if (volume.Node === data.Node || !volume.Node) {
|
||||
delete volume.Node;
|
||||
}
|
||||
if (volume.NodeID === data.NodeID || !volume.NodeID) {
|
||||
delete volume.NodeID;
|
||||
}
|
||||
if (volume.Capacity === data.Capacity || !volume.Capacity) {
|
||||
delete volume.Capacity;
|
||||
}
|
||||
if (volume.IOPSMin === data.IOPSMin || !volume.IOPSMin) {
|
||||
delete volume.IOPSMin;
|
||||
}
|
||||
if (volume.IOPSMax === data.IOPSMax || !volume.IOPSMax) {
|
||||
delete volume.IOPSMax;
|
||||
}
|
||||
if (volume.BandwidthMin === data.BandwidthMin || !volume.BandwidthMin) {
|
||||
delete volume.BandwidthMin;
|
||||
}
|
||||
if (volume.BandwidthMax === data.BandwidthMax || !volume.BandwidthMax) {
|
||||
delete volume.BandwidthMax;
|
||||
}
|
||||
return volume;
|
||||
};
|
||||
|
||||
this.confirmUpdate = function() {
|
||||
this.state.isUpdating = true;
|
||||
|
||||
var volume = this.prepareVolume();
|
||||
this.prepareLabels(volume);
|
||||
volume.Name = this.volume.Name;
|
||||
StoridgeVolumeService.update(volume)
|
||||
.then(function success() {
|
||||
Notifications.success('Volume successfully updated');
|
||||
$state.reload();
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to update volume');
|
||||
ctrl.state.isUpdating = false;
|
||||
});
|
||||
};
|
||||
|
||||
this.$onInit = function() {
|
||||
};
|
||||
|
||||
}]);
|
|
@ -0,0 +1,9 @@
|
|||
function StoridgeSnapshotModel(data) {
|
||||
this.Id = data.identifier;
|
||||
this.Date = data.date;
|
||||
this.Description = data.description;
|
||||
this.SourceID = data.sourceid;
|
||||
this.Type = data.type;
|
||||
this.Directory = data.directory;
|
||||
this.Source = data.source;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
function StoridgeVolumeModel(data) {
|
||||
this.Allocated = data['allocate%'];
|
||||
this.Capacity = data.capacity;
|
||||
this.Directory = data.directory;
|
||||
this.IOPSMax = data.iopsmax;
|
||||
this.IOPSMin = data.iopsmin;
|
||||
this.LocalDriveOnly = data.localdriveonly;
|
||||
this.Name = data.name;
|
||||
this.Node = data.node;
|
||||
this.NodeID = data.nodeid;
|
||||
this.Provisioning = data.provisioning;
|
||||
this.Redundancy = data.redundancy;
|
||||
this.Type = data.type;
|
||||
this.Uuid = data.uuid;
|
||||
this.Vdisk = data.vdisk;
|
||||
this.Labels = data.labels;
|
||||
|
||||
// this.IP = data.ipaddr;
|
||||
// this.Volume = data.volume;
|
||||
// this.DriveType = data.type;
|
||||
// this.Compression = data.compression;
|
||||
// this.Dedup = data.dedup;
|
||||
// this.Encryption = data.encryption;
|
||||
// this.Replication = data.replication;
|
||||
// this.Snapshot = data.snapshot;
|
||||
// this.SnapshotInterval = data.snap_interval;
|
||||
// this.SnapshotMax = data.snap_max;
|
||||
// this.Filesystem = data.filesystem;
|
||||
}
|
||||
|
||||
function StoridgeVolumeUpdateModel(data) {
|
||||
this.name = data.Name;
|
||||
this.opts = {
|
||||
node: data.Node,
|
||||
nodeid: data.NodeID,
|
||||
capacity: data.Capacity,
|
||||
iopsmin: data.IOPSMin,
|
||||
iopsmax: data.IOPSMax,
|
||||
bandwidthmin: data.BandwidthMin,
|
||||
bandwidthmax: data.BandwidthMax
|
||||
};
|
||||
this.labels = data.Labels;
|
||||
}
|
|
@ -23,9 +23,22 @@ angular.module('extension.storidge')
|
|||
createProfile: { method: 'POST', params: { resource: 'profiles' } },
|
||||
updateProfile: { method: 'PUT', params: { resource: 'profiles', id: '@name' } },
|
||||
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' } }
|
||||
removeDrive: { method: 'DELETE', params: { resource: 'drives', id: '@id' } },
|
||||
|
||||
queryVolumes: { method: 'GET', params: { resource: 'volumes' } },
|
||||
createVolume: { method: 'POST', params: { resource: 'volumes' } },
|
||||
getVolume: { method: 'GET', params: { resource: 'volumes', id: '@id' } },
|
||||
updateVolume: { method: 'POST', params: { resource: 'volumes', id: '@name' } },
|
||||
removeVolume: { method: 'DELETE', params: { resource: 'volumes' , id: '@id' } },
|
||||
|
||||
querySnapshots: { method: 'GET', params: { resource: 'volumes', id: '@id', action: 'snapshots' } },
|
||||
createSnapshot: { method: 'POST', params: { resource: 'volumes', id: '@id', action: 'snapshot' } },
|
||||
getSnapshot: { method: 'GET', params: { resource: 'snapshots', id: '@id' } },
|
||||
removeSnapshot: { method: 'DELETE', params: { resource: 'snapshots', id: '@id'} }
|
||||
|
||||
});
|
||||
}]);
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
angular.module('extension.storidge')
|
||||
.factory('StoridgeSnapshotService', ['$q', 'Storidge', function StoridgeSnapshotServiceFactory($q, Storidge) {
|
||||
'use strict';
|
||||
var service = {};
|
||||
|
||||
service.snapshots = snapshots;
|
||||
service.snapshot = snapshot;
|
||||
service.create = create;
|
||||
service.remove = remove;
|
||||
|
||||
function snapshots(volumeId) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
Storidge.querySnapshots({id: volumeId}).$promise
|
||||
.then(function success(data) {
|
||||
var snapshotsData = data.snapshots;
|
||||
var snapshots = snapshotsData.map(function (snapshot) {
|
||||
return new StoridgeSnapshotModel(snapshot);
|
||||
});
|
||||
deferred.resolve(snapshots);
|
||||
})
|
||||
.catch(function error(err) {
|
||||
deferred.reject({ msg: 'Unable to retrieve Storidge snapshots', err: err });
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function snapshot(id) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
Storidge.getSnapshot({id:id}).$promise
|
||||
.then(function success(data) {
|
||||
var snapshot = new StoridgeSnapshotModel(data.snapshot);
|
||||
deferred.resolve(snapshot);
|
||||
})
|
||||
.catch(function error(err) {
|
||||
deferred.reject({ msg: 'Unable to retrieve Storidge snapshot', err: err });
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function create(volumeId) {
|
||||
var deferred = $q.defer();
|
||||
Storidge.createSnapshot({id: volumeId}).$promise
|
||||
.then(function success(data) {
|
||||
deferred.resolve(data);
|
||||
})
|
||||
.catch(function error(err) {
|
||||
deferred.reject({ msg: 'Unable to create Storidge volume snapshot', err: err });
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function remove(id) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
Storidge.removeSnapshot({ id: id }).$promise
|
||||
.then(function success() {
|
||||
deferred.resolve();
|
||||
})
|
||||
.catch(function error(err) {
|
||||
deferred.reject({ msg: 'Unable to remove Storidge volume snapshot', err: err });
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
return service;
|
||||
}]);
|
|
@ -0,0 +1,36 @@
|
|||
angular.module('extension.storidge')
|
||||
.factory('StoridgeVolumeService', ['$q', 'Storidge', function StoridgeVolumeServiceFactory($q, Storidge) {
|
||||
'use strict';
|
||||
var service = {};
|
||||
|
||||
service.volume = function(id) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
Storidge.getVolume({id:id}).$promise
|
||||
.then(function success(data) {
|
||||
var volume = new StoridgeVolumeModel(data);
|
||||
deferred.resolve(volume);
|
||||
})
|
||||
.catch(function error(err) {
|
||||
deferred.reject({ msg: 'Unable to retrieve Storidge volume', err: err });
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
service.update = function(data) {
|
||||
var deferred = $q.defer();
|
||||
var volume = new StoridgeVolumeUpdateModel(data);
|
||||
Storidge.updateVolume(volume).$promise
|
||||
.then(function success(data) {
|
||||
deferred.resolve(data);
|
||||
})
|
||||
.catch(function error(err) {
|
||||
deferred.reject({ msg: 'Unable to update Storidge volume', err: err });
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
return service;
|
||||
}]);
|
|
@ -1,6 +1,6 @@
|
|||
angular.module('extension.storidge')
|
||||
.controller('StoridgeDriveController', ['$scope', '$state', '$transition$', 'Notifications', 'StoridgeDriveService',
|
||||
function ($scope, $state, $transition$, Notifications, StoridgeDriveService) {
|
||||
.controller('StoridgeDriveController', ['$scope', '$state', '$transition$', 'Notifications', 'ModalService', 'StoridgeDriveService',
|
||||
function ($scope, $state, $transition$, Notifications, ModalService, StoridgeDriveService) {
|
||||
|
||||
$scope.addDrive = function () {
|
||||
StoridgeDriveService.add($scope.drive.Device, $scope.drive.Node)
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
<rd-header>
|
||||
<rd-header-title title-text="Snasphot details"></rd-header-title>
|
||||
<rd-header-content>
|
||||
<a ui-sref="docker.volumes">Volumes</a> > <a ui-sref="docker.volumes.volume({id: volumeId})">{{ volumeId }}</a> > Snapshots > <a ui-sref="docker.volumes.volume.snapshot({id: snapshot.Id})">{{ snapshot.Id }}</a>
|
||||
</rd-header-content>
|
||||
</rd-header>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-xs-12">
|
||||
<rd-widget>
|
||||
<rd-widget-header icon="fa-hdd" title-text="Snapshot details "></rd-widget-header>
|
||||
<rd-widget-body classes="no-padding">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>ID</td>
|
||||
<td>
|
||||
{{ snapshot.Id }}
|
||||
<button class="btn btn-xs btn-danger" ng-click="removeSnapshot()">
|
||||
<i class="fa fa-trash space-right" aria-hidden="true"></i>Remove snapshot
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Date</td>
|
||||
<td>{{ snapshot.Date }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Description</td>
|
||||
<td>{{ snapshot.Description }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SourceID</td>
|
||||
<td>{{ snapshot.SourceID }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Type</td>
|
||||
<td>{{ snapshot.Type }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Directory</td>
|
||||
<td>{{ snapshot.Directory }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Source</td>
|
||||
<td>{{ snapshot.Source }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,44 @@
|
|||
angular.module('extension.storidge')
|
||||
.controller('StoridgeSnapshotController', ['$scope', '$state', '$transition$', 'Notifications', 'ModalService', 'StoridgeSnapshotService',
|
||||
function ($scope, $state, $transition$, Notifications, ModalService, StoridgeSnapshotService) {
|
||||
|
||||
$scope.removeSnapshot = function () {
|
||||
ModalService.confirm({
|
||||
title: 'Are you sure?',
|
||||
message: 'Do you want really want to remove this snapshot?',
|
||||
buttons: {
|
||||
confirm: {
|
||||
label: 'Remove',
|
||||
className: 'btn-danger'
|
||||
}
|
||||
},
|
||||
callback: function onConfirm(confirmed) {
|
||||
if(!confirmed) { return; }
|
||||
StoridgeSnapshotService.remove($scope.snapshot.Id)
|
||||
.then(function () {
|
||||
Notifications.success('Success', 'Snapshot removed');
|
||||
$state.go('portainer.volumes.volume', {id: $scope.volumeId});
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to remove snapshot');
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function initView() {
|
||||
$scope.volumeId = $transition$.params().id;
|
||||
$scope.snapshotId = $transition$.params().snapshotId;
|
||||
|
||||
StoridgeSnapshotService.snapshot($scope.snapshotId)
|
||||
.then(function success(data) {
|
||||
$scope.snapshot = data;
|
||||
})
|
||||
.catch(function error(err) {
|
||||
Notifications.error('Failure', err, 'Unable to retrieve snapshot details');
|
||||
});
|
||||
}
|
||||
|
||||
initView();
|
||||
|
||||
}]);
|
Loading…
Reference in New Issue