mirror of https://github.com/portainer/portainer
commit
9c985e63ee
15
app/app.js
15
app/app.js
|
@ -1,4 +1,4 @@
|
||||||
angular.module('dockerui', ['dockerui.templates', 'ngRoute', 'dockerui.services', 'dockerui.filters', 'masthead', 'footer', 'dashboard', 'container', 'containers', 'containersNetwork', 'images', 'image', 'pullImage', 'startContainer', 'sidebar', 'info', 'builder', 'containerLogs', 'containerTop', 'events'])
|
angular.module('dockerui', ['dockerui.templates', 'ngRoute', 'dockerui.services', 'dockerui.filters', 'masthead', 'footer', 'dashboard', 'container', 'containers', 'containersNetwork', 'images', 'image', 'pullImage', 'startContainer', 'sidebar', 'info', 'builder', 'containerLogs', 'containerTop', 'events', 'stats'])
|
||||||
.config(['$routeProvider', function ($routeProvider) {
|
.config(['$routeProvider', function ($routeProvider) {
|
||||||
'use strict';
|
'use strict';
|
||||||
$routeProvider.when('/', {
|
$routeProvider.when('/', {
|
||||||
|
@ -21,6 +21,10 @@ angular.module('dockerui', ['dockerui.templates', 'ngRoute', 'dockerui.services'
|
||||||
templateUrl: 'app/components/containerTop/containerTop.html',
|
templateUrl: 'app/components/containerTop/containerTop.html',
|
||||||
controller: 'ContainerTopController'
|
controller: 'ContainerTopController'
|
||||||
});
|
});
|
||||||
|
$routeProvider.when('/containers/:id/stats', {
|
||||||
|
templateUrl: 'app/components/stats/stats.html',
|
||||||
|
controller: 'StatsController'
|
||||||
|
});
|
||||||
$routeProvider.when('/containers_network', {
|
$routeProvider.when('/containers_network', {
|
||||||
templateUrl: 'app/components/containersNetwork/containersNetwork.html',
|
templateUrl: 'app/components/containersNetwork/containersNetwork.html',
|
||||||
controller: 'ContainersNetworkController'
|
controller: 'ContainersNetworkController'
|
||||||
|
@ -34,12 +38,15 @@ angular.module('dockerui', ['dockerui.templates', 'ngRoute', 'dockerui.services'
|
||||||
controller: 'ImageController'
|
controller: 'ImageController'
|
||||||
});
|
});
|
||||||
$routeProvider.when('/info', {templateUrl: 'app/components/info/info.html', controller: 'InfoController'});
|
$routeProvider.when('/info', {templateUrl: 'app/components/info/info.html', controller: 'InfoController'});
|
||||||
$routeProvider.when('/events', {templateUrl: 'app/components/events/events.html', controller: 'EventsController'});
|
$routeProvider.when('/events', {
|
||||||
|
templateUrl: 'app/components/events/events.html',
|
||||||
|
controller: 'EventsController'
|
||||||
|
});
|
||||||
$routeProvider.otherwise({redirectTo: '/'});
|
$routeProvider.otherwise({redirectTo: '/'});
|
||||||
}])
|
}])
|
||||||
// This is your docker url that the api will use to make requests
|
// 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
|
// 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('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('UI_VERSION', 'v0.8.0')
|
||||||
.constant('DOCKER_API_VERSION', 'v1.17');
|
.constant('DOCKER_API_VERSION', 'v1.20');
|
||||||
|
|
|
@ -133,6 +133,10 @@
|
||||||
<td>Logs:</td>
|
<td>Logs:</td>
|
||||||
<td><a href="#/containers/{{ container.Id }}/logs">stdout/stderr</a></td>
|
<td><a href="#/containers/{{ container.Id }}/logs">stdout/stderr</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Stats:</td>
|
||||||
|
<td><a href="#/containers/{{ container.Id }}/stats">stats</a></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Top:</td>
|
<td>Top:</td>
|
||||||
<td><a href="#/containers/{{ container.Id }}/top">Top</a></td>
|
<td><a href="#/containers/{{ container.Id }}/top">Top</a></td>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<div class="row logs">
|
<div class="row logs">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<h4>Logs for container: <a href="#/containers/{{ container.Id }}/">{{ container.Name }}</a></td></h4>
|
<h4>Logs for container: <a href="#/containers/{{ container.Id }}/">{{ container.Name }}</a></td></h4>
|
||||||
|
|
||||||
<div class="btn-group detail">
|
<div class="btn-group detail">
|
||||||
<button class="btn btn-info" ng-click="scrollTo('stdout')">stdout</button>
|
<button class="btn btn-info" ng-click="scrollTo('stdout')">stdout</button>
|
||||||
<button class="btn btn-warning" ng-click="scrollTo('stderr')">stderr</button>
|
<button class="btn btn-warning" ng-click="scrollTo('stderr')">stderr</button>
|
||||||
|
|
|
@ -9,7 +9,8 @@ function($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();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
<button class="btn btn-info" ng-click="network.showSelectedUpstream()">Show Selected Upstream</button>
|
<button class="btn btn-info" ng-click="network.showSelectedUpstream()">Show Selected Upstream</button>
|
||||||
<button class="btn btn-success" ng-click="network.showAll()">Show All</button>
|
<button class="btn btn-success" ng-click="network.showAll()">Show All</button>
|
||||||
</div>
|
</div>
|
||||||
<input type="checkbox" ng-model="includeStopped" id="includeStopped" ng-change="toggleIncludeStopped()"/> <label for="includeStopped">Include stopped containers</label>
|
<input type="checkbox" ng-model="includeStopped" id="includeStopped" ng-change="toggleIncludeStopped()"/> <label
|
||||||
|
for="includeStopped">Include stopped containers</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<vis-network data="network.data" options="network.options" events="network.events"
|
<vis-network data="network.data" options="network.options" events="network.events"
|
||||||
|
|
|
@ -50,8 +50,9 @@ angular.module('containersNetwork', ['ngVis'])
|
||||||
this.hasEdge = function (from, to) {
|
this.hasEdge = function (from, to) {
|
||||||
return this.edges.getIds({
|
return this.edges.getIds({
|
||||||
filter: function (item) {
|
filter: function (item) {
|
||||||
return item.from == from.Id && item.to == to.Id;
|
return item.from === from.Id && item.to === to.Id;
|
||||||
} }).length > 0;
|
}
|
||||||
|
}).length > 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.addLinkEdgeIfExists = function (from, to) {
|
this.addLinkEdgeIfExists = function (from, to) {
|
||||||
|
@ -59,7 +60,8 @@ angular.module('containersNetwork', ['ngVis'])
|
||||||
this.edges.add({
|
this.edges.add({
|
||||||
from: from.Id,
|
from: from.Id,
|
||||||
to: to.Id,
|
to: to.Id,
|
||||||
label: from.Links[to.Name] });
|
label: from.Links[to.Name]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -68,7 +70,8 @@ angular.module('containersNetwork', ['ngVis'])
|
||||||
this.edges.add({
|
this.edges.add({
|
||||||
from: from.Id,
|
from: from.Id,
|
||||||
to: to.Id,
|
to: to.Id,
|
||||||
color: { color: '#A0A0A0', highlight: '#A0A0A0', hover: '#848484'}});
|
color: {color: '#A0A0A0', highlight: '#A0A0A0', hover: '#848484'}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
<div class="col-xs-offset-1">
|
<div class="col-xs-offset-1">
|
||||||
<!--<div class="sidebar span4">
|
<!--<div class="sidebar span4">
|
||||||
<div ng-include="template" ng-controller="SideBarController"></div>
|
<div ng-include="template" ng-controller="SideBarController"></div>
|
||||||
|
@ -7,6 +6,7 @@
|
||||||
<div class="col-xs-10" id="masthead" style="display:none">
|
<div class="col-xs-10" id="masthead" style="display:none">
|
||||||
<div class="jumbotron">
|
<div class="jumbotron">
|
||||||
<h1>DockerUI</h1>
|
<h1>DockerUI</h1>
|
||||||
|
|
||||||
<p class="lead">The Linux container engine</p>
|
<p class="lead">The Linux container engine</p>
|
||||||
<a class="btn btn-large btn-success" href="http://docker.io">Learn more.</a>
|
<a class="btn btn-large btn-success" href="http://docker.io">Learn more.</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,7 +27,8 @@
|
||||||
<div class="col-xs-5 text-right">
|
<div class="col-xs-5 text-right">
|
||||||
<h3>Status</h3>
|
<h3>Status</h3>
|
||||||
<canvas id="containers-chart" class="pull-right">
|
<canvas id="containers-chart" class="pull-right">
|
||||||
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a
|
||||||
|
href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
||||||
</canvas>
|
</canvas>
|
||||||
<div id="chart-legend"></div>
|
<div id="chart-legend"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,11 +39,13 @@
|
||||||
<div class="col-xs-10" id="stats">
|
<div class="col-xs-10" id="stats">
|
||||||
<h4>Containers created</h4>
|
<h4>Containers created</h4>
|
||||||
<canvas id="containers-started-chart" width="700">
|
<canvas id="containers-started-chart" width="700">
|
||||||
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a
|
||||||
|
href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
||||||
</canvas>
|
</canvas>
|
||||||
<h4>Images created</h4>
|
<h4>Images created</h4>
|
||||||
<canvas id="images-created-chart" width="700">
|
<canvas id="images-created-chart" width="700">
|
||||||
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a
|
||||||
|
href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
||||||
</canvas>
|
</canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,24 +5,26 @@ angular.module('dashboard', [])
|
||||||
|
|
||||||
var getStarted = function (data) {
|
var getStarted = function (data) {
|
||||||
$scope.totalContainers = data.length;
|
$scope.totalContainers = data.length;
|
||||||
LineChart.build('#containers-started-chart', data, function(c) { return new Date(c.Created * 1000).toLocaleDateString(); });
|
LineChart.build('#containers-started-chart', data, function (c) {
|
||||||
|
return new Date(c.Created * 1000).toLocaleDateString();
|
||||||
|
});
|
||||||
var s = $scope;
|
var s = $scope;
|
||||||
Image.query({}, function (d) {
|
Image.query({}, function (d) {
|
||||||
s.totalImages = d.length;
|
s.totalImages = d.length;
|
||||||
LineChart.build('#images-created-chart', d, function(c) { return new Date(c.Created * 1000).toLocaleDateString(); });
|
LineChart.build('#images-created-chart', d, function (c) {
|
||||||
|
return new Date(c.Created * 1000).toLocaleDateString();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var opts = {animation: false};
|
var opts = {animation: false};
|
||||||
if (Settings.firstLoad) {
|
if (Settings.firstLoad) {
|
||||||
$('#stats').hide();
|
|
||||||
opts.animation = true;
|
opts.animation = true;
|
||||||
Settings.firstLoad = false;
|
Settings.firstLoad = false;
|
||||||
$('#masthead').show();
|
$('#masthead').show();
|
||||||
|
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
$('#masthead').slideUp('slow');
|
$('#masthead').slideUp('slow');
|
||||||
$('#stats').slideDown('slow');
|
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<h2>Events</h2>
|
<h2>Events</h2>
|
||||||
|
|
||||||
<form class="form-inline">
|
<form class="form-inline">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="since">Since:</label>
|
<label for="since">Since:</label>
|
||||||
|
|
|
@ -3,5 +3,7 @@ angular.module('footer', [])
|
||||||
$scope.template = 'app/components/footer/statusbar.html';
|
$scope.template = 'app/components/footer/statusbar.html';
|
||||||
|
|
||||||
$scope.uiVersion = Settings.uiVersion;
|
$scope.uiVersion = Settings.uiVersion;
|
||||||
Docker.get({}, function(d) { $scope.apiVersion = d.ApiVersion; });
|
Docker.get({}, function (d) {
|
||||||
|
$scope.apiVersion = d.ApiVersion;
|
||||||
|
});
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
<footer class="center well">
|
<footer class="center well">
|
||||||
<p><small>Docker API Version: <strong>{{ apiVersion }}</strong> UI Version: <strong>{{ uiVersion }}</strong> <a class="pull-right" href="https://github.com/crosbymichael/dockerui">dockerui</a></small></p>
|
<p>
|
||||||
|
<small>Docker API Version: <strong>{{ apiVersion }}</strong> UI Version: <strong>{{ uiVersion }}</strong> <a
|
||||||
|
class="pull-right" href="https://github.com/crosbymichael/dockerui">dockerui</a></small>
|
||||||
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
<div>
|
<div>
|
||||||
<h4>Containers created:</h4>
|
<h4>Containers created:</h4>
|
||||||
<canvas id="containers-started-chart" width="750">
|
<canvas id="containers-started-chart" width="750">
|
||||||
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
<p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a
|
||||||
|
href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
||||||
</canvas>
|
</canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -74,7 +75,8 @@
|
||||||
<div class="well well-large">
|
<div class="well well-large">
|
||||||
<ul>
|
<ul>
|
||||||
<li ng-repeat="change in history">
|
<li ng-repeat="change in history">
|
||||||
<strong>{{ change.Id }}</strong>: Created: {{ change.Created|getdate }} Created by: {{ change.CreatedBy }}
|
<strong>{{ change.Id }}</strong>: Created: {{ change.Created|getdate }} Created by: {{ change.CreatedBy
|
||||||
|
}}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -55,7 +55,9 @@ function($scope, $q, $routeParams, $location, Image, Container, Messages, LineCh
|
||||||
var promise = getContainersFromImage($q, Container, t);
|
var promise = getContainersFromImage($q, Container, t);
|
||||||
|
|
||||||
promise.then(function (containers) {
|
promise.then(function (containers) {
|
||||||
LineChart.build('#containers-started-chart', containers, function(c) { return new Date(c.Created * 1000).toLocaleDateString(); });
|
LineChart.build('#containers-started-chart', containers, function (c) {
|
||||||
|
return new Date(c.Created * 1000).toLocaleDateString();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, function (e) {
|
}, function (e) {
|
||||||
|
|
|
@ -43,7 +43,9 @@ function($scope, Image, ViewSpinner, Messages) {
|
||||||
|
|
||||||
ViewSpinner.spin();
|
ViewSpinner.spin();
|
||||||
Image.query({}, function (d) {
|
Image.query({}, function (d) {
|
||||||
$scope.images = d.map(function(item) { return new ImageViewModel(item); });
|
$scope.images = d.map(function (item) {
|
||||||
|
return new ImageViewModel(item);
|
||||||
|
});
|
||||||
ViewSpinner.stop();
|
ViewSpinner.stop();
|
||||||
}, function (e) {
|
}, function (e) {
|
||||||
Messages.error("Failure", e.data);
|
Messages.error("Failure", e.data);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
<h2>Docker Information</h2>
|
<h2>Docker Information</h2>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p class="lead">
|
<p class="lead">
|
||||||
<strong>API Endpoint: </strong>{{ endpoint }}<br/>
|
<strong>API Endpoint: </strong>{{ endpoint }}<br/>
|
||||||
|
|
|
@ -6,6 +6,10 @@ function($scope, System, Docker, Settings, Messages) {
|
||||||
$scope.endpoint = Settings.endpoint;
|
$scope.endpoint = Settings.endpoint;
|
||||||
$scope.apiVersion = Settings.version;
|
$scope.apiVersion = Settings.version;
|
||||||
|
|
||||||
Docker.get({}, function(d) { $scope.docker = d; });
|
Docker.get({}, function (d) {
|
||||||
System.get({}, function(d) { $scope.info = d; });
|
$scope.docker = d;
|
||||||
|
});
|
||||||
|
System.get({}, function (d) {
|
||||||
|
$scope.info = d;
|
||||||
|
});
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="masthead">
|
<div class="masthead">
|
||||||
<h3 class="text-muted">DockerUI</h3>
|
<h3 class="text-muted">DockerUI</h3>
|
||||||
<ul class="nav well">
|
<ul class="nav well">
|
||||||
<li><a href="#">Dashboard</a></li>
|
<li><a href="#/">Dashboard</a></li>
|
||||||
<li><a href="#/containers/">Containers</a></li>
|
<li><a href="#/containers/">Containers</a></li>
|
||||||
<li><a href="#/containers_network/">Containers Network</a></li>
|
<li><a href="#/containers_network/">Containers Network</a></li>
|
||||||
<li><a href="#/images/">Images</a></li>
|
<li><a href="#/images/">Images</a></li>
|
||||||
|
|
|
@ -13,19 +13,23 @@
|
||||||
</div>-->
|
</div>-->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Registry:</label>
|
<label>Registry:</label>
|
||||||
<input type="text" ng-model="config.registry" class="form-control" placeholder="Registry. Leave empty to user docker hub"/>
|
<input type="text" ng-model="config.registry" class="form-control"
|
||||||
|
placeholder="Registry. Leave empty to user docker hub"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Repo:</label>
|
<label>Repo:</label>
|
||||||
<input type="text" ng-model="config.repo" class="form-control" placeholder="Repository - usually your username."/>
|
<input type="text" ng-model="config.repo" class="form-control"
|
||||||
|
placeholder="Repository - usually your username."/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Image Name:</label>
|
<label>Image Name:</label>
|
||||||
<input type="text" ng-model="config.fromImage" class="form-control" placeholder="Image name" required/>
|
<input type="text" ng-model="config.fromImage" class="form-control" placeholder="Image name"
|
||||||
|
required/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Tag Name:</label>
|
<label>Tag Name:</label>
|
||||||
<input type="text" ng-model="config.tag" class="form-control" placeholder="Tag name. If empty it will download ALL tags."/>
|
<input type="text" ng-model="config.tag" class="form-control"
|
||||||
|
placeholder="Tag name. If empty it will download ALL tags."/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,8 +9,8 @@ angular.module('pullImage', [])
|
||||||
repo: '',
|
repo: '',
|
||||||
fromImage: '',
|
fromImage: '',
|
||||||
tag: 'latest'
|
tag: 'latest'
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
$scope.init();
|
$scope.init();
|
||||||
|
|
||||||
|
@ -52,5 +52,5 @@ angular.module('pullImage', [])
|
||||||
$('#pull-modal').modal('show');
|
$('#pull-modal').modal('show');
|
||||||
$('#error-message').show();
|
$('#error-message').show();
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -46,7 +46,9 @@ function($scope, $routeParams, $location, Container, Messages, containernameFilt
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNames(arr) {
|
function getNames(arr) {
|
||||||
return arr.map(function(item) {return item.name;});
|
return arr.map(function (item) {
|
||||||
|
return item.name;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.create = function () {
|
$scope.create = function () {
|
||||||
|
@ -61,7 +63,9 @@ function($scope, $routeParams, $location, Container, Messages, containernameFilt
|
||||||
config.Cmd = config.Cmd.split(' ');
|
config.Cmd = config.Cmd.split(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Env = config.Env.map(function(envar) {return envar.name + '=' + envar.value;});
|
config.Env = config.Env.map(function (envar) {
|
||||||
|
return envar.name + '=' + envar.value;
|
||||||
|
});
|
||||||
|
|
||||||
config.Volumes = getNames(config.Volumes);
|
config.Volumes = getNames(config.Volumes);
|
||||||
config.SecurityOpts = getNames(config.SecurityOpts);
|
config.SecurityOpts = getNames(config.SecurityOpts);
|
||||||
|
@ -77,7 +81,9 @@ function($scope, $routeParams, $location, Container, Messages, containernameFilt
|
||||||
prev[cur.name] = cur.value;
|
prev[cur.name] = cur.value;
|
||||||
return prev;
|
return prev;
|
||||||
}, {});
|
}, {});
|
||||||
config.HostConfig.ExtraHosts = config.HostConfig.ExtraHosts.map(function(entry) {return entry.host + ':' + entry.ip;});
|
config.HostConfig.ExtraHosts = config.HostConfig.ExtraHosts.map(function (entry) {
|
||||||
|
return entry.host + ':' + entry.ip;
|
||||||
|
});
|
||||||
|
|
||||||
var ExposedPorts = {};
|
var ExposedPorts = {};
|
||||||
var PortBindings = {};
|
var PortBindings = {};
|
||||||
|
|
|
@ -14,12 +14,14 @@
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Cmd:</label>
|
<label>Cmd:</label>
|
||||||
<input type="text" placeholder='["/bin/echo", "Hello world"]' ng-model="config.Cmd" class="form-control"/>
|
<input type="text" placeholder='["/bin/echo", "Hello world"]'
|
||||||
|
ng-model="config.Cmd" class="form-control"/>
|
||||||
<small>Input commands as a raw string or JSON array</small>
|
<small>Input commands as a raw string or JSON array</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Entrypoint:</label>
|
<label>Entrypoint:</label>
|
||||||
<input type="text" ng-model="config.Entrypoint" class="form-control" placeholder="./entrypoint.sh"/>
|
<input type="text" ng-model="config.Entrypoint" class="form-control"
|
||||||
|
placeholder="./entrypoint.sh"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Name:</label>
|
<label>Name:</label>
|
||||||
|
@ -43,13 +45,19 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Volumes:</label>
|
<label>Volumes:</label>
|
||||||
|
|
||||||
<div ng-repeat="volume in config.Volumes">
|
<div ng-repeat="volume in config.Volumes">
|
||||||
<div class="form-group form-inline">
|
<div class="form-group form-inline">
|
||||||
<input type="text" ng-model="volume.name" class="form-control" placeholder="/var/data"/>
|
<input type="text" ng-model="volume.name" class="form-control"
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.Volumes, volume)">Remove</button>
|
placeholder="/var/data"/>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.Volumes, volume)">Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.Volumes, {name: ''})">Add Volume</button>
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.Volumes, {name: ''})">Add Volume
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
|
@ -63,20 +71,24 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Cpuset:</label>
|
<label>Cpuset:</label>
|
||||||
<input type="text" ng-model="config.Cpuset" class="form-control" placeholder="1,2"/>
|
<input type="text" ng-model="config.Cpuset" class="form-control"
|
||||||
|
placeholder="1,2"/>
|
||||||
<small>Input as comma-separated list of numbers</small>
|
<small>Input as comma-separated list of numbers</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>WorkingDir:</label>
|
<label>WorkingDir:</label>
|
||||||
<input type="text" ng-model="config.WorkingDir" class="form-control" placeholder="/app"/>
|
<input type="text" ng-model="config.WorkingDir" class="form-control"
|
||||||
|
placeholder="/app"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>MacAddress:</label>
|
<label>MacAddress:</label>
|
||||||
<input type="text" ng-model="config.MacAddress" class="form-control" placeholder="12:34:56:78:9a:bc"/>
|
<input type="text" ng-model="config.MacAddress" class="form-control"
|
||||||
|
placeholder="12:34:56:78:9a:bc"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="networkDisabled">NetworkDisabled:</label>
|
<label for="networkDisabled">NetworkDisabled:</label>
|
||||||
<input id="networkDisabled" type="checkbox" ng-model="config.NetworkDisabled"/>
|
<input id="networkDisabled" type="checkbox"
|
||||||
|
ng-model="config.NetworkDisabled"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="tty">Tty:</label>
|
<label for="tty">Tty:</label>
|
||||||
|
@ -92,35 +104,49 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>SecurityOpts:</label>
|
<label>SecurityOpts:</label>
|
||||||
|
|
||||||
<div ng-repeat="opt in config.SecurityOpts">
|
<div ng-repeat="opt in config.SecurityOpts">
|
||||||
<div class="form-group form-inline">
|
<div class="form-group form-inline">
|
||||||
<input type="text" ng-model="opt.name" class="form-control" placeholder="label:type:svirt_apache"/>
|
<input type="text" ng-model="opt.name" class="form-control"
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.SecurityOpts, opt)">Remove</button>
|
placeholder="label:type:svirt_apache"/>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.SecurityOpts, opt)">Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.SecurityOpts, {name: ''})">Add Option</button>
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.SecurityOpts, {name: ''})">Add Option
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Env:</label>
|
<label>Env:</label>
|
||||||
|
|
||||||
<div ng-repeat="envar in config.Env">
|
<div ng-repeat="envar in config.Env">
|
||||||
<div class="form-group form-inline">
|
<div class="form-group form-inline">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="sr-only">Variable Name:</label>
|
<label class="sr-only">Variable Name:</label>
|
||||||
<input type="text" ng-model="envar.name" class="form-control" placeholder="NAME"/>
|
<input type="text" ng-model="envar.name" class="form-control"
|
||||||
|
placeholder="NAME"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="sr-only">Variable Value:</label>
|
<label class="sr-only">Variable Value:</label>
|
||||||
<input type="text" ng-model="envar.value" class="form-control" placeholder="value"/>
|
<input type="text" ng-model="envar.value" class="form-control"
|
||||||
|
placeholder="value"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.Env, envar)">Remove</button>
|
<button class="btn btn-danger btn-xs form-control"
|
||||||
|
ng-click="rmEntry(config.Env, envar)">Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.Env, {name: '', value: ''})">Add environment variable</button>
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.Env, {name: '', value: ''})">Add environment
|
||||||
|
variable
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</accordion-group>
|
</accordion-group>
|
||||||
|
@ -130,87 +156,137 @@
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Binds:</label>
|
<label>Binds:</label>
|
||||||
|
|
||||||
<div ng-repeat="bind in config.HostConfig.Binds">
|
<div ng-repeat="bind in config.HostConfig.Binds">
|
||||||
<div class="form-group form-inline">
|
<div class="form-group form-inline">
|
||||||
<input type="text" ng-model="bind.name" class="form-control" placeholder="/host:/container"/>
|
<input type="text" ng-model="bind.name" class="form-control"
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.Binds, bind)">Remove</button>
|
placeholder="/host:/container"/>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.HostConfig.Binds, bind)">Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.Binds, {name: ''})">Add Bind</button>
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.Binds, {name: ''})">Add Bind
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Links:</label>
|
<label>Links:</label>
|
||||||
|
|
||||||
<div ng-repeat="link in config.HostConfig.Links">
|
<div ng-repeat="link in config.HostConfig.Links">
|
||||||
<div class="form-group form-inline">
|
<div class="form-group form-inline">
|
||||||
<input type="text" ng-model="link.name" class="form-control" placeholder="web:db">
|
<input type="text" ng-model="link.name" class="form-control"
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.Links, link)">Remove</button>
|
placeholder="web:db">
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.HostConfig.Links, link)">Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.Links, {name: ''})">Add Link</button>
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.Links, {name: ''})">Add Link
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Dns:</label>
|
<label>Dns:</label>
|
||||||
|
|
||||||
<div ng-repeat="entry in config.HostConfig.Dns">
|
<div ng-repeat="entry in config.HostConfig.Dns">
|
||||||
<div class="form-group form-inline">
|
<div class="form-group form-inline">
|
||||||
<input type="text" ng-model="entry.name" class="form-control" placeholder="8.8.8.8"/>
|
<input type="text" ng-model="entry.name" class="form-control"
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.Dns, entry)">Remove</button>
|
placeholder="8.8.8.8"/>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.HostConfig.Dns, entry)">Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.Dns, {name: ''})">Add entry</button>
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.Dns, {name: ''})">Add entry
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>DnsSearch:</label>
|
<label>DnsSearch:</label>
|
||||||
|
|
||||||
<div ng-repeat="entry in config.HostConfig.DnsSearch">
|
<div ng-repeat="entry in config.HostConfig.DnsSearch">
|
||||||
<div class="form-group form-inline">
|
<div class="form-group form-inline">
|
||||||
<input type="text" ng-model="entry.name" class="form-control" placeholder="example.com"/>
|
<input type="text" ng-model="entry.name" class="form-control"
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.DnsSearch, entry)">Remove</button>
|
placeholder="example.com"/>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.HostConfig.DnsSearch, entry)">
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.DnsSearch, {name: ''})">Add entry</button>
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.DnsSearch, {name: ''})">Add
|
||||||
|
entry
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>CapAdd:</label>
|
<label>CapAdd:</label>
|
||||||
|
|
||||||
<div ng-repeat="entry in config.HostConfig.CapAdd">
|
<div ng-repeat="entry in config.HostConfig.CapAdd">
|
||||||
<div class="form-group form-inline">
|
<div class="form-group form-inline">
|
||||||
<input type="text" ng-model="entry.name" class="form-control" placeholder="cap_sys_admin"/>
|
<input type="text" ng-model="entry.name" class="form-control"
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.CapAdd, entry)">Remove</button>
|
placeholder="cap_sys_admin"/>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.HostConfig.CapAdd, entry)">Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.CapAdd, {name: ''})">Add entry</button>
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.CapAdd, {name: ''})">Add entry
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>CapDrop:</label>
|
<label>CapDrop:</label>
|
||||||
|
|
||||||
<div ng-repeat="entry in config.HostConfig.CapDrop">
|
<div ng-repeat="entry in config.HostConfig.CapDrop">
|
||||||
<div class="form-group form-inline">
|
<div class="form-group form-inline">
|
||||||
<input type="text" ng-model="entry.name" class="form-control" placeholder="cap_sys_admin"/>
|
<input type="text" ng-model="entry.name" class="form-control"
|
||||||
<button type="button" class="btn btn-danger btn-sm" ng-click="rmEntry(config.HostConfig.CapDrop, entry)">Remove</button>
|
placeholder="cap_sys_admin"/>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm"
|
||||||
|
ng-click="rmEntry(config.HostConfig.CapDrop, entry)">Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.CapDrop, {name: ''})">Add entry</button>
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.CapDrop, {name: ''})">Add entry
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>NetworkMode:</label>
|
<label>NetworkMode:</label>
|
||||||
<input type="text" ng-model="config.HostConfig.NetworkMode" class="form-control" placeholder="bridge"/>
|
<input type="text" ng-model="config.HostConfig.NetworkMode"
|
||||||
|
class="form-control" placeholder="bridge"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="publishAllPorts">PublishAllPorts:</label>
|
<label for="publishAllPorts">PublishAllPorts:</label>
|
||||||
<input id="publishAllPorts" type="checkbox" ng-model="config.HostConfig.PublishAllPorts"/>
|
<input id="publishAllPorts" type="checkbox"
|
||||||
|
ng-model="config.HostConfig.PublishAllPorts"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="privileged">Privileged:</label>
|
<label for="privileged">Privileged:</label>
|
||||||
<input id="privileged" type="checkbox" ng-model="config.HostConfig.Privileged"/>
|
<input id="privileged" type="checkbox"
|
||||||
|
ng-model="config.HostConfig.Privileged"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>VolumesFrom:</label>
|
<label>VolumesFrom:</label>
|
||||||
|
|
||||||
<div ng-repeat="volume in config.HostConfig.VolumesFrom">
|
<div ng-repeat="volume in config.HostConfig.VolumesFrom">
|
||||||
<div class="form-group form-inline">
|
<div class="form-group form-inline">
|
||||||
<select ng-model="volume.name" ng-options="name for name in containerNames track by name" class="form-control"/>
|
<select ng-model="volume.name"
|
||||||
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.HostConfig.VolumesFrom, volume)">Remove</button>
|
ng-options="name for name in containerNames track by name"
|
||||||
|
class="form-control"/>
|
||||||
|
<button class="btn btn-danger btn-xs form-control"
|
||||||
|
ng-click="rmEntry(config.HostConfig.VolumesFrom, volume)">
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.VolumesFrom, {name: ''})">Add volume</button>
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.VolumesFrom, {name: ''})">Add
|
||||||
|
volume
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -221,82 +297,118 @@
|
||||||
<option value="on-failure">on-failure</option>
|
<option value="on-failure">on-failure</option>
|
||||||
</select>
|
</select>
|
||||||
<label>MaximumRetryCount:</label>
|
<label>MaximumRetryCount:</label>
|
||||||
<input type="number" ng-model="config.HostConfig.RestartPolicy.MaximumRetryCount"/>
|
<input type="number"
|
||||||
|
ng-model="config.HostConfig.RestartPolicy.MaximumRetryCount"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>ExtraHosts:</label>
|
<label>ExtraHosts:</label>
|
||||||
|
|
||||||
<div ng-repeat="entry in config.HostConfig.ExtraHosts">
|
<div ng-repeat="entry in config.HostConfig.ExtraHosts">
|
||||||
<div class="form-group form-inline">
|
<div class="form-group form-inline">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="sr-only">Hostname:</label>
|
<label class="sr-only">Hostname:</label>
|
||||||
<input type="text" ng-model="entry.host" class="form-control" placeholder="hostname"/>
|
<input type="text" ng-model="entry.host" class="form-control"
|
||||||
|
placeholder="hostname"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="sr-only">IP Address:</label>
|
<label class="sr-only">IP Address:</label>
|
||||||
<input type="text" ng-model="entry.ip" class="form-control" placeholder="127.0.0.1"/>
|
<input type="text" ng-model="entry.ip" class="form-control"
|
||||||
|
placeholder="127.0.0.1"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.HostConfig.ExtraHosts, entry)">Remove</button>
|
<button class="btn btn-danger btn-xs form-control"
|
||||||
|
ng-click="rmEntry(config.HostConfig.ExtraHosts, entry)">Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.ExtraHosts, {host: '', ip: ''})">Add extra host</button>
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.ExtraHosts, {host: '', ip: ''})">Add
|
||||||
|
extra host
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>LxcConf:</label>
|
<label>LxcConf:</label>
|
||||||
|
|
||||||
<div ng-repeat="entry in config.HostConfig.LxcConf">
|
<div ng-repeat="entry in config.HostConfig.LxcConf">
|
||||||
<div class="form-group form-inline">
|
<div class="form-group form-inline">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="sr-only">Name:</label>
|
<label class="sr-only">Name:</label>
|
||||||
<input type="text" ng-model="entry.name" class="form-control" placeholder="lxc.utsname"/>
|
<input type="text" ng-model="entry.name" class="form-control"
|
||||||
|
placeholder="lxc.utsname"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="sr-only">Value:</label>
|
<label class="sr-only">Value:</label>
|
||||||
<input type="text" ng-model="entry.value" class="form-control" placeholder="docker"/>
|
<input type="text" ng-model="entry.value" class="form-control"
|
||||||
|
placeholder="docker"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.HostConfig.LxcConf, entry)">Remove</button>
|
<button class="btn btn-danger btn-xs form-control"
|
||||||
|
ng-click="rmEntry(config.HostConfig.LxcConf, entry)">Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.LxcConf, {name: '', value: ''})">Add Entry</button>
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.LxcConf, {name: '', value: ''})">Add
|
||||||
|
Entry
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Devices:</label>
|
<label>Devices:</label>
|
||||||
|
|
||||||
<div ng-repeat="device in config.HostConfig.Devices">
|
<div ng-repeat="device in config.HostConfig.Devices">
|
||||||
<div class="form-group form-inline inline-four">
|
<div class="form-group form-inline inline-four">
|
||||||
<label class="sr-only">PathOnHost:</label>
|
<label class="sr-only">PathOnHost:</label>
|
||||||
<input type="text" ng-model="device.PathOnHost" class="form-control" placeholder="PathOnHost"/>
|
<input type="text" ng-model="device.PathOnHost" class="form-control"
|
||||||
|
placeholder="PathOnHost"/>
|
||||||
<label class="sr-only">PathInContainer:</label>
|
<label class="sr-only">PathInContainer:</label>
|
||||||
<input type="text" ng-model="device.PathInContainer" class="form-control" placeholder="PathInContainer"/>
|
<input type="text" ng-model="device.PathInContainer" class="form-control"
|
||||||
|
placeholder="PathInContainer"/>
|
||||||
<label class="sr-only">CgroupPermissions:</label>
|
<label class="sr-only">CgroupPermissions:</label>
|
||||||
<input type="text" ng-model="device.CgroupPermissions" class="form-control" placeholder="CgroupPermissions"/>
|
<input type="text" ng-model="device.CgroupPermissions" class="form-control"
|
||||||
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.HostConfig.Devices, device)">Remove</button>
|
placeholder="CgroupPermissions"/>
|
||||||
|
<button class="btn btn-danger btn-xs form-control"
|
||||||
|
ng-click="rmEntry(config.HostConfig.Devices, device)">Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.Devices, { PathOnHost: '', PathInContainer: '', CgroupPermissions: ''})">Add Device</button>
|
<button type="button" class="btn btn-success btn-sm"
|
||||||
|
ng-click="addEntry(config.HostConfig.Devices, { PathOnHost: '', PathInContainer: '', CgroupPermissions: ''})">
|
||||||
|
Add Device
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>PortBindings:</label>
|
<label>PortBindings:</label>
|
||||||
|
|
||||||
<div ng-repeat="portBinding in config.HostConfig.PortBindings">
|
<div ng-repeat="portBinding in config.HostConfig.PortBindings">
|
||||||
<div class="form-group form-inline inline-four">
|
<div class="form-group form-inline inline-four">
|
||||||
<label class="sr-only">Host IP:</label>
|
<label class="sr-only">Host IP:</label>
|
||||||
<input type="text" ng-model="portBinding.ip" class="form-control" placeholder="Host IP Address"/>
|
<input type="text" ng-model="portBinding.ip" class="form-control"
|
||||||
|
placeholder="Host IP Address"/>
|
||||||
<label class="sr-only">Host Port:</label>
|
<label class="sr-only">Host Port:</label>
|
||||||
<input type="text" ng-model="portBinding.extPort" class="form-control" placeholder="Host Port"/>
|
<input type="text" ng-model="portBinding.extPort" class="form-control"
|
||||||
|
placeholder="Host Port"/>
|
||||||
<label class="sr-only">Container port:</label>
|
<label class="sr-only">Container port:</label>
|
||||||
<input type="text" ng-model="portBinding.intPort" class="form-control" placeholder="Container Port"/>
|
<input type="text" ng-model="portBinding.intPort" class="form-control"
|
||||||
|
placeholder="Container Port"/>
|
||||||
<select ng-model="portBinding.protocol">
|
<select ng-model="portBinding.protocol">
|
||||||
<option value="">tcp</option>
|
<option value="">tcp</option>
|
||||||
<option value="udp">udp</option>
|
<option value="udp">udp</option>
|
||||||
</select>
|
</select>
|
||||||
<button class="btn btn-danger btn-xs form-control" ng-click="rmEntry(config.HostConfig.PortBindings, portBinding)">Remove</button>
|
<button class="btn btn-danger btn-xs form-control"
|
||||||
|
ng-click="rmEntry(config.HostConfig.PortBindings, portBinding)">
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success btn-sm" ng-click="addEntry(config.HostConfig.PortBindings, {ip: '', extPort: '', intPort: ''})">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>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</accordion-group>
|
</accordion-group>
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<h1>Stats</h1>
|
||||||
|
|
||||||
|
<h2>CPU</h2>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-7">
|
||||||
|
<canvas id="cpu-stats-chart" width="650" height="300"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Memory</h2>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-7">
|
||||||
|
<canvas id="memory-stats-chart" width="650" height="300"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-offset-1 col-sm-4">
|
||||||
|
<table class="table">
|
||||||
|
<tr>
|
||||||
|
<td>Max usage</td>
|
||||||
|
<td>{{ data.memory_stats.max_usage | humansize }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Limit</td>
|
||||||
|
<td>{{ data.memory_stats.limit | humansize }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Fail count</td>
|
||||||
|
<td>{{ data.memory_stats.failcnt }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<accordion>
|
||||||
|
<accordion-group heading="Other stats">
|
||||||
|
<table class="table">
|
||||||
|
<tr ng-repeat="(key, value) in data.memory_stats.stats">
|
||||||
|
<td>{{ key }}</td>
|
||||||
|
<td>{{ value }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</accordion-group>
|
||||||
|
</accordion>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1>Network</h1>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-7">
|
||||||
|
<canvas id="network-stats-chart" width="650" height="300"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-offset-1 col-sm-4">
|
||||||
|
<div id="network-legend" style="margin-bottom: 20px;"></div>
|
||||||
|
<accordion>
|
||||||
|
<accordion-group heading="Other stats">
|
||||||
|
<table class="table">
|
||||||
|
<tr ng-repeat="(key, value) in data.network">
|
||||||
|
<td>{{ key }}</td>
|
||||||
|
<td>{{ value }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</accordion-group>
|
||||||
|
</accordion>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,187 @@
|
||||||
|
angular.module('stats', [])
|
||||||
|
.controller('StatsController', ['Settings', '$scope', 'Messages', '$timeout', 'Container', '$routeParams', 'humansizeFilter', '$sce', function (Settings, $scope, Messages, $timeout, Container, $routeParams, humansizeFilter, $sce) {
|
||||||
|
// TODO: Implement memory chart, force scale to 0-100 for cpu, 0 to limit for memory, fix charts on dashboard,
|
||||||
|
// TODO: Force memory scale to 0 - max memory
|
||||||
|
//var initialStats = {}; // Used to set scale of memory graph.
|
||||||
|
//
|
||||||
|
//Container.stats({id: $routeParams.id}, function (d) {
|
||||||
|
// var arr = Object.keys(d).map(function (key) {
|
||||||
|
// return d[key];
|
||||||
|
// });
|
||||||
|
// if (arr.join('').indexOf('no such id') !== -1) {
|
||||||
|
// Messages.error('Unable to retrieve stats', 'Is this container running?');
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// initialStats = d;
|
||||||
|
//}, function () {
|
||||||
|
// Messages.error('Unable to retrieve stats', 'Is this container running?');
|
||||||
|
//});
|
||||||
|
|
||||||
|
var cpuLabels = [];
|
||||||
|
var cpuData = [];
|
||||||
|
var memoryLabels = [];
|
||||||
|
var memoryData = [];
|
||||||
|
var networkLabels = [];
|
||||||
|
var networkTxData = [];
|
||||||
|
var networkRxData = [];
|
||||||
|
for (var i = 0; i < 20; i++) {
|
||||||
|
cpuLabels.push('');
|
||||||
|
cpuData.push(0);
|
||||||
|
memoryLabels.push('');
|
||||||
|
memoryData.push(0);
|
||||||
|
networkLabels.push('');
|
||||||
|
networkTxData.push(0);
|
||||||
|
networkRxData.push(0);
|
||||||
|
}
|
||||||
|
var cpuDataset = { // CPU Usage
|
||||||
|
fillColor: "rgba(151,187,205,0.5)",
|
||||||
|
strokeColor: "rgba(151,187,205,1)",
|
||||||
|
pointColor: "rgba(151,187,205,1)",
|
||||||
|
pointStrokeColor: "#fff",
|
||||||
|
data: cpuData
|
||||||
|
};
|
||||||
|
var memoryDataset = {
|
||||||
|
fillColor: "rgba(151,187,205,0.5)",
|
||||||
|
strokeColor: "rgba(151,187,205,1)",
|
||||||
|
pointColor: "rgba(151,187,205,1)",
|
||||||
|
pointStrokeColor: "#fff",
|
||||||
|
data: memoryData
|
||||||
|
};
|
||||||
|
var networkRxDataset = {
|
||||||
|
label: "Rx Bytes",
|
||||||
|
fillColor: "rgba(151,187,205,0.5)",
|
||||||
|
strokeColor: "rgba(151,187,205,1)",
|
||||||
|
pointColor: "rgba(151,187,205,1)",
|
||||||
|
pointStrokeColor: "#fff",
|
||||||
|
data: networkRxData
|
||||||
|
};
|
||||||
|
var networkTxDataset = {
|
||||||
|
label: "Tx Bytes",
|
||||||
|
fillColor: "rgba(255,180,174,0.5)",
|
||||||
|
strokeColor: "rgba(255,180,174,1)",
|
||||||
|
pointColor: "rgba(255,180,174,1)",
|
||||||
|
pointStrokeColor: "#fff",
|
||||||
|
data: networkTxData
|
||||||
|
};
|
||||||
|
var networkLegendData = [
|
||||||
|
{
|
||||||
|
//value: '',
|
||||||
|
color: 'rgba(151,187,205,0.5)',
|
||||||
|
title: 'Rx Data'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//value: '',
|
||||||
|
color: 'rgba(255,180,174,0.5)',
|
||||||
|
title: 'Rx Data'
|
||||||
|
}];
|
||||||
|
legend($('#network-legend').get(0), networkLegendData);
|
||||||
|
|
||||||
|
Chart.defaults.global.animationSteps = 30; // Lower from 60 to ease CPU load.
|
||||||
|
var cpuChart = new Chart($('#cpu-stats-chart').get(0).getContext("2d")).Line({
|
||||||
|
labels: cpuLabels,
|
||||||
|
datasets: [cpuDataset]
|
||||||
|
}, {
|
||||||
|
responsive: true
|
||||||
|
});
|
||||||
|
|
||||||
|
var memoryChart = new Chart($('#memory-stats-chart').get(0).getContext('2d')).Line({
|
||||||
|
labels: memoryLabels,
|
||||||
|
datasets: [memoryDataset]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scaleLabel: function (valueObj) {
|
||||||
|
return humansizeFilter(parseInt(valueObj.value, 10));
|
||||||
|
},
|
||||||
|
responsive: true
|
||||||
|
//scaleOverride: true,
|
||||||
|
//scaleSteps: 10,
|
||||||
|
//scaleStepWidth: Math.ceil(initialStats.memory_stats.limit / 10),
|
||||||
|
//scaleStartValue: 0
|
||||||
|
});
|
||||||
|
var networkChart = new Chart($('#network-stats-chart').get(0).getContext("2d")).Line({
|
||||||
|
labels: networkLabels,
|
||||||
|
datasets: [networkRxDataset, networkTxDataset]
|
||||||
|
}, {
|
||||||
|
scaleLabel: function (valueObj) {
|
||||||
|
return humansizeFilter(parseInt(valueObj.value, 10));
|
||||||
|
},
|
||||||
|
responsive: true
|
||||||
|
});
|
||||||
|
$scope.networkLegend = $sce.trustAsHtml(networkChart.generateLegend());
|
||||||
|
|
||||||
|
function updateStats() {
|
||||||
|
Container.stats({id: $routeParams.id}, function (d) {
|
||||||
|
var arr = Object.keys(d).map(function (key) {
|
||||||
|
return d[key];
|
||||||
|
});
|
||||||
|
if (arr.join('').indexOf('no such id') !== -1) {
|
||||||
|
Messages.error('Unable to retrieve stats', 'Is this container running?');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update graph with latest data
|
||||||
|
$scope.data = d;
|
||||||
|
updateCpuChart(d);
|
||||||
|
updateMemoryChart(d);
|
||||||
|
updateNetworkChart(d);
|
||||||
|
timeout = $timeout(updateStats, 2000);
|
||||||
|
}, function () {
|
||||||
|
Messages.error('Unable to retrieve stats', 'Is this container running?');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeout;
|
||||||
|
$scope.$on('$destroy', function () {
|
||||||
|
$timeout.cancel(timeout);
|
||||||
|
});
|
||||||
|
|
||||||
|
updateStats();
|
||||||
|
|
||||||
|
function updateCpuChart(data) {
|
||||||
|
console.log('updateCpuChart', data);
|
||||||
|
cpuChart.addData([calculateCPUPercent(data)], new Date(data.read).toLocaleTimeString());
|
||||||
|
cpuChart.removeData();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMemoryChart(data) {
|
||||||
|
console.log('updateMemoryChart', data);
|
||||||
|
memoryChart.addData([data.memory_stats.usage], new Date(data.read).toLocaleTimeString());
|
||||||
|
memoryChart.removeData();
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastRxBytes = 0, lastTxBytes = 0;
|
||||||
|
|
||||||
|
function updateNetworkChart(data) {
|
||||||
|
var rxBytes = 0, txBytes = 0;
|
||||||
|
if (lastRxBytes !== 0 || lastTxBytes !== 0) {
|
||||||
|
// These will be zero on first call, ignore to prevent large graph spike
|
||||||
|
rxBytes = data.network.rx_bytes - lastRxBytes;
|
||||||
|
txBytes = data.network.tx_bytes - lastTxBytes;
|
||||||
|
}
|
||||||
|
lastRxBytes = data.network.rx_bytes;
|
||||||
|
lastTxBytes = data.network.tx_bytes;
|
||||||
|
console.log('updateNetworkChart', data);
|
||||||
|
networkChart.addData([rxBytes, txBytes], new Date(data.read).toLocaleTimeString());
|
||||||
|
networkChart.removeData();
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateCPUPercent(stats) {
|
||||||
|
// Same algorithm the official client uses: https://github.com/docker/docker/blob/master/api/client/stats.go#L195-L208
|
||||||
|
var prevCpu = stats.precpu_stats;
|
||||||
|
var curCpu = stats.cpu_stats;
|
||||||
|
|
||||||
|
var cpuPercent = 0.0;
|
||||||
|
|
||||||
|
// calculate the change for the cpu usage of the container in between readings
|
||||||
|
var cpuDelta = curCpu.cpu_usage.total_usage - prevCpu.cpu_usage.total_usage;
|
||||||
|
// calculate the change for the entire system between readings
|
||||||
|
var systemDelta = curCpu.system_cpu_usage - prevCpu.system_cpu_usage;
|
||||||
|
|
||||||
|
if (systemDelta > 0.0 && cpuDelta > 0.0) {
|
||||||
|
//console.log('size thing:', curCpu.cpu_usage.percpu_usage);
|
||||||
|
cpuPercent = (cpuDelta / systemDelta) * curCpu.cpu_usage.percpu_usage.length * 100.0;
|
||||||
|
}
|
||||||
|
return cpuPercent;
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
;
|
|
@ -71,7 +71,9 @@ angular.module('dockerui.filters', [])
|
||||||
return 'n/a';
|
return 'n/a';
|
||||||
}
|
}
|
||||||
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
|
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
|
||||||
return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[[i]];
|
var value = bytes / Math.pow(1024, i);
|
||||||
|
var decimalPlaces = (i < 1) ? 0 : (i - 1);
|
||||||
|
return value.toFixed(decimalPlaces) + ' ' + sizes[[i]];
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter('containername', function () {
|
.filter('containername', function () {
|
||||||
|
@ -86,7 +88,9 @@ angular.module('dockerui.filters', [])
|
||||||
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 '';
|
||||||
|
|
|
@ -2,7 +2,7 @@ angular.module('dockerui.services', ['ngResource'])
|
||||||
.factory('Container', function ($resource, Settings) {
|
.factory('Container', function ($resource, Settings) {
|
||||||
'use strict';
|
'use strict';
|
||||||
// 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.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#2-1-containers
|
||||||
return $resource(Settings.url + '/containers/:id/:action', {
|
return $resource(Settings.url + '/containers/:id/:action', {
|
||||||
name: '@name'
|
name: '@name'
|
||||||
}, {
|
}, {
|
||||||
|
@ -17,11 +17,13 @@ angular.module('dockerui.services', ['ngResource'])
|
||||||
changes: {method: 'GET', params: {action: 'changes'}, isArray: true},
|
changes: {method: 'GET', params: {action: 'changes'}, isArray: true},
|
||||||
create: {method: 'POST', params: {action: 'create'}},
|
create: {method: 'POST', params: {action: 'create'}},
|
||||||
remove: {method: 'DELETE', params: {id: '@id', v: 0}},
|
remove: {method: 'DELETE', params: {id: '@id', v: 0}},
|
||||||
rename: {method: 'POST', params: {id: '@id', action: 'rename'}, isArray: false}
|
rename: {method: 'POST', params: {id: '@id', action: 'rename'}, isArray: false},
|
||||||
|
stats: {method: 'GET', params: {id: '@id', stream: false, action: 'stats'}, timeout: 2000}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.factory('ContainerCommit', function ($resource, $http, Settings) {
|
.factory('ContainerCommit', function ($resource, $http, Settings) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#create-a-new-image-from-a-container-s-changes
|
||||||
return {
|
return {
|
||||||
commit: function (params, callback) {
|
commit: function (params, callback) {
|
||||||
$http({
|
$http({
|
||||||
|
@ -39,6 +41,7 @@ angular.module('dockerui.services', ['ngResource'])
|
||||||
})
|
})
|
||||||
.factory('ContainerLogs', function ($resource, $http, Settings) {
|
.factory('ContainerLogs', function ($resource, $http, Settings) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#get-container-logs
|
||||||
return {
|
return {
|
||||||
get: function (id, params, callback) {
|
get: function (id, params, callback) {
|
||||||
$http({
|
$http({
|
||||||
|
@ -58,6 +61,7 @@ angular.module('dockerui.services', ['ngResource'])
|
||||||
})
|
})
|
||||||
.factory('ContainerTop', function ($http, Settings) {
|
.factory('ContainerTop', function ($http, Settings) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#list-processes-running-inside-a-container
|
||||||
return {
|
return {
|
||||||
get: function (id, params, callback, errorCallback) {
|
get: function (id, params, callback, errorCallback) {
|
||||||
$http({
|
$http({
|
||||||
|
@ -72,18 +76,19 @@ angular.module('dockerui.services', ['ngResource'])
|
||||||
})
|
})
|
||||||
.factory('Image', function ($resource, Settings) {
|
.factory('Image', function ($resource, Settings) {
|
||||||
'use strict';
|
'use strict';
|
||||||
// Resource for docker images
|
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#2-2-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', isArray: true, transformResponse: [function f(data) {
|
create: {
|
||||||
|
method: 'POST', isArray: true, transformResponse: [function f(data) {
|
||||||
var str = data.replace(/\n/g, " ").replace(/\}\W*\{/g, "}, {");
|
var str = data.replace(/\n/g, " ").replace(/\}\W*\{/g, "}, {");
|
||||||
return angular.fromJson("[" + str + "]");
|
return angular.fromJson("[" + str + "]");
|
||||||
}],
|
}],
|
||||||
params: {action: 'create', fromImage: '@fromImage', repo: '@repo', tag: '@tag', registry: '@registry'}},
|
params: {action: 'create', fromImage: '@fromImage', repo: '@repo', tag: '@tag', registry: '@registry'}
|
||||||
|
},
|
||||||
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'}},
|
||||||
|
@ -92,16 +97,14 @@ angular.module('dockerui.services', ['ngResource'])
|
||||||
})
|
})
|
||||||
.factory('Docker', function ($resource, Settings) {
|
.factory('Docker', function ($resource, Settings) {
|
||||||
'use strict';
|
'use strict';
|
||||||
// Information for docker
|
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#show-the-docker-version-information
|
||||||
// http://docs.docker.io/en/latest/api/docker_remote_api.html#display-system-wide-information
|
|
||||||
return $resource(Settings.url + '/version', {}, {
|
return $resource(Settings.url + '/version', {}, {
|
||||||
get: {method: 'GET'}
|
get: {method: 'GET'}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.factory('Auth', function ($resource, Settings) {
|
.factory('Auth', function ($resource, Settings) {
|
||||||
'use strict';
|
'use strict';
|
||||||
// Auto Information for docker
|
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#check-auth-configuration
|
||||||
// http://docs.docker.io/en/latest/api/docker_remote_api.html#set-auth-configuration
|
|
||||||
return $resource(Settings.url + '/auth', {}, {
|
return $resource(Settings.url + '/auth', {}, {
|
||||||
get: {method: 'GET'},
|
get: {method: 'GET'},
|
||||||
update: {method: 'POST'}
|
update: {method: 'POST'}
|
||||||
|
@ -109,8 +112,7 @@ angular.module('dockerui.services', ['ngResource'])
|
||||||
})
|
})
|
||||||
.factory('System', function ($resource, Settings) {
|
.factory('System', function ($resource, Settings) {
|
||||||
'use strict';
|
'use strict';
|
||||||
// System for docker
|
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#display-system-wide-information
|
||||||
// http://docs.docker.io/en/latest/api/docker_remote_api.html#display-system-wide-information
|
|
||||||
return $resource(Settings.url + '/info', {}, {
|
return $resource(Settings.url + '/info', {}, {
|
||||||
get: {method: 'GET'}
|
get: {method: 'GET'}
|
||||||
});
|
});
|
||||||
|
@ -176,6 +178,7 @@ angular.module('dockerui.services', ['ngResource'])
|
||||||
})
|
})
|
||||||
.factory('Dockerfile', function (Settings) {
|
.factory('Dockerfile', function (Settings) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
// http://docs.docker.com/reference/api/docker_remote_api_<%= remoteApiVersion %>/#build-image-from-a-dockerfile
|
||||||
var url = Settings.rawUrl + '/build';
|
var url = Settings.rawUrl + '/build';
|
||||||
return {
|
return {
|
||||||
build: function (file, callback) {
|
build: function (file, callback) {
|
||||||
|
@ -192,7 +195,6 @@ angular.module('dockerui.services', ['ngResource'])
|
||||||
})
|
})
|
||||||
.factory('LineChart', function (Settings) {
|
.factory('LineChart', function (Settings) {
|
||||||
'use strict';
|
'use strict';
|
||||||
var url = Settings.rawUrl + '/build';
|
|
||||||
return {
|
return {
|
||||||
build: function (id, data, getkey) {
|
build: function (id, data, getkey) {
|
||||||
var chart = new Chart($(id).get(0).getContext("2d"));
|
var chart = new Chart($(id).get(0).getContext("2d"));
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
function ImageViewModel(data) {
|
function ImageViewModel(data) {
|
||||||
this.Id = data.Id;
|
this.Id = data.Id;
|
||||||
this.Tag = data.Tag;
|
this.Tag = data.Tag;
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -31,8 +31,8 @@ module.exports = function (grunt) {
|
||||||
grunt.initConfig({
|
grunt.initConfig({
|
||||||
distdir: 'dist',
|
distdir: 'dist',
|
||||||
pkg: grunt.file.readJSON('package.json'),
|
pkg: grunt.file.readJSON('package.json'),
|
||||||
banner:
|
remoteApiVersion: 'v1.20',
|
||||||
'/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' +
|
banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' +
|
||||||
'<%= pkg.homepage ? " * " + pkg.homepage + "\\n" : "" %>' +
|
'<%= pkg.homepage ? " * " + pkg.homepage + "\\n" : "" %>' +
|
||||||
' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>;\n' +
|
' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>;\n' +
|
||||||
' * Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %>\n */\n',
|
' * Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %>\n */\n',
|
||||||
|
@ -108,8 +108,8 @@ module.exports = function (grunt) {
|
||||||
recess: {
|
recess: {
|
||||||
build: {
|
build: {
|
||||||
files: {
|
files: {
|
||||||
'<%= distdir %>/<%= pkg.name %>.css':
|
'<%= distdir %>/<%= pkg.name %>.css': ['<%= src.css %>']
|
||||||
['<%= src.css %>'] },
|
},
|
||||||
options: {
|
options: {
|
||||||
compile: true,
|
compile: true,
|
||||||
noOverqualifying: false // TODO: Added because of .nav class, rename
|
noOverqualifying: false // TODO: Added because of .nav class, rename
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"author": "Michael Crosby & Kevan Ahlquist",
|
"author": "Michael Crosby & Kevan Ahlquist",
|
||||||
"name": "dockerui",
|
"name": "dockerui",
|
||||||
"homepage": "https://github.com/crosbymichael/dockerui",
|
"homepage": "https://github.com/crosbymichael/dockerui",
|
||||||
"version": "0.6.0",
|
"version": "0.8.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git@github.com:crosbymichael/dockerui.git"
|
"url": "git@github.com:crosbymichael/dockerui.git"
|
||||||
|
|
|
@ -34,6 +34,7 @@ describe('startContainerController', function() {
|
||||||
'Status': 'Up 2 minutes'
|
'Status': 'Up 2 minutes'
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Create and start a container with port bindings', function () {
|
describe('Create and start a container with port bindings', function () {
|
||||||
it('should issue a correct create request to the Docker remote API', function () {
|
it('should issue a correct create request to the Docker remote API', function () {
|
||||||
var controller = createController();
|
var controller = createController();
|
||||||
|
@ -154,7 +155,11 @@ describe('startContainerController', function() {
|
||||||
DnsSearch: ['example.com'],
|
DnsSearch: ['example.com'],
|
||||||
CapAdd: ['cap_sys_admin'],
|
CapAdd: ['cap_sys_admin'],
|
||||||
CapDrop: ['cap_foo_bar'],
|
CapDrop: ['cap_foo_bar'],
|
||||||
Devices: [{ 'PathOnHost': '/dev/deviceName', 'PathInContainer': '/dev/deviceName', 'CgroupPermissions': 'mrw'}],
|
Devices: [{
|
||||||
|
'PathOnHost': '/dev/deviceName',
|
||||||
|
'PathInContainer': '/dev/deviceName',
|
||||||
|
'CgroupPermissions': 'mrw'
|
||||||
|
}],
|
||||||
LxcConf: {'lxc.utsname': 'docker'},
|
LxcConf: {'lxc.utsname': 'docker'},
|
||||||
ExtraHosts: ['hostname:127.0.0.1'],
|
ExtraHosts: ['hostname:127.0.0.1'],
|
||||||
RestartPolicy: {name: 'always', MaximumRetryCount: 5}
|
RestartPolicy: {name: 'always', MaximumRetryCount: 5}
|
||||||
|
@ -190,7 +195,11 @@ describe('startContainerController', function() {
|
||||||
scope.config.HostConfig.PublishAllPorts = true;
|
scope.config.HostConfig.PublishAllPorts = true;
|
||||||
scope.config.HostConfig.Privileged = true;
|
scope.config.HostConfig.Privileged = true;
|
||||||
scope.config.HostConfig.RestartPolicy = {name: 'always', MaximumRetryCount: 5};
|
scope.config.HostConfig.RestartPolicy = {name: 'always', MaximumRetryCount: 5};
|
||||||
scope.config.HostConfig.Devices = [{ 'PathOnHost': '/dev/deviceName', 'PathInContainer': '/dev/deviceName', 'CgroupPermissions': 'mrw'}];
|
scope.config.HostConfig.Devices = [{
|
||||||
|
'PathOnHost': '/dev/deviceName',
|
||||||
|
'PathInContainer': '/dev/deviceName',
|
||||||
|
'CgroupPermissions': 'mrw'
|
||||||
|
}];
|
||||||
scope.config.HostConfig.LxcConf = [{name: 'lxc.utsname', value: 'docker'}];
|
scope.config.HostConfig.LxcConf = [{name: 'lxc.utsname', value: 'docker'}];
|
||||||
scope.config.HostConfig.ExtraHosts = [{host: 'hostname', ip: '127.0.0.1'}];
|
scope.config.HostConfig.ExtraHosts = [{host: 'hostname', ip: '127.0.0.1'}];
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
describe("StatsController", function () {
|
||||||
|
var $scope, $httpBackend, $routeParams;
|
||||||
|
|
||||||
|
beforeEach(angular.mock.module('dockerui'));
|
||||||
|
|
||||||
|
beforeEach(inject(function (_$rootScope_, _$httpBackend_, $controller, _$routeParams_) {
|
||||||
|
$scope = _$rootScope_.$new();
|
||||||
|
$httpBackend = _$httpBackend_;
|
||||||
|
$routeParams = _$routeParams_;
|
||||||
|
$routeParams.id = 'b17882378cee8ec0136f482681b764cca430befd52a9bfd1bde031f49b8bba9f';
|
||||||
|
$controller('StatsController', {
|
||||||
|
'$scope': $scope,
|
||||||
|
'$routeParams': $routeParams
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
//it("should test controller initialize", function () {
|
||||||
|
// $httpBackend.expectGET('dockerapi/containers/b17882378cee8ec0136f482681b764cca430befd52a9bfd1bde031f49b8bba9f/stats?stream=false').respond(200);
|
||||||
|
// //expect($scope.ps_args).toBeDefined();
|
||||||
|
// $httpBackend.flush();
|
||||||
|
//});
|
||||||
|
//
|
||||||
|
//it("a correct top request to the Docker remote API", function () {
|
||||||
|
// //$httpBackend.expectGET('dockerapi/containers/' + $routeParams.id + '/top?ps_args=').respond(200);
|
||||||
|
// //$routeParams.id = '123456789123456789123456789';
|
||||||
|
// //$scope.ps_args = 'aux';
|
||||||
|
// //$httpBackend.expectGET('dockerapi/containers/' + $routeParams.id + '/top?ps_args=' + $scope.ps_args).respond(200);
|
||||||
|
// //$scope.getTop();
|
||||||
|
// //$httpBackend.flush();
|
||||||
|
//});
|
||||||
|
});
|
|
@ -106,19 +106,19 @@ describe('filters', function () {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should handle KB values', inject(function (humansizeFilter) {
|
it('should handle KB values', inject(function (humansizeFilter) {
|
||||||
expect(humansizeFilter(5120)).toBe('5 KB');
|
expect(humansizeFilter(5 * 1024)).toBe('5 KB');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should handle MB values', inject(function (humansizeFilter) {
|
it('should handle MB values', inject(function (humansizeFilter) {
|
||||||
expect(humansizeFilter(5 * Math.pow(10, 6))).toBe('5 MB');
|
expect(humansizeFilter(5 * 1024 * 1024)).toBe('5.0 MB');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should handle GB values', inject(function (humansizeFilter) {
|
it('should handle GB values', inject(function (humansizeFilter) {
|
||||||
expect(humansizeFilter(5 * Math.pow(10, 9))).toBe('5 GB');
|
expect(humansizeFilter(5 * 1024 * 1024 * 1024)).toBe('5.00 GB');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should handle TB values', inject(function (humansizeFilter) {
|
it('should handle TB values', inject(function (humansizeFilter) {
|
||||||
expect(humansizeFilter(5 * Math.pow(10, 12))).toBe('5 TB');
|
expect(humansizeFilter(5 * 1024 * 1024 * 1024 * 1024)).toBe('5.000 TB');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -157,7 +157,197 @@ describe('filters', function () {
|
||||||
describe('errorMsgFilter', function () {
|
describe('errorMsgFilter', function () {
|
||||||
it('should convert the $resource object to a string message',
|
it('should convert the $resource object to a string message',
|
||||||
inject(function (errorMsgFilter) {
|
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 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';
|
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);
|
expect(errorMsgFilter(response)).toBe(message);
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -9,6 +9,7 @@ files = [
|
||||||
'assets/js/jquery.gritter.min.js',
|
'assets/js/jquery.gritter.min.js',
|
||||||
'assets/js/bootstrap.min.js',
|
'assets/js/bootstrap.min.js',
|
||||||
'assets/js/spin.js',
|
'assets/js/spin.js',
|
||||||
|
'assets/js/Chart.min.js',
|
||||||
'dist/angular.js',
|
'dist/angular.js',
|
||||||
'assets/js/ui-bootstrap/ui-bootstrap-custom-tpls-0.12.0.min.js',
|
'assets/js/ui-bootstrap/ui-bootstrap-custom-tpls-0.12.0.min.js',
|
||||||
'assets/js/angular-vis.js',
|
'assets/js/angular-vis.js',
|
||||||
|
|
Loading…
Reference in New Issue