From 781dad3e17b9d60239220702730b3c45b81cb465 Mon Sep 17 00:00:00 2001 From: Anthony Lapenna Date: Mon, 13 Feb 2017 18:16:14 +1300 Subject: [PATCH] feat(templates): add the ability to update the volume configuration (#590) --- app/components/templates/templates.html | 151 ++++++++++++++---- .../templates/templatesController.js | 19 ++- app/helpers/templateHelper.js | 27 ++++ app/models/template.js | 11 +- app/services/templateService.js | 12 +- app/services/volumeService.js | 13 +- bower.json | 2 +- 7 files changed, 188 insertions(+), 47 deletions(-) diff --git a/app/components/templates/templates.html b/app/components/templates/templates.html index 04518aa89..0e2982a46 100644 --- a/app/components/templates/templates.html +++ b/app/components/templates/templates.html @@ -27,12 +27,12 @@
- -
+ +
- -
+ +
@@ -61,40 +61,125 @@
-
- -
- - map additional port - + +
+ +
+
+ + + map additional port + +
+
+ Portainer will automatically assign a port if you leave the host port empty. +
+ + +
+
+
+ +
+ host + +
+ + + + + +
+ container + +
+ + +
+
+ + +
+ +
+ +
+
+
+
- -
-
-
- host - -
-
- container - -
-
- - - - + + +
+
+ + + map additional volume + +
+
+ Portainer will automatically create and map a local volume when using the auto option. +
+
+
+ +
+ +
+ container + +
+ + +
+
+ + + +
+ +
+ +
+ + +
+ + +
+ volume + +
+ + +
+ host + +
+ + +
+
+ + +
+
+ +
+
- +
- +
diff --git a/app/components/templates/templatesController.js b/app/components/templates/templatesController.js index ca71e0ab9..015dc5198 100644 --- a/app/components/templates/templatesController.js +++ b/app/components/templates/templatesController.js @@ -1,6 +1,6 @@ angular.module('templates', []) -.controller('TemplatesController', ['$scope', '$q', '$state', '$anchorScroll', 'Config', 'ContainerService', 'ImageService', 'NetworkService', 'TemplateService', 'TemplateHelper', 'VolumeService', 'Messages', 'Pagination', -function ($scope, $q, $state, $anchorScroll, Config, ContainerService, ImageService, NetworkService, TemplateService, TemplateHelper, VolumeService, Messages, Pagination) { +.controller('TemplatesController', ['$scope', '$q', '$state', '$anchorScroll', 'Config', 'ContainerService', 'ContainerHelper', 'ImageService', 'NetworkService', 'TemplateService', 'TemplateHelper', 'VolumeService', 'Messages', 'Pagination', +function ($scope, $q, $state, $anchorScroll, Config, ContainerService, ContainerHelper, ImageService, NetworkService, TemplateService, TemplateHelper, VolumeService, Messages, Pagination) { $scope.state = { selectedTemplate: null, showAdvancedOptions: false, @@ -15,6 +15,14 @@ function ($scope, $q, $state, $anchorScroll, Config, ContainerService, ImageServ Pagination.setPaginationCount('templates', $scope.state.pagination_count); }; + $scope.addVolume = function () { + $scope.state.selectedTemplate.Volumes.push({ containerPath: '', name: '', readOnly: false, type: 'auto' }); + }; + + $scope.removeVolume = function(index) { + $scope.state.selectedTemplate.Volumes.splice(index, 1); + }; + $scope.addPortBinding = function() { $scope.state.selectedTemplate.Ports.push({ hostPort: '', containerPort: '', protocol: 'tcp' }); }; @@ -27,8 +35,9 @@ function ($scope, $q, $state, $anchorScroll, Config, ContainerService, ImageServ $('#createContainerSpinner').show(); var template = $scope.state.selectedTemplate; var templateConfiguration = createTemplateConfiguration(template); + var generatedVolumeCount = TemplateHelper.determineRequiredGeneratedVolumeCount(template.Volumes); - VolumeService.createAutoGeneratedLocalVolumes(template.Volumes) + VolumeService.createXAutoGeneratedLocalVolumes(generatedVolumeCount) .then(function success(data) { TemplateService.updateContainerConfigurationWithVolumes(templateConfiguration.container, template, data); return ImageService.pullImage(templateConfiguration.image); @@ -108,12 +117,14 @@ function ($scope, $q, $state, $anchorScroll, Config, ContainerService, ImageServ $q.all({ templates: TemplateService.getTemplates(), containers: ContainerService.getContainers(0, c.hiddenLabels), - networks: NetworkService.getNetworks() + networks: NetworkService.getNetworks(), + volumes: VolumeService.getVolumes() }) .then(function success(data) { $scope.templates = data.templates; $scope.runningContainers = data.containers; $scope.availableNetworks = filterNetworksBasedOnProvider(data.networks); + $scope.availableVolumes = data.volumes.Volumes; }) .catch(function error(err) { $scope.templates = []; diff --git a/app/helpers/templateHelper.js b/app/helpers/templateHelper.js index 39da37746..0df432495 100644 --- a/app/helpers/templateHelper.js +++ b/app/helpers/templateHelper.js @@ -66,5 +66,32 @@ angular.module('portainer.helpers') return env; }; + helper.createVolumeBindings = function(volumes, generatedVolumesPile) { + volumes.forEach(function (volume) { + if (volume.containerPath) { + var binding; + if (volume.type === 'auto') { + binding = generatedVolumesPile.pop().Name + ':' + volume.containerPath; + } else if (volume.type !== 'auto' && volume.name) { + binding = volume.name + ':' + volume.containerPath; + } + if (volume.readOnly) { + binding += ':ro'; + } + volume.binding = binding; + } + }); + }; + + helper.determineRequiredGeneratedVolumeCount = function(volumes) { + var count = 0; + volumes.forEach(function (volume) { + if (volume.type === 'auto') { + ++count; + } + }); + return count; + }; + return helper; }]); diff --git a/app/models/template.js b/app/models/template.js index 2849544d7..58c974bee 100644 --- a/app/models/template.js +++ b/app/models/template.js @@ -7,7 +7,16 @@ function TemplateViewModel(data) { this.Command = data.command ? data.command : ''; this.Network = data.network ? data.network : ''; this.Env = data.env ? data.env : []; - this.Volumes = data.volumes ? data.volumes : []; + this.Volumes = []; + if (data.volumes) { + this.Volumes = data.volumes.map(function (v) { + return { + readOnly: false, + containerPath: v, + type: 'auto' + }; + }); + } this.Ports = []; if (data.ports) { this.Ports = data.ports.map(function (p) { diff --git a/app/services/templateService.js b/app/services/templateService.js index c63ee8731..2c861c428 100644 --- a/app/services/templateService.js +++ b/app/services/templateService.js @@ -47,10 +47,14 @@ angular.module('portainer.services') return configuration; }; - service.updateContainerConfigurationWithVolumes = function(configuration, template, createdVolumes) { - createdVolumes.forEach(function (volume, idx) { - configuration.Volumes[template.Volumes[idx]] = {}; - configuration.HostConfig.Binds.push(volume.Name + ':' + template.Volumes[idx]); + service.updateContainerConfigurationWithVolumes = function(configuration, template, generatedVolumesPile) { + var volumes = template.Volumes; + TemplateHelper.createVolumeBindings(volumes, generatedVolumesPile); + volumes.forEach(function (volume) { + if (volume.binding) { + configuration.Volumes[volume.containerPath] = {}; + configuration.HostConfig.Binds.push(volume.binding); + } }); }; diff --git a/app/services/volumeService.js b/app/services/volumeService.js index ef3debd5b..d889ce493 100644 --- a/app/services/volumeService.js +++ b/app/services/volumeService.js @@ -3,6 +3,10 @@ angular.module('portainer.services') 'use strict'; var service = {}; + service.getVolumes = function() { + return Volume.query({}).$promise; + }; + function prepareVolumeQueries(template, containerConfig) { var volumeQueries = []; if (template.volumes) { @@ -48,10 +52,11 @@ angular.module('portainer.services') return $q.all(createVolumeQueries); }; - service.createAutoGeneratedLocalVolumes = function (volumes) { - var createVolumeQueries = volumes.map(function(volume) { - return service.createVolume({}); - }); + service.createXAutoGeneratedLocalVolumes = function (x) { + var createVolumeQueries = []; + for (var i = 0; i < x; i++) { + createVolumeQueries.push(service.createVolume({})); + } return $q.all(createVolumeQueries); }; diff --git a/bower.json b/bower.json index a75b42cef..c4f0adc85 100644 --- a/bower.json +++ b/bower.json @@ -26,7 +26,7 @@ "Chart.js": "1.0.2", "angular": "~1.5.0", "angular-cookies": "~1.5.0", - "angular-bootstrap": "~1.0.3", + "angular-bootstrap": "~2.5.0", "angular-ui-router": "^0.2.15", "angular-sanitize": "~1.5.0", "angular-mocks": "~1.5.0",