diff --git a/app/app.js b/app/app.js index 531cf4515..7596fece0 100644 --- a/app/app.js +++ b/app/app.js @@ -12,7 +12,7 @@ angular.module('dockerui', ['dockerui.templates', 'ngRoute', 'dockerui.services' }]) // This is your docker url that the api will use to make requests // You need to set this to the api endpoint without the port i.e. http://192.168.1.9 - .constant('DOCKER_ENDPOINT', '/dockerapi') + .constant('DOCKER_ENDPOINT', 'dockerapi') .constant('DOCKER_PORT', '') // Docker port, leave as an empty string if no port is requred. If you have a port, prefix it with a ':' i.e. :4243 .constant('UI_VERSION', 'v0.6.0') .constant('DOCKER_API_VERSION', 'v1.16'); diff --git a/app/components/startContainer/startContainerController.js b/app/components/startContainer/startContainerController.js index 23837f41d..d0bee1909 100644 --- a/app/components/startContainer/startContainerController.js +++ b/app/components/startContainer/startContainerController.js @@ -1,4 +1,4 @@ -angular.module('startContainer', []) +angular.module('startContainer', ['ui.bootstrap']) .controller('StartContainerController', ['$scope', '$routeParams', '$location', 'Container', 'Messages', 'containernameFilter', function($scope, $routeParams, $location, Container, Messages, containernameFilter) { $scope.template = 'app/components/startContainer/startcontainer.html'; @@ -10,81 +10,94 @@ function($scope, $routeParams, $location, Container, Messages, containernameFilt }); $scope.config = { - name: '', - memory: 0, - memorySwap: 0, - cpuShares: 1024, - env: [], - commands: '', - volumesFrom: [], - portBindings: [] + Env: [], + Volumes: [], + SecurityOpts: [], + PortBindings: [], + HostConfig: { + Binds: [], + Links: [], + Dns: [], + DnsSearch: [], + VolumesFrom: [], + CapAdd: [], + CapDrop: [] + } }; - $scope.commandPlaceholder = '["/bin/echo", "Hello world"]'; function failedRequestHandler(e, Messages) { Messages.send({class: 'text-error', data: e.data}); } - $scope.create = function() { - var cmds = null; - if ($scope.config.commands !== '') { - cmds = angular.fromJson($scope.config.commands); + function rmEmptyKeys(col) { + for (var key in col) { + if (col[key] === null || col[key] === undefined || col[key] === '' || $.isEmptyObject(col[key]) || col[key].length === 0) { + delete col[key]; + } } - var id = $routeParams.id; - var ctor = Container; - var loc = $location; - var s = $scope; + } - var volumesFrom = $scope.config.volumesFrom.map(function(volume) { - return volume.name; - }); + function getNames(arr) { + return arr.map(function(item) {return item.name;}); + } - var env = $scope.config.env.map(function(envar) { - return envar.name + '=' + envar.value; - }); + $scope.create = function() { + // Copy the config before transforming fields to the remote API format + var config = angular.copy($scope.config); - var exposedPorts = {}; - var portBindings = {}; + config.Image = $routeParams.id; + + if (config.Cmd && config.Cmd[0] === "[") { + config.Cmd = angular.fromJson(config.Cmd); + } + + config.Env = config.Env.map(function(envar) {return envar.name + '=' + envar.value;}); + + config.Volumes = getNames(config.Volumes); + config.SecurityOpts = getNames(config.SecurityOpts); + + config.HostConfig.VolumesFrom = getNames(config.HostConfig.VolumesFrom); + config.HostConfig.Binds = getNames(config.HostConfig.Binds); + config.HostConfig.Links = getNames(config.HostConfig.Links); + config.HostConfig.Dns = getNames(config.HostConfig.Dns); + config.HostConfig.DnsSearch = getNames(config.HostConfig.DnsSearch); + config.HostConfig.CapAdd = getNames(config.HostConfig.CapAdd); + config.HostConfig.CapDrop = getNames(config.HostConfig.CapDrop); + + var ExposedPorts = {}; + var PortBindings = {}; // TODO: consider using compatibility library - $scope.config.portBindings.forEach(function(portBinding) { + config.PortBindings.forEach(function(portBinding) { var intPort = portBinding.intPort + "/tcp"; var binding = { HostIp: portBinding.ip, HostPort: portBinding.extPort }; if (portBinding.intPort) { - exposedPorts[intPort] = {}; - if (intPort in portBindings) { - portBindings[intPort].push(binding); + ExposedPorts[intPort] = {}; + if (intPort in PortBindings) { + PortBindings[intPort].push(binding); } else { - portBindings[intPort] = [binding]; + PortBindings[intPort] = [binding]; } } else { // TODO: Send warning message? Internal port need to be specified. } }); + config.ExposedPorts = ExposedPorts; + delete config.PortBindings; + config.HostConfig.PortBindings = PortBindings; - Container.create({ - Image: id, - name: $scope.config.name, - Memory: $scope.config.memory, - MemorySwap: $scope.config.memorySwap, - CpuShares: $scope.config.cpuShares, - Cmd: cmds, - VolumesFrom: volumesFrom, - Env: env, - ExposedPorts: exposedPorts, - HostConfig: { - PortBindings: portBindings - } - }, function(d) { + // Remove empty fields from the request to avoid overriding defaults + rmEmptyKeys(config.HostConfig); + rmEmptyKeys(config); + + var ctor = Container; + var loc = $location; + var s = $scope; + Container.create(config, function(d) { if (d.Id) { - ctor.start({ - id: d.Id, - HostConfig: { - PortBindings: portBindings - } - }, function(cd) { + ctor.start({id: d.Id}, function(cd) { $('#create-modal').modal('hide'); loc.path('/containers/' + d.Id + '/'); }, function(e) { @@ -99,29 +112,39 @@ function($scope, $routeParams, $location, Container, Messages, containernameFilt }; $scope.addPortBinding = function() { - $scope.config.portBindings.push({ip: '', extPort: '', intPort: ''}); + $scope.config.PortBindings.push({ip: '', extPort: '', intPort: ''}); }; $scope.removePortBinding = function(portBinding) { - var idx = $scope.config.portBindings.indexOf(portBinding); - $scope.config.portBindings.splice(idx, 1); + var idx = $scope.config.PortBindings.indexOf(portBinding); + $scope.config.PortBindings.splice(idx, 1); }; + // TODO: refactor out $scope.addEnv = function() { - $scope.config.env.push({name: '', value: ''}); + $scope.config.Env.push({name: '', value: ''}); }; $scope.removeEnv = function(envar) { var idx = $scope.config.env.indexOf(envar); - $scope.config.env.splice(idx, 1); + $scope.config.Env.splice(idx, 1); }; - $scope.addVolume = function() { - $scope.config.volumesFrom.push({name: ''}); + // Todo: refactor out + $scope.addVolumeFrom = function() { + $scope.config.HostConfig.volumesFrom.push({name: ''}); }; - $scope.removeVolume = function(volume) { - var idx = $scope.config.volumesFrom.indexOf(volume); - $scope.config.volumesFrom.splice(idx, 1); + $scope.removeVolumeFrom = function(volume) { + var idx = $scope.config.HostConfig.volumesFrom.indexOf(volume); + $scope.config.HostConfig.volumesFrom.splice(idx, 1); + }; + + $scope.addEntry = function(array, entry) { + array.push(entry); + }; + $scope.rmEntry = function(array, entry) { + var idx = array.indexOf(entry); + array.splice(idx, 1); }; }]); diff --git a/app/components/startContainer/startContainerController.spec.js b/app/components/startContainer/startContainerController.spec.js index acdfb9123..50fe21035 100644 --- a/app/components/startContainer/startContainerController.spec.js +++ b/app/components/startContainer/startContainerController.spec.js @@ -18,19 +18,28 @@ describe('startContainerController', function() { $httpBackend = _$httpBackend_; }); })); - + function expectGetContainers() { + $httpBackend.expectGET('dockerapi/containers/json?all=1').respond([{ + "Command": "./dockerui -e /docker.sock", + "Created": 1421817232, + "Id": "b17882378cee8ec0136f482681b764cca430befd52a9bfd1bde031f49b8bba9f", + "Image": "dockerui:latest", + "Names": ["/dockerui"], + "Ports": [{ + "IP": "0.0.0.0", + "PrivatePort": 9000, + "PublicPort": 9000, + "Type": "tcp" + }], + "Status": "Up 2 minutes" + }]); + } describe('Create and start a container with port bindings', function() { it('should issue a correct create request to the Docker remote API', function() { var controller = createController(); var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c'; var expectedBody = { "name": "container-name", - "Memory": 0, - "MemorySwap": 0, - "CpuShares": 1024, - "Cmd": null, - "VolumesFrom": [], - "Env": [], "ExposedPorts": { "9000/tcp": {}, }, @@ -44,32 +53,19 @@ describe('startContainerController', function() { } }; - $httpBackend.expectGET('/dockerapi/containers/json?all=1').respond([{ - "Command": "./dockerui -e /docker.sock", - "Created": 1421817232, - "Id": "b17882378cee8ec0136f482681b764cca430befd52a9bfd1bde031f49b8bba9f", - "Image": "dockerui:latest", - "Names": ["/dockerui"], - "Ports": [{ - "IP": "0.0.0.0", - "PrivatePort": 9000, - "PublicPort": 9000, - "Type": "tcp" - }], - "Status": "Up 2 minutes" - }]); + expectGetContainers(); - $httpBackend.expectPOST('/dockerapi/containers/create?name=container-name', expectedBody).respond({ + $httpBackend.expectPOST('dockerapi/containers/create?name=container-name', expectedBody).respond({ "Id": id, "Warnings": null }); - $httpBackend.expectPOST('/dockerapi/containers/' + id + '/start?').respond({ + $httpBackend.expectPOST('dockerapi/containers/' + id + '/start?').respond({ "Id": id, "Warnings": null }); scope.config.name = 'container-name'; - scope.config.portBindings = [{ + scope.config.PortBindings = [{ ip: '10.20.10.15', extPort: '9999', intPort: '9000' @@ -86,44 +82,22 @@ describe('startContainerController', function() { var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c'; var expectedBody = { "name": "container-name", - "Memory": 0, - "MemorySwap": 0, - "CpuShares": 1024, - "Cmd": null, - "VolumesFrom": [], - "Env": ["SHELL=/bin/bash", "TERM=xterm-256color"], - "ExposedPorts": {}, - "HostConfig": { - "PortBindings": {} - } + "Env": ["SHELL=/bin/bash", "TERM=xterm-256color"] }; - $httpBackend.expectGET('/dockerapi/containers/json?all=1').respond([{ - "Command": "./dockerui -e /docker.sock", - "Created": 1421817232, - "Id": "b17882378cee8ec0136f482681b764cca430befd52a9bfd1bde031f49b8bba9f", - "Image": "dockerui:latest", - "Names": ["/dockerui"], - "Ports": [{ - "IP": "0.0.0.0", - "PrivatePort": 9000, - "PublicPort": 9000, - "Type": "tcp" - }], - "Status": "Up 2 minutes" - }]); + expectGetContainers(); - $httpBackend.expectPOST('/dockerapi/containers/create?name=container-name', expectedBody).respond({ + $httpBackend.expectPOST('dockerapi/containers/create?name=container-name', expectedBody).respond({ "Id": id, "Warnings": null }); - $httpBackend.expectPOST('/dockerapi/containers/' + id + '/start?').respond({ + $httpBackend.expectPOST('dockerapi/containers/' + id + '/start?').respond({ "Id": id, "Warnings": null }); scope.config.name = 'container-name'; - scope.config.env = [{ + scope.config.Env = [{ name: 'SHELL', value: '/bin/bash' }, { @@ -141,45 +115,26 @@ describe('startContainerController', function() { var controller = createController(); var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c'; var expectedBody = { - "name": "container-name", - "Memory": 0, - "MemorySwap": 0, - "CpuShares": 1024, - "Cmd": null, - "VolumesFrom": ["parent", "other:ro"], - "Env": [], - "ExposedPorts": {}, - "HostConfig": { - "PortBindings": {} - } + HostConfig: { + "VolumesFrom": ["parent", "other:ro"] + }, + "name": "container-name" }; - $httpBackend.expectGET('/dockerapi/containers/json?all=1').respond([{ - "Command": "./dockerui -e /docker.sock", - "Created": 1421817232, - "Id": "b17882378cee8ec0136f482681b764cca430befd52a9bfd1bde031f49b8bba9f", - "Image": "dockerui:latest", - "Names": ["/dockerui"], - "Ports": [{ - "IP": "0.0.0.0", - "PrivatePort": 9000, - "PublicPort": 9000, - "Type": "tcp" - }], - "Status": "Up 2 minutes" - }]); + expectGetContainers(); - $httpBackend.expectPOST('/dockerapi/containers/create?name=container-name', expectedBody).respond({ + + $httpBackend.expectPOST('dockerapi/containers/create?name=container-name', expectedBody).respond({ "Id": id, "Warnings": null }); - $httpBackend.expectPOST('/dockerapi/containers/' + id + '/start?').respond({ + $httpBackend.expectPOST('dockerapi/containers/' + id + '/start?').respond({ "Id": id, "Warnings": null }); scope.config.name = 'container-name'; - scope.config.volumesFrom = [{name: "parent"}, {name:"other:ro"}]; + scope.config.HostConfig.VolumesFrom = [{name: "parent"}, {name:"other:ro"}]; scope.create(); $httpBackend.flush(); diff --git a/app/components/startContainer/startcontainer.html b/app/components/startContainer/startcontainer.html index 8429bd6c5..3599698f4 100644 --- a/app/components/startContainer/startcontainer.html +++ b/app/components/startContainer/startcontainer.html @@ -6,40 +6,106 @@