diff --git a/app/app.js b/app/app.js
index 82fa21625..513743c75 100644
--- a/app/app.js
+++ b/app/app.js
@@ -28,6 +28,7 @@ angular.module('portainer', [
'containers',
'createContainer',
'createNetwork',
+ 'createSecret',
'createService',
'createVolume',
'docker',
@@ -42,6 +43,8 @@ angular.module('portainer', [
'network',
'networks',
'node',
+ 'secrets',
+ 'secret',
'service',
'services',
'settings',
@@ -249,6 +252,19 @@ angular.module('portainer', [
}
}
})
+ .state('actions.create.secret', {
+ url: '/secret',
+ views: {
+ 'content@': {
+ templateUrl: 'app/components/createSecret/createsecret.html',
+ controller: 'CreateSecretController'
+ },
+ 'sidebar@': {
+ templateUrl: 'app/components/sidebar/sidebar.html',
+ controller: 'SidebarController'
+ }
+ }
+ })
.state('actions.create.service', {
url: '/service',
views: {
@@ -414,6 +430,32 @@ angular.module('portainer', [
}
}
})
+ .state('secrets', {
+ url: '^/secrets/',
+ views: {
+ 'content@': {
+ templateUrl: 'app/components/secrets/secrets.html',
+ controller: 'SecretsController'
+ },
+ 'sidebar@': {
+ templateUrl: 'app/components/sidebar/sidebar.html',
+ controller: 'SidebarController'
+ }
+ }
+ })
+ .state('secret', {
+ url: '^/secret/:id/',
+ views: {
+ 'content@': {
+ templateUrl: 'app/components/secret/secret.html',
+ controller: 'SecretController'
+ },
+ 'sidebar@': {
+ templateUrl: 'app/components/sidebar/sidebar.html',
+ controller: 'SidebarController'
+ }
+ }
+ })
.state('services', {
url: '/services/',
views: {
diff --git a/app/components/createSecret/createSecretController.js b/app/components/createSecret/createSecretController.js
new file mode 100644
index 000000000..ca2fcdc79
--- /dev/null
+++ b/app/components/createSecret/createSecretController.js
@@ -0,0 +1,64 @@
+angular.module('createSecret', [])
+.controller('CreateSecretController', ['$scope', '$state', 'Notifications', 'SecretService',
+function ($scope, $state, Notifications, SecretService) {
+ $scope.formValues = {
+ Name: '',
+ Data: '',
+ Labels: [],
+ encodeSecret: true
+ };
+
+ $scope.addLabel = function() {
+ $scope.formValues.Labels.push({ name: '', value: ''});
+ };
+
+ $scope.removeLabel = function(index) {
+ $scope.formValues.Labels.splice(index, 1);
+ };
+
+ function prepareLabelsConfig(config) {
+ var labels = {};
+ $scope.formValues.Labels.forEach(function (label) {
+ if (label.name && label.value) {
+ labels[label.name] = label.value;
+ }
+ });
+ config.Labels = labels;
+ }
+
+ function prepareSecretData(config) {
+ if ($scope.formValues.encodeSecret) {
+ config.Data = btoa(unescape(encodeURIComponent($scope.formValues.Data)));
+ } else {
+ config.Data = $scope.formValues.Data;
+ }
+ }
+
+ function prepareConfiguration() {
+ var config = {};
+ config.Name = $scope.formValues.Name;
+ prepareSecretData(config);
+ prepareLabelsConfig(config);
+ return config;
+ }
+
+ function createSecret(config) {
+ $('#createSecretSpinner').show();
+ SecretService.create(config)
+ .then(function success(data) {
+ Notifications.success('Secret successfully created');
+ $state.go('secrets', {}, {reload: true});
+ })
+ .catch(function error(err) {
+ Notifications.error('Failure', err, 'Unable to create secret');
+ })
+ .finally(function final() {
+ $('#createSecretSpinner').hide();
+ });
+ }
+
+ $scope.create = function () {
+ var config = prepareConfiguration();
+ createSecret(config);
+ };
+}]);
diff --git a/app/components/createSecret/createsecret.html b/app/components/createSecret/createsecret.html
new file mode 100644
index 000000000..385bb3067
--- /dev/null
+++ b/app/components/createSecret/createsecret.html
@@ -0,0 +1,85 @@
+
+
+
+ Secrets > Add secret
+
+
+
+
diff --git a/app/components/createService/createServiceController.js b/app/components/createService/createServiceController.js
index 5ba874fb7..28812e93f 100644
--- a/app/components/createService/createServiceController.js
+++ b/app/components/createService/createServiceController.js
@@ -1,8 +1,8 @@
// @@OLD_SERVICE_CONTROLLER: this service should be rewritten to use services.
// See app/components/templates/templatesController.js as a reference.
angular.module('createService', [])
-.controller('CreateServiceController', ['$scope', '$state', 'Service', 'ServiceHelper', 'Volume', 'Network', 'ImageHelper', 'Authentication', 'ResourceControlService', 'Notifications', 'ControllerDataPipeline', 'FormValidator',
-function ($scope, $state, Service, ServiceHelper, Volume, Network, ImageHelper, Authentication, ResourceControlService, Notifications, ControllerDataPipeline, FormValidator) {
+.controller('CreateServiceController', ['$q', '$scope', '$state', 'Service', 'ServiceHelper', 'SecretHelper', 'SecretService', 'VolumeService', 'NetworkService', 'ImageHelper', 'Authentication', 'ResourceControlService', 'Notifications', 'ControllerDataPipeline', 'FormValidator',
+function ($q, $scope, $state, Service, ServiceHelper, SecretHelper, SecretService, VolumeService, NetworkService, ImageHelper, Authentication, ResourceControlService, Notifications, ControllerDataPipeline, FormValidator) {
$scope.formValues = {
Name: '',
@@ -24,7 +24,8 @@ function ($scope, $state, Service, ServiceHelper, Volume, Network, ImageHelper,
Parallelism: 1,
PlacementConstraints: [],
UpdateDelay: 0,
- FailureAction: 'pause'
+ FailureAction: 'pause',
+ Secrets: []
};
$scope.state = {
@@ -55,6 +56,14 @@ function ($scope, $state, Service, ServiceHelper, Volume, Network, ImageHelper,
$scope.formValues.Volumes.splice(index, 1);
};
+ $scope.addSecret = function() {
+ $scope.formValues.Secrets.push({});
+ };
+
+ $scope.removeSecret = function(index) {
+ $scope.formValues.Secrets.splice(index, 1);
+ };
+
$scope.addEnvironmentVariable = function() {
$scope.formValues.Env.push({ name: '', value: ''});
};
@@ -62,18 +71,23 @@ function ($scope, $state, Service, ServiceHelper, Volume, Network, ImageHelper,
$scope.removeEnvironmentVariable = function(index) {
$scope.formValues.Env.splice(index, 1);
};
+
$scope.addPlacementConstraint = function() {
$scope.formValues.PlacementConstraints.push({ key: '', operator: '==', value: '' });
};
+
$scope.removePlacementConstraint = function(index) {
$scope.formValues.PlacementConstraints.splice(index, 1);
};
+
$scope.addPlacementPreference = function() {
$scope.formValues.PlacementPreferences.push({ key: '', operator: '==', value: '' });
};
+
$scope.removePlacementPreference = function(index) {
$scope.formValues.PlacementPreferences.splice(index, 1);
};
+
$scope.addLabel = function() {
$scope.formValues.Labels.push({ name: '', value: ''});
};
@@ -203,6 +217,18 @@ function ($scope, $state, Service, ServiceHelper, Volume, Network, ImageHelper,
config.TaskTemplate.Placement.Constraints = ServiceHelper.translateKeyValueToPlacementConstraints(input.PlacementConstraints);
}
+ function prepareSecretConfig(config, input) {
+ if (input.Secrets) {
+ var secrets = [];
+ angular.forEach(input.Secrets, function(secret) {
+ if (secret.model) {
+ secrets.push(SecretHelper.secretConfig(secret.model));
+ }
+ });
+ config.TaskTemplate.ContainerSpec.Secrets = secrets;
+ }
+ }
+
function prepareConfiguration() {
var input = $scope.formValues;
var config = {
@@ -225,6 +251,7 @@ function ($scope, $state, Service, ServiceHelper, Volume, Network, ImageHelper,
prepareVolumes(config, input);
prepareNetworks(config, input);
prepareUpdateConfig(config, input);
+ prepareSecretConfig(config, input);
preparePlacementConfig(config, input);
return config;
}
@@ -277,20 +304,22 @@ function ($scope, $state, Service, ServiceHelper, Volume, Network, ImageHelper,
};
function initView() {
- Volume.query({}, function (d) {
- $scope.availableVolumes = d.Volumes;
- }, function (e) {
- Notifications.error('Failure', e, 'Unable to retrieve volumes');
- });
-
- Network.query({}, function (d) {
- $scope.availableNetworks = d.filter(function (network) {
- if (network.Scope === 'swarm') {
- return network;
- }
- });
- }, function (e) {
- Notifications.error('Failure', e, 'Unable to retrieve networks');
+ $('#loadingViewSpinner').show();
+ $q.all({
+ volumes: VolumeService.volumes(),
+ networks: NetworkService.retrieveSwarmNetworks(),
+ secrets: SecretService.secrets()
+ })
+ .then(function success(data) {
+ $scope.availableVolumes = data.volumes;
+ $scope.availableNetworks = data.networks;
+ $scope.availableSecrets = data.secrets;
+ })
+ .catch(function error(err) {
+ Notifications.error('Failure', err, 'Unable to initialize view');
+ })
+ .finally(function final() {
+ $('#loadingViewSpinner').hide();
});
}
diff --git a/app/components/createService/createservice.html b/app/components/createService/createservice.html
index 8dd1c637c..e6ecc79b2 100644
--- a/app/components/createService/createservice.html
+++ b/app/components/createService/createservice.html
@@ -1,5 +1,7 @@
-
+
+
+
Services > Add service
@@ -140,6 +142,7 @@
Network
Labels
Update config
+ Secrets
Placement
@@ -422,7 +425,9 @@
-
+
+
+
diff --git a/app/components/createService/includes/placement.html b/app/components/createService/includes/placement.html
index 1b4f8b7c2..f33c5ab88 100644
--- a/app/components/createService/includes/placement.html
+++ b/app/components/createService/includes/placement.html
@@ -2,7 +2,7 @@
-
+
placement constraint
diff --git a/app/components/createService/includes/secret.html b/app/components/createService/includes/secret.html
new file mode 100644
index 000000000..fdf95a01d
--- /dev/null
+++ b/app/components/createService/includes/secret.html
@@ -0,0 +1,28 @@
+
diff --git a/app/components/secret/secret.html b/app/components/secret/secret.html
new file mode 100644
index 000000000..8c9d10e18
--- /dev/null
+++ b/app/components/secret/secret.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+ Secrets > {{ secret.Name }}
+
+
+
+
+
+
+
+
+
+
+
+ Name |
+ {{ secret.Name }} |
+
+
+ ID |
+
+ {{ secret.Id }}
+
+ |
+
+
+ Created |
+ {{ secret.CreatedAt | getisodate }} |
+
+
+ Last updated |
+ {{ secret.UpdatedAt | getisodate }} |
+
+
+ Labels |
+
+
+
+ {{ k }} |
+ {{ v }} |
+
+
+ |
+
+
+
+
+
+
+
diff --git a/app/components/secret/secretController.js b/app/components/secret/secretController.js
new file mode 100644
index 000000000..48bfe970e
--- /dev/null
+++ b/app/components/secret/secretController.js
@@ -0,0 +1,35 @@
+angular.module('secret', [])
+.controller('SecretController', ['$scope', '$stateParams', '$state', 'SecretService', 'Notifications',
+function ($scope, $stateParams, $state, SecretService, Notifications) {
+
+ $scope.removeSecret = function removeSecret(secretId) {
+ $('#loadingViewSpinner').show();
+ SecretService.remove(secretId)
+ .then(function success(data) {
+ Notifications.success('Secret successfully removed');
+ $state.go('secrets', {});
+ })
+ .catch(function error(err) {
+ Notifications.error('Failure', err, 'Unable to remove secret');
+ })
+ .finally(function final() {
+ $('#loadingViewSpinner').hide();
+ });
+ };
+
+ function initView() {
+ $('#loadingViewSpinner').show();
+ SecretService.secret($stateParams.id)
+ .then(function success(data) {
+ $scope.secret = data;
+ })
+ .catch(function error(err) {
+ Notifications.error('Failure', err, 'Unable to retrieve secret details');
+ })
+ .finally(function final() {
+ $('#loadingViewSpinner').hide();
+ });
+ }
+
+ initView();
+}]);
diff --git a/app/components/secrets/secrets.html b/app/components/secrets/secrets.html
new file mode 100644
index 000000000..215ac1796
--- /dev/null
+++ b/app/components/secrets/secrets.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+ Secrets
+
+
+
diff --git a/app/components/secrets/secretsController.js b/app/components/secrets/secretsController.js
new file mode 100644
index 000000000..055aa07ee
--- /dev/null
+++ b/app/components/secrets/secretsController.js
@@ -0,0 +1,76 @@
+angular.module('secrets', [])
+.controller('SecretsController', ['$scope', '$stateParams', '$state', 'SecretService', 'Notifications', 'Pagination',
+function ($scope, $stateParams, $state, SecretService, Notifications, Pagination) {
+ $scope.state = {};
+ $scope.state.selectedItemCount = 0;
+ $scope.state.pagination_count = Pagination.getPaginationCount('secrets');
+ $scope.sortType = 'Name';
+ $scope.sortReverse = false;
+
+ $scope.order = function (sortType) {
+ $scope.sortReverse = ($scope.sortType === sortType) ? !$scope.sortReverse : false;
+ $scope.sortType = sortType;
+ };
+
+ $scope.selectItems = function (allSelected) {
+ angular.forEach($scope.state.filteredSecrets, function (secret) {
+ if (secret.Checked !== allSelected) {
+ secret.Checked = allSelected;
+ $scope.selectItem(secret);
+ }
+ });
+ };
+
+ $scope.selectItem = function (item) {
+ if (item.Checked) {
+ $scope.state.selectedItemCount++;
+ } else {
+ $scope.state.selectedItemCount--;
+ }
+ };
+
+ $scope.removeAction = function () {
+ $('#loadingViewSpinner').show();
+ var counter = 0;
+ var complete = function () {
+ counter = counter - 1;
+ if (counter === 0) {
+ $('#loadingViewSpinner').hide();
+ }
+ };
+ angular.forEach($scope.secrets, function (secret) {
+ if (secret.Checked) {
+ counter = counter + 1;
+ SecretService.remove(secret.Id)
+ .then(function success() {
+ Notifications.success('Secret deleted', secret.Id);
+ var index = $scope.secrets.indexOf(secret);
+ $scope.secrets.splice(index, 1);
+ })
+ .catch(function error(err) {
+ Notifications.error('Failure', err, 'Unable to remove secret');
+ })
+ .finally(function final() {
+ complete();
+ });
+ }
+ });
+ };
+
+ function initView() {
+ $('#loadingViewSpinner').show();
+ SecretService.secrets()
+ .then(function success(data) {
+ $scope.secrets = data;
+ })
+ .catch(function error(err) {
+ $scope.secrets = [];
+ Notifications.error('Failure', err, 'Unable to retrieve secrets');
+ })
+ .finally(function final() {
+ $('#loadingViewSpinner').hide();
+ });
+ }
+
+ initView();
+}]);
diff --git a/app/components/service/includes/secrets.html b/app/components/service/includes/secrets.html
new file mode 100644
index 000000000..2ca48e907
--- /dev/null
+++ b/app/components/service/includes/secrets.html
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+ Name |
+ File name |
+ UID |
+ GID |
+ Mode |
+ |
+
+
+
+
+ {{ secret.Name }} |
+ {{ secret.FileName }} |
+ {{ secret.Uid }} |
+ {{ secret.Gid }} |
+ {{ secret.Mode }} |
+
+
+ |
+
+
+ No secrets associated to this service. |
+
+
+
+
+
+
+
+
+
diff --git a/app/components/service/service.html b/app/components/service/service.html
index a49e9a44a..e66b4f0b0 100644
--- a/app/components/service/service.html
+++ b/app/components/service/service.html
@@ -109,6 +109,7 @@
Restart policy
Update configuration
Service labels
+
Secrets
Tasks
diff --git a/app/components/service/serviceController.js b/app/components/service/serviceController.js
index 20a283538..8cc6453e1 100644
--- a/app/components/service/serviceController.js
+++ b/app/components/service/serviceController.js
@@ -1,6 +1,6 @@
angular.module('service', [])
-.controller('ServiceController', ['$q', '$scope', '$stateParams', '$state', '$location', '$anchorScroll', 'ServiceService', 'Service', 'ServiceHelper', 'TaskService', 'NodeService', 'Notifications', 'Pagination', 'ModalService', 'ControllerDataPipeline',
-function ($q, $scope, $stateParams, $state, $location, $anchorScroll, ServiceService, Service, ServiceHelper, TaskService, NodeService, Notifications, Pagination, ModalService, ControllerDataPipeline) {
+.controller('ServiceController', ['$q', '$scope', '$stateParams', '$state', '$location', '$anchorScroll', 'ServiceService', 'Secret', 'SecretHelper', 'Service', 'ServiceHelper', 'TaskService', 'NodeService', 'Notifications', 'Pagination', 'ModalService', 'ControllerDataPipeline',
+function ($q, $scope, $stateParams, $state, $location, $anchorScroll, ServiceService, Secret, SecretHelper, Service, ServiceHelper, TaskService, NodeService, Notifications, Pagination, ModalService, ControllerDataPipeline) {
$scope.state = {};
$scope.state.pagination_count = Pagination.getPaginationCount('service_tasks');
@@ -55,6 +55,18 @@ function ($q, $scope, $stateParams, $state, $location, $anchorScroll, ServiceSer
updateServiceArray(service, 'EnvironmentVariables', service.EnvironmentVariables);
}
};
+ $scope.addSecret = function addSecret(service, secret) {
+ if (secret && service.ServiceSecrets.filter(function(serviceSecret) { return serviceSecret.Id === secret.Id;}).length === 0) {
+ service.ServiceSecrets.push({ Id: secret.Id, Name: secret.Name, FileName: secret.Name, Uid: '0', Gid: '0', Mode: 444 });
+ updateServiceArray(service, 'ServiceSecrets', service.ServiceSecrets);
+ }
+ };
+ $scope.removeSecret = function removeSecret(service, index) {
+ var removedElement = service.ServiceSecrets.splice(index, 1);
+ if (removedElement !== null) {
+ updateServiceArray(service, 'ServiceSecrets', service.ServiceSecrets);
+ }
+ };
$scope.addLabel = function addLabel(service) {
service.ServiceLabels.push({ key: '', value: '', originalValue: '' });
updateServiceArray(service, 'ServiceLabels', service.ServiceLabels);
@@ -162,7 +174,7 @@ function ($q, $scope, $stateParams, $state, $location, $anchorScroll, ServiceSer
config.TaskTemplate.ContainerSpec.Env = translateEnvironmentVariablesToEnv(service.EnvironmentVariables);
config.TaskTemplate.ContainerSpec.Labels = translateServiceLabelsToLabels(service.ServiceContainerLabels);
config.TaskTemplate.ContainerSpec.Image = service.Image;
- config.TaskTemplate.ContainerSpec.Secrets = service.ServiceSecrets;
+ config.TaskTemplate.ContainerSpec.Secrets = service.ServiceSecrets ? service.ServiceSecrets.map(SecretHelper.secretConfig) : [];
if (service.Mode === 'replicated') {
config.Mode.Replicated.Replicas = service.Replicas;
@@ -246,7 +258,7 @@ function ($q, $scope, $stateParams, $state, $location, $anchorScroll, ServiceSer
}
function translateServiceArrays(service) {
- service.ServiceSecrets = service.Secrets;
+ service.ServiceSecrets = service.Secrets ? service.Secrets.map(SecretHelper.flattenSecret) : [];
service.EnvironmentVariables = translateEnvironmentVariables(service.Env);
service.ServiceLabels = translateLabelsToServiceLabels(service.Labels);
service.ServiceContainerLabels = translateLabelsToServiceLabels(service.ContainerLabels);
@@ -272,14 +284,19 @@ function ($q, $scope, $stateParams, $state, $location, $anchorScroll, ServiceSer
return $q.all({
tasks: TaskService.serviceTasks(service.Name),
- nodes: NodeService.nodes()
+ nodes: NodeService.nodes(),
+ secrets: Secret.query({}).$promise
});
})
.then(function success(data) {
$scope.tasks = data.tasks;
$scope.nodes = data.nodes;
+ $scope.secrets = data.secrets.map(function (secret) {
+ return new SecretViewModel(secret);
+ });
})
.catch(function error(err) {
+ $scope.secrets = [];
Notifications.error('Failure', err, 'Unable to retrieve service details');
})
.finally(function final() {
@@ -287,6 +304,20 @@ function ($q, $scope, $stateParams, $state, $location, $anchorScroll, ServiceSer
});
}
+ function fetchSecrets() {
+ $('#loadSecretsSpinner').show();
+ Secret.query({}, function (d) {
+ $scope.secrets = d.map(function (secret) {
+ return new SecretViewModel(secret);
+ });
+ $('#loadSecretsSpinner').hide();
+ }, function(e) {
+ $('#loadSecretsSpinner').hide();
+ Notifications.error('Failure', e, 'Unable to retrieve secrets');
+ $scope.secrets = [];
+ });
+ }
+
$scope.updateServiceAttribute = function updateServiceAttribute(service, name) {
if (service[name] !== originalService[name] || !(name in originalService)) {
service.hasChanges = true;
diff --git a/app/components/sidebar/sidebar.html b/app/components/sidebar/sidebar.html
index 9a30b6b38..fdad3cc53 100644
--- a/app/components/sidebar/sidebar.html
+++ b/app/components/sidebar/sidebar.html
@@ -28,6 +28,9 @@
+
diff --git a/app/components/templates/templatesController.js b/app/components/templates/templatesController.js
index 5ead966ac..f4434058a 100644
--- a/app/components/templates/templatesController.js
+++ b/app/components/templates/templatesController.js
@@ -163,7 +163,7 @@ function ($scope, $q, $state, $stateParams, $anchorScroll, $filter, Config, Cont
$q.all({
templates: TemplateService.getTemplates(templatesKey),
containers: ContainerService.getContainers(0, c.hiddenLabels),
- networks: NetworkService.getNetworks(),
+ networks: NetworkService.networks(),
volumes: VolumeService.getVolumes()
})
.then(function success(data) {
diff --git a/app/helpers/secretHelper.js b/app/helpers/secretHelper.js
new file mode 100644
index 000000000..ff84aaef5
--- /dev/null
+++ b/app/helpers/secretHelper.js
@@ -0,0 +1,34 @@
+angular.module('portainer.helpers')
+.factory('SecretHelper', [function SecretHelperFactory() {
+ 'use strict';
+ return {
+ flattenSecret: function(secret) {
+ if (secret) {
+ return {
+ Id: secret.SecretID,
+ Name: secret.SecretName,
+ FileName: secret.File.Name,
+ Uid: secret.File.UID,
+ Gid: secret.File.GID,
+ Mode: secret.File.Mode
+ };
+ }
+ return {};
+ },
+ secretConfig: function(secret) {
+ if (secret) {
+ return {
+ SecretID: secret.Id,
+ SecretName: secret.Name,
+ File: {
+ Name: secret.Name,
+ UID: '0',
+ GID: '0',
+ Mode: 444
+ }
+ };
+ }
+ return {};
+ }
+ };
+}]);
diff --git a/app/models/docker/secret.js b/app/models/docker/secret.js
new file mode 100644
index 000000000..112419791
--- /dev/null
+++ b/app/models/docker/secret.js
@@ -0,0 +1,8 @@
+function SecretViewModel(data) {
+ this.Id = data.ID;
+ this.CreatedAt = data.CreatedAt;
+ this.UpdatedAt = data.UpdatedAt;
+ this.Version = data.Version.Index;
+ this.Name = data.Spec.Name;
+ this.Labels = data.Spec.Labels;
+}
diff --git a/app/rest/secret.js b/app/rest/secret.js
new file mode 100644
index 000000000..2cd06a759
--- /dev/null
+++ b/app/rest/secret.js
@@ -0,0 +1,12 @@
+angular.module('portainer.rest')
+.factory('Secret', ['$resource', 'Settings', 'EndpointProvider', function SecretFactory($resource, Settings, EndpointProvider) {
+ 'use strict';
+ return $resource(Settings.url + '/:endpointId/secrets/:id/:action', {
+ endpointId: EndpointProvider.endpointID
+ }, {
+ get: { method: 'GET', params: {id: '@id'} },
+ query: { method: 'GET', isArray: true },
+ create: { method: 'POST', params: {action: 'create'} },
+ remove: { method: 'DELETE', params: {id: '@id'} }
+ });
+}]);
diff --git a/app/services/networkService.js b/app/services/networkService.js
index e3abe33e7..b3bfc236a 100644
--- a/app/services/networkService.js
+++ b/app/services/networkService.js
@@ -3,10 +3,29 @@ angular.module('portainer.services')
'use strict';
var service = {};
- service.getNetworks = function() {
+ service.networks = function() {
return Network.query({}).$promise;
};
+ service.retrieveSwarmNetworks = function() {
+ var deferred = $q.defer();
+
+ service.networks()
+ .then(function success(data) {
+ var networks = data.filter(function (network) {
+ if (network.Scope === 'swarm') {
+ return network;
+ }
+ });
+ deferred.resolve(networks);
+ })
+ .catch(function error(err) {
+ deferred.reject({msg: 'Unable to retrieve networks', err: err});
+ });
+
+ return deferred.promise;
+ };
+
service.filterGlobalNetworks = function(networks) {
return networks.filter(function (network) {
if (network.Scope === 'global') {
diff --git a/app/services/secretService.js b/app/services/secretService.js
new file mode 100644
index 000000000..b15fdbcbc
--- /dev/null
+++ b/app/services/secretService.js
@@ -0,0 +1,47 @@
+angular.module('portainer.services')
+.factory('SecretService', ['$q', 'Secret', function SecretServiceFactory($q, Secret) {
+ 'use strict';
+ var service = {};
+
+ service.secret = function(secretId) {
+ var deferred = $q.defer();
+
+ Secret.get({id: secretId}).$promise
+ .then(function success(data) {
+ var secret = new SecretViewModel(data);
+ deferred.resolve(secret);
+ })
+ .catch(function error(err) {
+ deferred.reject({ msg: 'Unable to retrieve secret details', err: err });
+ });
+
+ return deferred.promise;
+ };
+
+ service.secrets = function() {
+ var deferred = $q.defer();
+
+ Secret.query({}).$promise
+ .then(function success(data) {
+ var secrets = data.map(function (item) {
+ return new SecretViewModel(item);
+ });
+ deferred.resolve(secrets);
+ })
+ .catch(function error(err) {
+ deferred.reject({ msg: 'Unable to retrieve secrets', err: err });
+ });
+
+ return deferred.promise;
+ };
+
+ service.remove = function(secretId) {
+ return Secret.remove({ id: secretId }).$promise;
+ };
+
+ service.create = function(secretConfig) {
+ return Secret.create(secretConfig).$promise;
+ };
+
+ return service;
+}]);