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 + + + +
+
+ + +
+ +
+ +
+ +
+
+ + +
+ +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + + add label + +
+ +
+
+
+ name + +
+
+ value + +
+ +
+
+ +
+ + +
+ Actions +
+
+
+ + Cancel + +
+
+ +
+
+
+
+
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 @@ +
    +
    +
    + Secrets will be available under /run/secrets/$SECRET_NAME in containers. +
    +
    +
    +
    + + + add a secret + +
    +
    +
    +
    + secret + +
    + +
    +
    +
    +
    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 + + +
    +
    + + + + +
    + + Add secret +
    +
    + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + Name + + + + + + Created at + + + +
    {{ secret.Name }}{{ secret.CreatedAt | getisodate }}
    Loading...
    No secrets available.
    +
    + +
    +
    +
    + +
    +
    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 @@ +
    + + + + +
    + Add a secret: + + + add secret + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    NameFile nameUIDGIDMode
    {{ 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; +}]);