Cleaned up controller methods, Added placeholders, fixed PortBindings and error messages.

pull/2/head
Kevan Ahlquist 2015-01-25 17:59:08 -06:00
parent 4682ae4ca7
commit f75d298fe1
6 changed files with 135 additions and 88 deletions

View File

@ -1,6 +1,6 @@
angular.module('startContainer', ['ui.bootstrap'])
.controller('StartContainerController', ['$scope', '$routeParams', '$location', 'Container', 'Messages', 'containernameFilter',
function($scope, $routeParams, $location, Container, Messages, containernameFilter) {
.controller('StartContainerController', ['$scope', '$routeParams', '$location', 'Container', 'Messages', 'containernameFilter', 'errorMsgFilter',
function($scope, $routeParams, $location, Container, Messages, containernameFilter, errorMsgFilter) {
$scope.template = 'app/components/startContainer/startcontainer.html';
Container.query({all: 1}, function(d) {
@ -13,8 +13,8 @@ function($scope, $routeParams, $location, Container, Messages, containernameFilt
Env: [],
Volumes: [],
SecurityOpts: [],
PortBindings: [],
HostConfig: {
PortBindings: [],
Binds: [],
Links: [],
Dns: [],
@ -25,8 +25,13 @@ function($scope, $routeParams, $location, Container, Messages, containernameFilt
}
};
$scope.menuStatus = {
containerOpen: true,
hostConfigOpen: false
};
function failedRequestHandler(e, Messages) {
Messages.send({class: 'text-error', data: e.data});
Messages.error('Error', errorMsgFilter(e));
}
function rmEmptyKeys(col) {
@ -67,7 +72,7 @@ function($scope, $routeParams, $location, Container, Messages, containernameFilt
var ExposedPorts = {};
var PortBindings = {};
// TODO: consider using compatibility library
config.PortBindings.forEach(function(portBinding) {
config.HostConfig.PortBindings.forEach(function(portBinding) {
var intPort = portBinding.intPort + "/tcp";
var binding = {
HostIp: portBinding.ip,
@ -85,7 +90,6 @@ function($scope, $routeParams, $location, Container, Messages, containernameFilt
}
});
config.ExposedPorts = ExposedPorts;
delete config.PortBindings;
config.HostConfig.PortBindings = PortBindings;
// Remove empty fields from the request to avoid overriding defaults
@ -111,35 +115,6 @@ function($scope, $routeParams, $location, Container, Messages, containernameFilt
});
};
$scope.addPortBinding = function() {
$scope.config.PortBindings.push({ip: '', extPort: '', intPort: ''});
};
$scope.removePortBinding = function(portBinding) {
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.removeEnv = function(envar) {
var idx = $scope.config.env.indexOf(envar);
$scope.config.Env.splice(idx, 1);
};
// Todo: refactor out
$scope.addVolumeFrom = function() {
$scope.config.HostConfig.volumesFrom.push({name: ''});
};
$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);
};

View File

@ -20,18 +20,18 @@ describe('startContainerController', function() {
}));
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"
'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"
'Status': 'Up 2 minutes'
}]);
}
describe('Create and start a container with port bindings', function() {
@ -39,15 +39,15 @@ describe('startContainerController', function() {
var controller = createController();
var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c';
var expectedBody = {
"name": "container-name",
"ExposedPorts": {
"9000/tcp": {},
'name': 'container-name',
'ExposedPorts': {
'9000/tcp': {},
},
"HostConfig": {
"PortBindings": {
"9000/tcp": [{
"HostPort": "9999",
"HostIp": "10.20.10.15",
'HostConfig': {
'PortBindings': {
'9000/tcp': [{
'HostPort': '9999',
'HostIp': '10.20.10.15',
}]
},
}
@ -56,16 +56,16 @@ describe('startContainerController', function() {
expectGetContainers();
$httpBackend.expectPOST('dockerapi/containers/create?name=container-name', expectedBody).respond({
"Id": id,
"Warnings": null
'Id': id,
'Warnings': null
});
$httpBackend.expectPOST('dockerapi/containers/' + id + '/start?').respond({
"Id": id,
"Warnings": null
'Id': id,
'Warnings': null
});
scope.config.name = 'container-name';
scope.config.PortBindings = [{
scope.config.HostConfig.PortBindings = [{
ip: '10.20.10.15',
extPort: '9999',
intPort: '9000'
@ -81,19 +81,19 @@ describe('startContainerController', function() {
var controller = createController();
var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c';
var expectedBody = {
"name": "container-name",
"Env": ["SHELL=/bin/bash", "TERM=xterm-256color"]
'name': 'container-name',
'Env': ['SHELL=/bin/bash', 'TERM=xterm-256color']
};
expectGetContainers();
$httpBackend.expectPOST('dockerapi/containers/create?name=container-name', expectedBody).respond({
"Id": id,
"Warnings": null
'Id': id,
'Warnings': null
});
$httpBackend.expectPOST('dockerapi/containers/' + id + '/start?').respond({
"Id": id,
"Warnings": null
'Id': id,
'Warnings': null
});
scope.config.name = 'container-name';
@ -116,25 +116,75 @@ describe('startContainerController', function() {
var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c';
var expectedBody = {
HostConfig: {
"VolumesFrom": ["parent", "other:ro"]
'VolumesFrom': ['parent', 'other:ro']
},
"name": "container-name"
'name': 'container-name'
};
expectGetContainers();
$httpBackend.expectPOST('dockerapi/containers/create?name=container-name', expectedBody).respond({
"Id": id,
"Warnings": null
'Id': id,
'Warnings': null
});
$httpBackend.expectPOST('dockerapi/containers/' + id + '/start?').respond({
"Id": id,
"Warnings": null
'Id': id,
'Warnings': null
});
scope.config.name = 'container-name';
scope.config.HostConfig.VolumesFrom = [{name: "parent"}, {name:"other:ro"}];
scope.config.HostConfig.VolumesFrom = [{name: 'parent'}, {name:'other:ro'}];
scope.create();
$httpBackend.flush();
});
});
describe('Create and start a container with multiple options', function() {
it('should issue a correct create request to the Docker remote API', function() {
var controller = createController();
var id = '6abd8bfba81cf8a05a76a4bdefcb36c4b66cd02265f4bfcd0e236468696ebc6c';
var expectedBody = {
Volumes: ['/var/www'],
SecurityOpts: ['label:type:svirt_apache'],
HostConfig: {
Binds: ['/app:/app'],
Links: ['web:db'],
Dns: ['8.8.8.8'],
DnsSearch: ['example.com'],
CapAdd: ['cap_sys_admin'],
CapDrop: ['cap_foo_bar']
},
name: 'container-name'
};
expectGetContainers();
$httpBackend.expectPOST('dockerapi/containers/create?name=container-name', expectedBody).respond({
'Id': id,
'Warnings': null
});
$httpBackend.expectPOST('dockerapi/containers/' + id + '/start?').respond({
'Id': id,
'Warnings': null
});
scope.config.name = 'container-name';
scope.config.Volumes = [{name: '/var/www'}];
scope.config.SecurityOpts = [{name: 'label:type:svirt_apache'}];
scope.config.NetworkDisabled = true;
scope.config.Tty = true;
scope.config.OpenStdin = true;
scope.config.StdinOnce = true;
scope.config.HostConfig.Binds = [{name: '/app:/app'}];
scope.config.HostConfig.Links = [{name: 'web:db'}];
scope.config.HostConfig.Dns = [{name: '8.8.8.8'}];
scope.config.HostConfig.DnsSearch = [{name: 'example.com'}];
scope.config.HostConfig.CapAdd = [{name: 'cap_sys_admin'}];
scope.config.HostConfig.CapDrop = [{name: 'cap_foo_bar'}];
scope.config.HostConfig.PublishAllPorts = true;
scope.config.HostConfig.Privileged = true;
scope.create();
$httpBackend.flush();

View File

@ -8,7 +8,7 @@
<div class="modal-body">
<form role="form">
<accordion close-others="true">
<accordion-group heading="Container options">
<accordion-group heading="Container options" is-open="menuStatus.containerOpen">
<fieldset>
<div class="row">
<div class="col-xs-6">
@ -94,7 +94,7 @@
<label>Security Options:</label>
<div ng-repeat="opt in config.SecurityOpts">
<div class="form-group form-inline">
<input type="text" ng-model="opt.name" class="form-control" placeholder="???"/>
<input type="text" ng-model="opt.name" class="form-control" placeholder="label:type:svirt_apache"/>
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.SecurityOpts, opt)">Remove</button>
</div>
</div>
@ -102,6 +102,7 @@
</div>
</div>
</div>
<hr>
<div class="form-group">
<label>Environment Variables:</label>
<div ng-repeat="envar in config.Env">
@ -115,15 +116,15 @@
<input type="text" ng-model="envar.value" class="form-control" placeholder="value"/>
</div>
<div class="form-group">
<button class="btn btn-danger btn-xs form-control" ng-click="removeEnv(portBinding)">Remove</button>
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.Env, envar)">Remove</button>
</div>
</div>
</div>
<button type="button" class="btn btn-success btn-sm" ng-click="addEnv()">Add ENV variable</button>
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.Env, {name: '', value: ''})">Add ENV variable</button>
</div>
</fieldset>
</accordion-group>
<accordion-group heading="HostConfig options">
<accordion-group heading="HostConfig options" is-open="menuStatus.hostConfigOpen">
<fieldset>
<div class="row">
<div class="col-xs-6">
@ -131,7 +132,7 @@
<label>Binds:</label>
<div ng-repeat="bind in config.HostConfig.Binds">
<div class="form-group form-inline">
<input type="text" ng-model="bind.name" class="form-control" placeholder="???"/>
<input type="text" ng-model="bind.name" class="form-control" placeholder="/host:/container"/>
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.Binds, bind)">Remove</button>
</div>
</div>
@ -161,7 +162,7 @@
<label>DnsSearch:</label>
<div ng-repeat="entry in config.HostConfig.DnsSearch">
<div class="form-group form-inline">
<input type="text" ng-model="entry.name" class="form-control" placeholder="???"/>
<input type="text" ng-model="entry.name" class="form-control" placeholder="example.com"/>
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.DnsSearch, entry)">Remove</button>
</div>
</div>
@ -171,7 +172,7 @@
<label>CapAdd:</label>
<div ng-repeat="entry in config.HostConfig.CapAdd">
<div class="form-group form-inline">
<input type="text" ng-model="entry.name" class="form-control" placeholder="???"/>
<input type="text" ng-model="entry.name" class="form-control" placeholder="cap_sys_admin"/>
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.CapAdd, entry)">Remove</button>
</div>
</div>
@ -183,7 +184,7 @@
<label>CapDrop:</label>
<div ng-repeat="entry in config.HostConfig.CapDrop">
<div class="form-group form-inline">
<input type="text" ng-model="entry.name" class="form-control" placeholder="???"/>
<input type="text" ng-model="entry.name" class="form-control" placeholder="cap_sys_admin"/>
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.CapDrop, entry)">Remove</button>
</div>
</div>
@ -206,10 +207,10 @@
<div ng-repeat="volume in config.HostConfig.VolumesFrom">
<div class="form-inline">
<select ng-model="volume.name" ng-options="name for name in containerNames track by name" class="form-control"/>
<button class="btn btn-danger btn-xs form-control" ng-click="removeVolumeFrom($index)">Remove</button>
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.HostConfig.VolumesFrom, volume)">Remove</button>
</div>
</div>
<button type="button" class="btn btn-success btn-sm" ng-click="addVolumeFrom()">Add volume</button>
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.VolumesFrom, {name: ''})">Add volume</button>
</div>
<!--
<div class="form-group">
@ -224,9 +225,10 @@
-->
</div>
</div>
<hr>
<div class="form-group">
<label>Port bindings:</label>
<div ng-repeat="portBinding in config.PortBindings">
<div ng-repeat="portBinding in config.HostConfig.PortBindings">
<div class="form-group form-inline">
<label class="sr-only">Host IP:</label>
<input type="text" ng-model="portBinding.ip" class="form-control" placeholder="Host IP Address"/>
@ -234,10 +236,10 @@
<input type="text" ng-model="portBinding.extPort" class="form-control" placeholder="Host Port"/>
<label class="sr-only">Container port:</label>
<input type="text" ng-model="portBinding.intPort" class="form-control" placeholder="Container Port"/>
<button class="btn btn-danger btn-xs form-control" ng-click="removePortBinding(portBinding)">Remove</button>
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.HostConfig.PortBindings, portBinding)">Remove</button>
</div>
</div>
<button type="button" class="btn btn-success btn-sm" ng-click="addPortBinding()">Add Port Binding</button>
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.PortBindings, {ip: '', extPort: '', intPort: ''})">Add Port Binding</button>
</div>
</fieldset>
</accordion-group>

View File

@ -99,4 +99,15 @@ angular.module('dockerui.filters', [])
var date = new Date(data * 1000);
return date.toDateString();
};
})
.filter('errorMsg', function() {
return function(object) {
var idx = 0;
var msg = '';
while (object[idx] && typeof(object[idx]) === 'string') {
msg += object[idx];
idx++;
}
return msg;
};
});

View File

@ -119,7 +119,7 @@ angular.module('dockerui.services', ['ngResource'])
$.gritter.add({
title: title,
text: text,
time: 6000,
time: 10000,
before_open: function() {
if($('.gritter-item-wrapper').length === 4) {
return false;

View File

@ -153,4 +153,13 @@ describe('filters', function () {
expect(getdateFilter(1420424998)).toBe('Sun Jan 04 2015');
}));
});
describe('errorMsgFilter', function() {
it('should convert the $resource object to a string message',
inject(function(errorMsgFilter) {
var response = {'0':'C','1':'o','2':'n','3':'f','4':'l','5':'i','6':'c','7':'t','8':',','9':' ','10':'T','11':'h','12':'e','13':' ','14':'n','15':'a','16':'m','17':'e','18':' ','19':'u','20':'b','21':'u','22':'n','23':'t','24':'u','25':'-','26':'s','27':'l','28':'e','29':'e','30':'p','31':'-','32':'r','33':'u','34':'n','35':'t','36':'i','37':'m','38':'e','39':' ','40':'i','41':'s','42':' ','43':'a','44':'l','45':'r','46':'e','47':'a','48':'d','49':'y','50':' ','51':'a','52':'s','53':'s','54':'i','55':'g','56':'n','57':'e','58':'d','59':' ','60':'t','61':'o','62':' ','63':'b','64':'6','65':'9','66':'e','67':'5','68':'3','69':'a','70':'6','71':'2','72':'2','73':'c','74':'8','75':'.','76':' ','77':'Y','78':'o','79':'u','80':' ','81':'h','82':'a','83':'v','84':'e','85':' ','86':'t','87':'o','88':' ','89':'d','90':'e','91':'l','92':'e','93':'t','94':'e','95':' ','96':'(','97':'o','98':'r','99':' ','100':'r','101':'e','102':'n','103':'a','104':'m','105':'e','106':')','107':' ','108':'t','109':'h','110':'a','111':'t','112':' ','113':'c','114':'o','115':'n','116':'t','117':'a','118':'i','119':'n','120':'e','121':'r','122':' ','123':'t','124':'o','125':' ','126':'b','127':'e','128':' ','129':'a','130':'b','131':'l','132':'e','133':' ','134':'t','135':'o','136':' ','137':'a','138':'s','139':'s','140':'i','141':'g','142':'n','143':' ','144':'u','145':'b','146':'u','147':'n','148':'t','149':'u','150':'-','151':'s','152':'l','153':'e','154':'e','155':'p','156':'-','157':'r','158':'u','159':'n','160':'t','161':'i','162':'m','163':'e','164':' ','165':'t','166':'o','167':' ','168':'a','169':' ','170':'c','171':'o','172':'n','173':'t','174':'a','175':'i','176':'n','177':'e','178':'r','179':' ','180':'a','181':'g','182':'a','183':'i','184':'n','185':'.','186':'\n','$promise':{},'$resolved':true};
var message = 'Conflict, The name ubuntu-sleep-runtime is already assigned to b69e53a622c8. You have to delete (or rename) that container to be able to assign ubuntu-sleep-runtime to a container again.\n';
expect(errorMsgFilter(response)).toBe(message);
}));
});
});