Mercurial > hg > thermostat-ng > web-client
changeset 127:ef302144b90a
Client-Gateway integration
Reviewed-by: jerboaa
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-July/024095.html
line wrap: on
line diff
--- a/mock-api/endpoints/jvms.endpoint.js Wed Jul 12 13:56:56 2017 -0400 +++ b/mock-api/endpoints/jvms.endpoint.js Thu Jul 13 10:44:20 2017 -0400 @@ -20,22 +20,26 @@ 'jvms': [ { 'mainClass': 'c.r.t.A', - 'startTime': { $numberLong: '45000' }, + 'startTime': { $numberLong: (Date.now() - 10000000).toString() }, + 'stopTime': { $numberLong: '-1' }, 'jvmId': 'vm-0' }, { 'mainClass': 'c.r.t.B', - 'startTime': { $numberLong: '45000' }, + 'startTime': { $numberLong: (Date.now() - 1500000).toString() }, + 'stopTime': { $numberLong: '-1' }, 'jvmId': 'vm-1' }, { 'mainClass': 'c.r.t.C', - 'startTime': { $numberLong: '45000' }, + 'startTime': { $numberLong: (Date.now() - 25000000).toString() }, + 'stopTime': { $numberLong: '-1' }, 'jvmId': 'vm-2' }, { 'mainClass': 'c.r.t.D', - 'startTime': { $numberLong: '45000' }, + 'startTime': { $numberLong: (Date.now() - 350000000).toString() }, + 'stopTime': { $numberLong: Date.now().toString() }, 'jvmId': 'vm-3' } ] @@ -55,8 +59,8 @@ systemId: req.params.systemId, jvmId: req.params.jvmId, mainClass: 'c.r.t.A', - startTime: { $numberLong: (Date.now() - 5000000 + _.round(Math.random() * 1000000)).toString() }, - stopTime: { $numberLong: '-1' }, + startTime: Date.now() - 5000000 + _.round(Math.random() * 1000000), + stopTime: -1, isAlive: true, jvmPid: _.round(Math.random() * 2048) + 512, javaVersion: '1.9', @@ -77,9 +81,9 @@ value: 'bam' } ], - uid: { $numberLong: _.round(Math.random() * 800) }, + uid: _.floor(Math.random() * 800), username: 'thermostat-user', - lastUpdated: { $numberLong: Date.now().toString() } + lastUpdated: Date.now().toString() }] } ));
--- a/mock-api/endpoints/system-cpu.endpoint.js Wed Jul 12 13:56:56 2017 -0400 +++ b/mock-api/endpoints/system-cpu.endpoint.js Thu Jul 13 10:44:20 2017 -0400 @@ -1,14 +1,17 @@ function systemCpu (server) { var _ = require('lodash'); server.init('systemCpu'); - server.app.get('/system-info/cpu/:systemId', function (req, res, next) { + server.app.get('/system-cpu/0.0.1/systems/:systemId', function (req, res, next) { server.logRequest('system-info', req); res.setHeader('Content-Type', 'application/json'); + var randomUsage = function () { + return _.round(Math.random() * 100); + }; res.send(JSON.stringify( { - response: { - percent: _.round(Math.random() * 100) - } + response: [{ + perProcessorUsage: [randomUsage(), randomUsage(), randomUsage(), randomUsage()] + }] } )); next();
--- a/mock-api/endpoints/system-info.endpoint.js Wed Jul 12 13:56:56 2017 -0400 +++ b/mock-api/endpoints/system-info.endpoint.js Thu Jul 13 10:44:20 2017 -0400 @@ -1,19 +1,19 @@ function systemInfo (server) { server.init('systemInfo'); - server.app.get('/system-info/:systemId', function (req, res, next) { + server.app.get('/systems/0.0.1/systems/:systemId', function (req, res, next) { server.logRequest('system-info', req); res.setHeader('Content-Type', 'application/json'); res.send(JSON.stringify( { - response: { + response: [{ systemId: req.params.systemId, - hostName: req.params.systemId + '-host', + hostname: req.params.systemId + '-host', osName: 'Linux', osKernel: '4.10.11-200.fc25.x86_64', cpuCount: 4, cpuModel: 'GenuineIntel', - totalMemory: 16384 - } + totalMemory: 16 * 1024 * 1024 * 1024 + }] } )); next();
--- a/mock-api/endpoints/system-memory.endpoint.js Wed Jul 12 13:56:56 2017 -0400 +++ b/mock-api/endpoints/system-memory.endpoint.js Thu Jul 13 10:44:20 2017 -0400 @@ -20,7 +20,7 @@ var data = { systemId: systemId, agentId: 'mock-agentId', - timestamp: new Date().getTime(), + timeStamp: new Date().getTime(), total: 16384, free: _.round(Math.random() * (16384 / 4)), buffers: 16384 / 32,
--- a/src/app/components/jvm-info/jvm-info.html Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/components/jvm-info/jvm-info.html Thu Jul 13 10:44:20 2017 -0400 @@ -22,7 +22,7 @@ </tr> <tr> <td>UID</td> - <td>{{ctrl.jvmInfo.uid | metricToBigInt | bigIntToString }}</td> + <td>{{ctrl.jvmInfo.uid}}</td> </tr> <tr> <td>JVM ID</td> @@ -34,15 +34,15 @@ </tr> <tr> <td>Start Time</td> - <td>{{ctrl.jvmInfo.startTime | timestampToDate}}</td> + <td>{{ctrl.jvmInfo.startTime | date:"medium"}}</td> </tr> <tr ng-show="parseInt(ctrl.jvmInfo.endTime.$numberLong) > 0"> <td>Stop Time</td> - <td>{{ctrl.jvmInfo.stopTime | timestampToDate}}</td> + <td>{{ctrl.jvmInfo.stopTime | date:"medium"}}</td> </tr> <tr ng-show="ctrl.jvmInfo.lastUpdated"> <td>Last Updated</td> - <td>{{ctrl.jvmInfo.lastUpdated | timestampToDate}}</td> + <td>{{ctrl.jvmInfo.lastUpdated | date:"medium"}}</td> </tr> <tr> <td>JVM PID</td>
--- a/src/app/components/jvm-list/jvm-list.controller.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/components/jvm-list/jvm-list.controller.js Thu Jul 13 10:44:20 2017 -0400 @@ -49,7 +49,7 @@ this.loadData(); }); - this.scope.isAlive = (jvm) => { + this.scope.isAlive = jvm => { if (!jvm.hasOwnProperty('stopTime')) { return false; }
--- a/src/app/components/system-info/system-cpu.controller.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/components/system-info/system-cpu.controller.js Thu Jul 13 10:44:20 2017 -0400 @@ -26,6 +26,7 @@ */ import 'c3'; +import _ from 'lodash'; import filters from 'shared/filters/filters.module.js'; import service from './system-info.service.js'; @@ -57,9 +58,9 @@ update () { this.svc.getCpuInfo(this.scope.systemId).then(resp => { - let cpuInfo = resp.data.response; + let cpuInfo = resp.data.response[0]; this.data = { - used: cpuInfo.percent, + used: _.floor(_.mean(cpuInfo.perProcessorUsage)), total: 100 }; });
--- a/src/app/components/system-info/system-cpu.controller.spec.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/components/system-info/system-cpu.controller.spec.js Thu Jul 13 10:44:20 2017 -0400 @@ -107,14 +107,14 @@ func.should.be.a.Function(); let mockData = { data: { - response: { - percent: 80 - } + response: [{ + perProcessorUsage: [80] + }] } }; func(mockData); controller.data.should.deepEqual({ - used: mockData.data.response.percent, + used: mockData.data.response[0].perProcessorUsage[0], total: 100 }); });
--- a/src/app/components/system-info/system-info.controller.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/components/system-info/system-info.controller.js Thu Jul 13 10:44:20 2017 -0400 @@ -40,7 +40,7 @@ systemInfoService.getSystemInfo(systemId).then( resp => { - this.systemInfo = resp.data.response; + this.systemInfo = resp.data.response[0]; this.showErr = false; }, () => {
--- a/src/app/components/system-info/system-info.controller.spec.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/components/system-info/system-info.controller.spec.js Thu Jul 13 10:44:20 2017 -0400 @@ -58,7 +58,7 @@ }; promise.resolve({ data: { - response: response + response: [response] } }); scope.$apply();
--- a/src/app/components/system-info/system-info.html Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/components/system-info/system-info.html Thu Jul 13 10:44:20 2017 -0400 @@ -18,9 +18,25 @@ </tr> </thead> <tbody> - <tr ng-repeat="(key, value) in ctrl.systemInfo"> - <td>{{key}}</td> - <td>{{value}}</td> + <tr> + <td>Hostname</td> + <td>{{ctrl.systemInfo.hostname}}</td> + </tr> + <tr> + <td>Operating System</td> + <td>{{ctrl.systemInfo.osName}}</td> + </tr> + <tr> + <td>Kernel</td> + <td>{{ctrl.systemInfo.osKernel}}</td> + </tr> + <tr> + <td>CPU</td> + <td>{{ctrl.systemInfo.cpuModel}}<br/>({{ctrl.systemInfo.cpuCount}} cores)</td> + </tr> + <tr> + <td>Memory</td> + <td>{{ctrl.systemInfo.totalMemory | formatBytes}}</td> </tr> </tbody> </table>
--- a/src/app/components/system-info/system-info.service.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/components/system-info/system-info.service.js Thu Jul 13 10:44:20 2017 -0400 @@ -37,15 +37,29 @@ } getSystemInfo (systemId) { - return this.http.get(urlJoin(this.gatewayUrl, 'system-info', systemId)); + return this.http.get(urlJoin(this.gatewayUrl, 'systems', '0.0.1', 'systems', systemId), { + params: { + sort: '-timeStamp', + limit: 1 + } + }); } getCpuInfo (systemId) { - return this.http.get(urlJoin(this.gatewayUrl, 'system-info', 'cpu', systemId)); + return this.http.get(urlJoin(this.gatewayUrl, 'system-cpu', '0.0.1', 'systems', systemId), { + params: { + sort: '-timeStamp', + limit: 1 + } + }); } getMemoryInfo (systemId) { - return this.http.get(urlJoin(this.gatewayUrl, 'system-memory', '0.0.1', 'systems', systemId)); + return this.http.get(urlJoin(this.gatewayUrl, 'system-memory', '0.0.1', 'systems', systemId), { + params: { + sort: '-timeStamp' + } + }); } }
--- a/src/app/components/system-info/system-info.service.spec.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/components/system-info/system-info.service.spec.js Thu Jul 13 10:44:20 2017 -0400 @@ -60,13 +60,13 @@ osName: 'Linux', osKernel: '4.10.11-200.fc25.x86_64' }; - httpBackend.when('GET', 'http://example.com:1234/system-info/foo-systemId') + httpBackend.when('GET', 'http://example.com:1234/systems/0.0.1/systems/foo-systemId?limit=1&sort=-timeStamp') .respond(expected); svc.getSystemInfo('foo-systemId').then(res => { res.data.should.deepEqual(expected); done(); }); - httpBackend.expectGET('http://example.com:1234/system-info/foo-systemId'); + httpBackend.expectGET('http://example.com:1234/systems/0.0.1/systems/foo-systemId?limit=1&sort=-timeStamp'); httpBackend.flush(); scope.$apply(); }); @@ -77,13 +77,13 @@ let expected = { percent: 80 }; - httpBackend.when('GET', 'http://example.com:1234/system-info/cpu/foo-systemId') + httpBackend.when('GET', 'http://example.com:1234/system-cpu/0.0.1/systems/foo-systemId?limit=1&sort=-timeStamp') .respond(expected); svc.getCpuInfo('foo-systemId').then(res => { res.data.should.deepEqual(expected); done(); }); - httpBackend.expectGET('http://example.com:1234/system-info/cpu/foo-systemId'); + httpBackend.expectGET('http://example.com:1234/system-cpu/0.0.1/systems/foo-systemId?limit=1&sort=-timeStamp'); httpBackend.flush(); scope.$apply(); }); @@ -95,13 +95,13 @@ total: 16384, used: 9001 }; - httpBackend.when('GET', 'http://example.com:1234/system-memory/0.0.1/systems/foo-systemId') + httpBackend.when('GET', 'http://example.com:1234/system-memory/0.0.1/systems/foo-systemId?sort=-timeStamp') .respond(expected); svc.getMemoryInfo('foo-systemId').then(res => { res.data.should.deepEqual(expected); done(); }); - httpBackend.expectGET('http://example.com:1234/system-memory/0.0.1/systems/foo-systemId'); + httpBackend.expectGET('http://example.com:1234/system-memory/0.0.1/systems/foo-systemId?sort=-timeStamp'); httpBackend.flush(); scope.$apply(); });
--- a/src/app/components/system-info/system-memory.controller.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/components/system-info/system-memory.controller.js Thu Jul 13 10:44:20 2017 -0400 @@ -132,7 +132,7 @@ // update the memory time series chart this.lineConfig.axis.y.max = total; - this.lineData.xData.push(data.timestamp); + this.lineData.xData.push(data.timeStamp); this.lineData.yData0.push(total); this.lineData.yData1.push(free); this.lineData.yData2.push(used);
--- a/src/app/components/system-info/system-memory.controller.spec.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/components/system-info/system-memory.controller.spec.js Thu Jul 13 10:44:20 2017 -0400 @@ -94,7 +94,7 @@ response: { systemId: 'foo-systemId', agentId: 'mock-agentId', - timestamp: Date.now(), + timeStamp: Date.now(), total: 16384, free: 0, buffers: 1, @@ -219,7 +219,7 @@ { systemId: 'foo-systemId', agentId: 'mock-agentId', - timestamp: timestamp, + timeStamp: timestamp, total: 16384, free: 0, buffers: 1, @@ -268,7 +268,7 @@ { systemId: 'foo-systemId', agentId: 'mock-agentId', - timestamp: timestampA, + timeStamp: timestampA, total: 16384, free: 0, buffers: 0, @@ -280,7 +280,7 @@ { systemId: 'foo-systemId', agentId: 'mock-agentId', - timestamp: timestampB, + timeStamp: timestampB, total: 16384, free: 0, buffers: 0, @@ -306,7 +306,7 @@ { systemId: 'foo-systemId', agentId: 'mock-agentId', - timestamp: timestampA, + timeStamp: timestampA, total: 16384, free: 0, buffers: 0, @@ -324,7 +324,7 @@ { systemId: 'foo-systemId', agentId: 'mock-agentId', - timestamp: timestampB, + timeStamp: timestampB, total: 16384, free: 0, buffers: 0, @@ -351,7 +351,7 @@ { systemId: 'foo-systemId', agentId: 'mock-agentId', - timestamp: timestampA, + timeStamp: timestampA, total: 16384, free: 0, buffers: 0, @@ -369,7 +369,7 @@ { systemId: 'foo-systemId', agentId: 'mock-agentId', - timestamp: timestampB, + timeStamp: timestampB, total: 16384, free: 0, buffers: 0,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/shared/filters/format-bytes.filter.js Thu Jul 13 10:44:20 2017 -0400 @@ -0,0 +1,45 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import filterModule from './filters.module.js'; + +function filterProvider (scaleBytesService) { + 'ngInject'; + return val => { + // FIXME: https://trello.com/c/3jDpmy8M/170-clean-up-numberlong-ambiguities + if (typeof val === 'number') { + val = { $numberLong: val.toString() }; + } + let scale = scaleBytesService.format(val); + return scale.result + ' ' + scale.unit; + }; +} + +export default angular + .module(filterModule) + .filter('formatBytes', filterProvider) + .name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/shared/filters/format-bytes.filter.spec.js Thu Jul 13 10:44:20 2017 -0400 @@ -0,0 +1,71 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import filtersModule from 'shared/filters/filters.module.js'; +import servicesModule from 'shared/services/services.module.js'; + +describe('formatBytesFilter', () => { + + let fn, mockSvc; + beforeEach(() => { + mockSvc = { + format: sinon.stub().returns({ + result: 100, + scale: 2, + unit: 'MiB' + }) + }; + angular.mock.module(filtersModule); + angular.mock.module(servicesModule, $provide => { + 'ngInject'; + $provide.value('scaleBytesService', mockSvc); + }); + angular.mock.inject(formatBytesFilter => { + 'ngInject'; + fn = formatBytesFilter; + }); + }); + + it('should exist', () => { + should.exist(fn); + }); + + it('should convert raw numbers', () => { + mockSvc.format.should.not.be.called(); + fn(100).should.equal('100 MiB'); + mockSvc.format.should.be.calledOnce(); + mockSvc.format.should.be.calledWithMatch({ $numberLong: '100' }); + }); + + it('should delegate when called with $numberLong', () => { + mockSvc.format.should.not.be.called(); + fn({ $numberLong: '100' }).should.equal('100 MiB'); + mockSvc.format.should.be.calledOnce(); + mockSvc.format.should.be.calledWithMatch({ $numberLong: '100' }); + }); + +});
--- a/src/app/shared/filters/metric-to-big-int.filter.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/shared/filters/metric-to-big-int.filter.js Thu Jul 13 10:44:20 2017 -0400 @@ -40,6 +40,10 @@ // in case the filter is invoked on asynchronously loaded data and // 'val' is undefined, we want to avoid throwing an error below val = val || { $numberLong: '0' }; + // FIXME: https://trello.com/c/3jDpmy8M/170-clean-up-numberlong-ambiguities + if (typeof val === 'number') { + val = { $numberLong: val.toString() }; + } let res = metricToBigIntService.convert(val); // 'big(undefined)' does not have any functions defined on it,
--- a/src/app/shared/filters/metric-to-big-int.filter.spec.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/shared/filters/metric-to-big-int.filter.spec.js Thu Jul 13 10:44:20 2017 -0400 @@ -47,7 +47,11 @@ }); it('should fail on non-objects', () => { - fn(100).should.deepEqual(big(undefined)); + fn('foo').should.deepEqual(big(undefined)); + }); + + it('should convert plain numbers', () => { + fn(100).should.deepEqual(big(100)); }); it('should fail on objects without $numberLong property', () => {
--- a/src/app/shared/services/metric-to-big-int.service.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/shared/services/metric-to-big-int.service.js Thu Jul 13 10:44:20 2017 -0400 @@ -40,6 +40,13 @@ } convert (metric) { + if (!angular.isDefined(metric)) { + return this.big(undefined); + } + // FIXME: https://trello.com/c/3jDpmy8M/170-clean-up-numberlong-ambiguities + if (typeof metric === 'number') { + metric = { $numberLong: metric.toString() }; + } return this.big(metric.$numberLong); } }
--- a/src/app/shared/services/metric-to-big-int.service.spec.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/shared/services/metric-to-big-int.service.spec.js Thu Jul 13 10:44:20 2017 -0400 @@ -50,4 +50,18 @@ svc.big.should.be.calledWith('0'); }); + it('should convert raw numbers', () => { + svc.big.should.not.be.called(); + svc.convert(0).should.deepEqual(big(0)); + svc.big.should.be.calledOnce(); + svc.big.should.be.calledWith('0'); + }); + + it('should handle undefined', () => { + svc.big.should.not.be.called(); + svc.convert(undefined).should.deepEqual(big(undefined)); + svc.big.should.be.calledOnce(); + svc.big.should.be.calledWith(undefined); + }); + });
--- a/src/app/shared/services/scale-bytes.service.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/shared/services/scale-bytes.service.js Thu Jul 13 10:44:20 2017 -0400 @@ -36,6 +36,17 @@ } format (bytesMetric, dp = 2) { + if (!angular.isDefined(bytesMetric)) { + return { + result: 0, + scale: 0, + unit: '' + }; + } + // FIXME: https://trello.com/c/3jDpmy8M/170-clean-up-numberlong-ambiguities + if (typeof bytesMetric === 'number') { + bytesMetric = { $numberLong: bytesMetric.toString() }; + } const base = 1024; let big = this.metricToBigInt.convert(bytesMetric);
--- a/src/app/shared/services/scale-bytes.service.spec.js Wed Jul 12 13:56:56 2017 -0400 +++ b/src/app/shared/services/scale-bytes.service.spec.js Thu Jul 13 10:44:20 2017 -0400 @@ -39,6 +39,22 @@ should.exist(svc); }); + it('should handle undefined', () => { + svc.format(undefined).should.deepEqual({ + result: 0, + scale: 0, + unit: '' + }); + }); + + it('should convert plain numbers', () => { + svc.format(100).should.deepEqual({ + result: 100, + scale: 1, + unit: 'B' + }); + }); + it('should not scale 0 bytes', () => { svc.format({ $numberLong: '0' }).should.deepEqual({ result: 0,