diff --git a/app/app.js b/app/app.js index d9a48daf6..7a4a4dbcc 100644 --- a/app/app.js +++ b/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) { 'use strict'; $routeProvider.when('/', { @@ -21,6 +21,10 @@ angular.module('dockerui', ['dockerui.templates', 'ngRoute', 'dockerui.services' templateUrl: 'app/components/containerTop/containerTop.html', controller: 'ContainerTopController' }); + $routeProvider.when('/containers/:id/stats', { + templateUrl: 'app/components/stats/stats.html', + controller: 'StatsController' + }); $routeProvider.when('/containers_network', { templateUrl: 'app/components/containersNetwork/containersNetwork.html', controller: 'ContainersNetworkController' diff --git a/app/components/container/container.html b/app/components/container/container.html index 8843449c2..9f45e92fc 100644 --- a/app/components/container/container.html +++ b/app/components/container/container.html @@ -133,6 +133,10 @@ Logs: stdout/stderr + + Stats: + stats + Top: Top diff --git a/app/components/stats/stats.html b/app/components/stats/stats.html new file mode 100644 index 000000000..365a931db --- /dev/null +++ b/app/components/stats/stats.html @@ -0,0 +1,21 @@ +
+
+

Stats

+ +
+ + + + + + + + + + +
Time readCPU usageStat
+ + +
+
+
diff --git a/app/components/stats/statsController.js b/app/components/stats/statsController.js new file mode 100644 index 000000000..4f620c33b --- /dev/null +++ b/app/components/stats/statsController.js @@ -0,0 +1,56 @@ +angular.module('stats', []) + .controller('StatsController', ['Settings', '$scope', 'Messages', '$timeout', 'Container', 'LineChart', '$routeParams', function (Settings, $scope, Messages, $timeout, Container, LineChart, $routeParams) { + var sessionKey = 'dockeruiStats-' + $routeParams.id; + var localData = sessionStorage.getItem(sessionKey); + if (localData) { + $scope.dockerStats = localData; + } else { + $scope.dockerStats = []; + } + + + function updateStats() { + Container.stats({id: $routeParams.id}, function (d) { + console.log(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 container stats', 'Has this container been removed?'); + return; + } + $scope.dockerStats.push(d); + sessionStorage.setItem(sessionKey, $scope.dockerStats); + $timeout(updateStats, 1000); + // Update graph with latest data + updateChart($scope.dockerStats); + }, function () { + Messages.error('Unable to retrieve container stats', 'Has this container been removed?'); + }); + } + + updateStats(); + + $scope.calculateCPUPercent = function (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) { + cpuPercent = (cpuDelta / systemDelta) * curCpu.cpu_usage.percpu_usage.size() * 100.0; + } + return cpuPercent + }; + + function updateChart(data) { + // TODO: Build data in the right format and create chart. + //LineChart.build('#cpu-stats-chart', $scope.dockerStats, function (d) { + // return $scope.calculateCPUPercent(d) + //}); + } + }]); \ No newline at end of file diff --git a/app/shared/services.js b/app/shared/services.js index a996e20cf..41c809342 100644 --- a/app/shared/services.js +++ b/app/shared/services.js @@ -17,7 +17,8 @@ angular.module('dockerui.services', ['ngResource']) changes: {method: 'GET', params: {action: 'changes'}, isArray: true}, create: {method: 'POST', params: {action: 'create'}}, 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'}} }); }) .factory('ContainerCommit', function ($resource, $http, Settings) { @@ -192,7 +193,6 @@ angular.module('dockerui.services', ['ngResource']) }) .factory('LineChart', function (Settings) { 'use strict'; - var url = Settings.rawUrl + '/build'; return { build: function (id, data, getkey) { var chart = new Chart($(id).get(0).getContext("2d")); diff --git a/test/unit/app/components/statsController.spec.js b/test/unit/app/components/statsController.spec.js new file mode 100644 index 000000000..c26aa06c3 --- /dev/null +++ b/test/unit/app/components/statsController.spec.js @@ -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(); + }); +}); \ No newline at end of file