Merge pull request #54 from kevana/master
Features: Pause/unpause, update container info after actions, keep same HostConfig through stop/start 👍
pull/2/head
commit
4dddd6227b
|
@ -155,34 +155,86 @@ function SettingsController($scope, System, Docker, Settings, Messages) {
|
||||||
function ContainerController($scope, $routeParams, $location, Container, Messages, ViewSpinner) {
|
function ContainerController($scope, $routeParams, $location, Container, Messages, ViewSpinner) {
|
||||||
$scope.changes = [];
|
$scope.changes = [];
|
||||||
|
|
||||||
|
var update = function() {
|
||||||
|
Container.get({id: $routeParams.id}, function(d) {
|
||||||
|
$scope.container = d;
|
||||||
|
ViewSpinner.stop();
|
||||||
|
}, function(e) {
|
||||||
|
if (e.status === 404) {
|
||||||
|
$('.detail').hide();
|
||||||
|
Messages.error("Not found", "Container not found.");
|
||||||
|
} else {
|
||||||
|
Messages.error("Failure", e.data);
|
||||||
|
}
|
||||||
|
ViewSpinner.stop();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
$scope.start = function(){
|
$scope.start = function(){
|
||||||
Container.start({id: $routeParams.id}, function(d) {
|
ViewSpinner.spin();
|
||||||
|
Container.start({
|
||||||
|
id: $scope.container.Id,
|
||||||
|
HostConfig: $scope.container.HostConfig
|
||||||
|
}, function(d) {
|
||||||
|
update();
|
||||||
Messages.send("Container started", $routeParams.id);
|
Messages.send("Container started", $routeParams.id);
|
||||||
}, function(e) {
|
}, function(e) {
|
||||||
|
update();
|
||||||
Messages.error("Failure", "Container failed to start." + e.data);
|
Messages.error("Failure", "Container failed to start." + e.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.stop = function() {
|
$scope.stop = function() {
|
||||||
|
ViewSpinner.spin();
|
||||||
Container.stop({id: $routeParams.id}, function(d) {
|
Container.stop({id: $routeParams.id}, function(d) {
|
||||||
|
update();
|
||||||
Messages.send("Container stopped", $routeParams.id);
|
Messages.send("Container stopped", $routeParams.id);
|
||||||
}, function(e) {
|
}, function(e) {
|
||||||
|
update();
|
||||||
Messages.error("Failure", "Container failed to stop." + e.data);
|
Messages.error("Failure", "Container failed to stop." + e.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.kill = function() {
|
$scope.kill = function() {
|
||||||
|
ViewSpinner.spin();
|
||||||
Container.kill({id: $routeParams.id}, function(d) {
|
Container.kill({id: $routeParams.id}, function(d) {
|
||||||
|
update();
|
||||||
Messages.send("Container killed", $routeParams.id);
|
Messages.send("Container killed", $routeParams.id);
|
||||||
}, function(e) {
|
}, function(e) {
|
||||||
|
update();
|
||||||
Messages.error("Failure", "Container failed to die." + e.data);
|
Messages.error("Failure", "Container failed to die." + e.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.pause = function() {
|
||||||
|
ViewSpinner.spin();
|
||||||
|
Container.pause({id: $routeParams.id}, function(d) {
|
||||||
|
update();
|
||||||
|
Messages.send("Container paused", $routeParams.id);
|
||||||
|
}, function(e) {
|
||||||
|
update();
|
||||||
|
Messages.error("Failure", "Container failed to pause." + e.data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.unpause = function() {
|
||||||
|
ViewSpinner.spin();
|
||||||
|
Container.unpause({id: $routeParams.id}, function(d) {
|
||||||
|
update();
|
||||||
|
Messages.send("Container unpaused", $routeParams.id);
|
||||||
|
}, function(e) {
|
||||||
|
update();
|
||||||
|
Messages.error("Failure", "Container failed to unpause." + e.data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
$scope.remove = function() {
|
$scope.remove = function() {
|
||||||
|
ViewSpinner.spin();
|
||||||
Container.remove({id: $routeParams.id}, function(d) {
|
Container.remove({id: $routeParams.id}, function(d) {
|
||||||
|
update();
|
||||||
Messages.send("Container removed", $routeParams.id);
|
Messages.send("Container removed", $routeParams.id);
|
||||||
}, function(e){
|
}, function(e){
|
||||||
|
update();
|
||||||
Messages.error("Failure", "Container failed to remove." + e.data);
|
Messages.error("Failure", "Container failed to remove." + e.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -192,23 +244,15 @@ function ContainerController($scope, $routeParams, $location, Container, Message
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.getChanges = function() {
|
$scope.getChanges = function() {
|
||||||
|
ViewSpinner.spin();
|
||||||
Container.changes({id: $routeParams.id}, function(d) {
|
Container.changes({id: $routeParams.id}, function(d) {
|
||||||
$scope.changes = d;
|
$scope.changes = d;
|
||||||
|
ViewSpinner.stop();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Container.get({id: $routeParams.id}, function(d) {
|
update();
|
||||||
$scope.container = d;
|
$scope.getChanges();
|
||||||
}, function(e) {
|
|
||||||
if (e.status === 404) {
|
|
||||||
$('.detail').hide();
|
|
||||||
Messages.error("Not found", "Container not found.");
|
|
||||||
} else {
|
|
||||||
Messages.error("Failure", e.data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$scope.getChanges();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Controller for the list of containers
|
// Controller for the list of containers
|
||||||
|
@ -221,7 +265,7 @@ function ContainersController($scope, Container, Settings, Messages, ViewSpinner
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
Container.query(data, function(d) {
|
Container.query(data, function(d) {
|
||||||
$scope.containers = d.map(function(item) {
|
$scope.containers = d.map(function(item) {
|
||||||
return new ContainerViewModel(item); });
|
return new ContainerViewModel(item); });
|
||||||
ViewSpinner.stop();
|
ViewSpinner.stop();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -233,22 +277,25 @@ function ContainersController($scope, Container, Settings, Messages, ViewSpinner
|
||||||
counter = counter -1;
|
counter = counter -1;
|
||||||
if (counter === 0) {
|
if (counter === 0) {
|
||||||
ViewSpinner.stop();
|
ViewSpinner.stop();
|
||||||
|
update({all: Settings.displayAll ? 1 : 0});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
angular.forEach(items, function(c) {
|
angular.forEach(items, function(c) {
|
||||||
if (c.Checked) {
|
if (c.Checked) {
|
||||||
counter = counter + 1;
|
counter = counter + 1;
|
||||||
action({id: c.Id}, function(d) {
|
action({id: c.Id}, function(d) {
|
||||||
Messages.send("Container " + msg, c.Id);
|
Messages.send("Container " + msg, c.Id);
|
||||||
var index = $scope.containers.indexOf(c);
|
var index = $scope.containers.indexOf(c);
|
||||||
$scope.containers.splice(index, 1);
|
|
||||||
complete();
|
complete();
|
||||||
}, function(e) {
|
}, function(e) {
|
||||||
Messages.error("Failure", e.data);
|
Messages.error("Failure", e.data);
|
||||||
complete();
|
complete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (counter === 0) {
|
||||||
|
ViewSpinner.stop();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.toggleSelectAll = function() {
|
$scope.toggleSelectAll = function() {
|
||||||
|
@ -274,6 +321,14 @@ function ContainersController($scope, Container, Settings, Messages, ViewSpinner
|
||||||
batch($scope.containers, Container.kill, "Killed");
|
batch($scope.containers, Container.kill, "Killed");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.pauseAction = function() {
|
||||||
|
batch($scope.containers, Container.pause, "Paused");
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.unpauseAction = function() {
|
||||||
|
batch($scope.containers, Container.unpause, "Unpaused");
|
||||||
|
};
|
||||||
|
|
||||||
$scope.removeAction = function() {
|
$scope.removeAction = function() {
|
||||||
batch($scope.containers, Container.remove, "Removed");
|
batch($scope.containers, Container.remove, "Removed");
|
||||||
};
|
};
|
||||||
|
@ -398,6 +453,7 @@ function StartContainerController($scope, $routeParams, $location, Container, Me
|
||||||
name: '',
|
name: '',
|
||||||
memory: 0,
|
memory: 0,
|
||||||
memorySwap: 0,
|
memorySwap: 0,
|
||||||
|
cpuShares: 1024,
|
||||||
env: '',
|
env: '',
|
||||||
commands: '',
|
commands: '',
|
||||||
volumesFrom: ''
|
volumesFrom: ''
|
||||||
|
@ -419,6 +475,7 @@ function StartContainerController($scope, $routeParams, $location, Container, Me
|
||||||
name: $scope.config.name,
|
name: $scope.config.name,
|
||||||
Memory: $scope.config.memory,
|
Memory: $scope.config.memory,
|
||||||
MemorySwap: $scope.config.memorySwap,
|
MemorySwap: $scope.config.memorySwap,
|
||||||
|
CpuShares: $scope.config.cpuShares,
|
||||||
Cmd: cmds,
|
Cmd: cmds,
|
||||||
VolumesFrom: $scope.config.volumesFrom
|
VolumesFrom: $scope.config.volumesFrom
|
||||||
}, function(d) {
|
}, function(d) {
|
||||||
|
|
|
@ -34,6 +34,9 @@ angular.module('dockerui.filters', [])
|
||||||
if (state.Ghost && state.Running) {
|
if (state.Ghost && state.Running) {
|
||||||
return 'Ghost';
|
return 'Ghost';
|
||||||
}
|
}
|
||||||
|
if (state.Running && state.Paused) {
|
||||||
|
return 'Running (Paused)';
|
||||||
|
}
|
||||||
if (state.Running) {
|
if (state.Running) {
|
||||||
return 'Running';
|
return 'Running';
|
||||||
}
|
}
|
||||||
|
@ -65,18 +68,18 @@ angular.module('dockerui.filters', [])
|
||||||
})
|
})
|
||||||
.filter('containername', function() {
|
.filter('containername', function() {
|
||||||
return function(container) {
|
return function(container) {
|
||||||
var name = container.Names[0];
|
var name = container.Names[0];
|
||||||
return name.substring(1, name.length);
|
return name.substring(1, name.length);
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter('repotag', function() {
|
.filter('repotag', function() {
|
||||||
return function(image) {
|
return function(image) {
|
||||||
if (image.RepoTags && image.RepoTags.length > 0) {
|
if (image.RepoTags && image.RepoTags.length > 0) {
|
||||||
var tag = image.RepoTags[0];
|
var tag = image.RepoTags[0];
|
||||||
if (tag == '<none>:<none>') { tag = ''; }
|
if (tag == '<none>:<none>') { tag = ''; }
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter('getdate', function() {
|
.filter('getdate', function() {
|
||||||
|
|
|
@ -5,17 +5,19 @@ angular.module('dockerui.services', ['ngResource'])
|
||||||
// Resource for interacting with the docker containers
|
// Resource for interacting with the docker containers
|
||||||
// http://docs.docker.io/en/latest/api/docker_remote_api.html#containers
|
// http://docs.docker.io/en/latest/api/docker_remote_api.html#containers
|
||||||
return $resource(Settings.url + '/containers/:id/:action', {
|
return $resource(Settings.url + '/containers/:id/:action', {
|
||||||
name: '@name'
|
name: '@name'
|
||||||
}, {
|
}, {
|
||||||
query: {method: 'GET', params:{ all: 0, action: 'json'}, isArray: true},
|
query: {method: 'GET', params:{ all: 0, action: 'json'}, isArray: true},
|
||||||
get :{method: 'GET', params: { action:'json'}},
|
get: {method: 'GET', params: { action:'json'}},
|
||||||
start: {method: 'POST', params: {id: '@id', action: 'start'}},
|
start: {method: 'POST', params: {id: '@id', action: 'start'}},
|
||||||
stop: {method: 'POST', params: {id: '@id', t: 5, action: 'stop'}},
|
stop: {method: 'POST', params: {id: '@id', t: 5, action: 'stop'}},
|
||||||
restart: {method: 'POST', params: {id: '@id', t: 5, action: 'restart' }},
|
restart: {method: 'POST', params: {id: '@id', t: 5, action: 'restart' }},
|
||||||
kill :{method: 'POST', params: {id: '@id', action:'kill'}},
|
kill: {method: 'POST', params: {id: '@id', action: 'kill'}},
|
||||||
changes :{method: 'GET', params: {action:'changes'}, isArray: true},
|
pause: {method: 'POST', params: {id: '@id', action: 'pause'}},
|
||||||
create :{method: 'POST', params: {action:'create'}},
|
unpause: {method: 'POST', params: {id: '@id', action: 'unpause'}},
|
||||||
remove :{method: 'DELETE', params: {id: '@id', v:0}}
|
changes: {method: 'GET', params: {action:'changes'}, isArray: true},
|
||||||
|
create: {method: 'POST', params: {action:'create'}},
|
||||||
|
remove: {method: 'DELETE', params: {id: '@id', v:0}}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.factory('Image', function($resource, Settings) {
|
.factory('Image', function($resource, Settings) {
|
||||||
|
@ -23,14 +25,14 @@ angular.module('dockerui.services', ['ngResource'])
|
||||||
// http://docs.docker.io/en/latest/api/docker_remote_api.html#images
|
// http://docs.docker.io/en/latest/api/docker_remote_api.html#images
|
||||||
return $resource(Settings.url + '/images/:id/:action', {}, {
|
return $resource(Settings.url + '/images/:id/:action', {}, {
|
||||||
query: {method: 'GET', params:{ all: 0, action: 'json'}, isArray: true},
|
query: {method: 'GET', params:{ all: 0, action: 'json'}, isArray: true},
|
||||||
get :{method: 'GET', params: { action:'json'}},
|
get: {method: 'GET', params: { action:'json'}},
|
||||||
search :{method: 'GET', params: { action:'search'}},
|
search: {method: 'GET', params: { action:'search'}},
|
||||||
history :{method: 'GET', params: { action:'history'}, isArray: true},
|
history: {method: 'GET', params: { action:'history'}, isArray: true},
|
||||||
create :{method: 'POST', params: {action:'create'}},
|
create: {method: 'POST', params: {action:'create'}},
|
||||||
insert :{method: 'POST', params: {id: '@id', action:'insert'}},
|
insert: {method: 'POST', params: {id: '@id', action:'insert'}},
|
||||||
push :{method: 'POST', params: {id: '@id', action:'push'}},
|
push: {method: 'POST', params: {id: '@id', action:'push'}},
|
||||||
tag :{method: 'POST', params: {id: '@id', action:'tag', force: 0, repo: '@repo'}},
|
tag: {method: 'POST', params: {id: '@id', action:'tag', force: 0, repo: '@repo'}},
|
||||||
remove :{method: 'DELETE', params: {id: '@id'}, isArray: true}
|
remove: {method: 'DELETE', params: {id: '@id'}, isArray: true}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.factory('Docker', function($resource, Settings) {
|
.factory('Docker', function($resource, Settings) {
|
||||||
|
@ -74,52 +76,51 @@ angular.module('dockerui.services', ['ngResource'])
|
||||||
var spinner = new Spinner();
|
var spinner = new Spinner();
|
||||||
var target = document.getElementById('view');
|
var target = document.getElementById('view');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
spin: function() { spinner.spin(target); },
|
spin: function() { spinner.spin(target); },
|
||||||
stop: function() { spinner.stop(); }
|
stop: function() { spinner.stop(); }
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.factory('Messages', function($rootScope) {
|
.factory('Messages', function($rootScope) {
|
||||||
return {
|
return {
|
||||||
send: function(title, text) {
|
send: function(title, text) {
|
||||||
$.gritter.add({
|
$.gritter.add({
|
||||||
title: title,
|
title: title,
|
||||||
text: text,
|
text: text,
|
||||||
time: 2000,
|
time: 2000,
|
||||||
before_open: function() {
|
before_open: function() {
|
||||||
if($('.gritter-item-wrapper').length == 3) {
|
if($('.gritter-item-wrapper').length == 3) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
});
|
},
|
||||||
},
|
error: function(title, text) {
|
||||||
error: function(title, text) {
|
|
||||||
$.gritter.add({
|
$.gritter.add({
|
||||||
title: title,
|
title: title,
|
||||||
text: text,
|
text: text,
|
||||||
time: 6000,
|
time: 6000,
|
||||||
before_open: function() {
|
before_open: function() {
|
||||||
if($('.gritter-item-wrapper').length == 4) {
|
if($('.gritter-item-wrapper').length == 4) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.factory('Dockerfile', function(Settings) {
|
.factory('Dockerfile', function(Settings) {
|
||||||
var url = Settings.rawUrl + '/build';
|
var url = Settings.rawUrl + '/build';
|
||||||
return {
|
return {
|
||||||
build: function(file, callback) {
|
build: function(file, callback) {
|
||||||
var data = new FormData();
|
var data = new FormData();
|
||||||
var dockerfile = new Blob([file], { type: 'text/text' });
|
var dockerfile = new Blob([file], { type: 'text/text' });
|
||||||
data.append('Dockerfile', dockerfile);
|
data.append('Dockerfile', dockerfile);
|
||||||
|
|
||||||
var request = new XMLHttpRequest();
|
var request = new XMLHttpRequest();
|
||||||
request.onload = callback;
|
request.onload = callback;
|
||||||
request.open('POST', url);
|
request.open('POST', url);
|
||||||
request.send(data);
|
request.send(data);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,9 +3,21 @@
|
||||||
<h4>Container: {{ container.Name }}</h4>
|
<h4>Container: {{ container.Name }}</h4>
|
||||||
|
|
||||||
<div class="btn-group detail">
|
<div class="btn-group detail">
|
||||||
<button class="btn btn-success" ng-click="start()">Start</button>
|
<button class="btn btn-success"
|
||||||
<button class="btn btn-warning" ng-click="stop()">Stop</button>
|
ng-click="start()"
|
||||||
<button class="btn btn-danger" ng-click="kill()">Kill</button>
|
ng-show="!container.State.Running">Start</button>
|
||||||
|
<button class="btn btn-warning"
|
||||||
|
ng-click="stop()"
|
||||||
|
ng-show="container.State.Running && !container.State.Paused">Stop</button>
|
||||||
|
<button class="btn btn-danger"
|
||||||
|
ng-click="kill()"
|
||||||
|
ng-show="container.State.Running && !container.State.Paused">Kill</button>
|
||||||
|
<button class="btn btn-info"
|
||||||
|
ng-click="pause()"
|
||||||
|
ng-show="container.State.Running && !container.State.Paused">Pause</button>
|
||||||
|
<button class="btn btn-success"
|
||||||
|
ng-click="unpause()"
|
||||||
|
ng-show="container.State.Running && container.State.Paused">Unpause</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
<li><a tabindex="-1" href="" ng-click="startAction()">Start</a></li>
|
<li><a tabindex="-1" href="" ng-click="startAction()">Start</a></li>
|
||||||
<li><a tabindex="-1" href="" ng-click="stopAction()">Stop</a></li>
|
<li><a tabindex="-1" href="" ng-click="stopAction()">Stop</a></li>
|
||||||
<li><a tabindex="-1" href="" ng-click="killAction()">Kill</a></li>
|
<li><a tabindex="-1" href="" ng-click="killAction()">Kill</a></li>
|
||||||
|
<li><a tabindex="-1" href="" ng-click="pauseAction()">Pause</a></li>
|
||||||
|
<li><a tabindex="-1" href="" ng-click="unpauseAction()">Unpause</a></li>
|
||||||
<li><a tabindex="-1" href="" ng-click="removeAction()">Remove</a></li>
|
<li><a tabindex="-1" href="" ng-click="removeAction()">Remove</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
<label>Memory Swap:</label>
|
<label>Memory Swap:</label>
|
||||||
<input type="number" ng-model="config.memorySwap"/>
|
<input type="number" ng-model="config.memorySwap"/>
|
||||||
|
|
||||||
|
<label>CPU Shares:</label>
|
||||||
|
<input type="number" ng-model="config.cpuShares"/>
|
||||||
|
|
||||||
<label>Volumes From:</label>
|
<label>Volumes From:</label>
|
||||||
<input type="text" ng-model="config.volumesFrom"/>
|
<input type="text" ng-model="config.volumesFrom"/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
Loading…
Reference in New Issue