diff --git a/lib/actions-oclif/device/index.ts b/lib/actions-oclif/device/index.ts index 5814f5a7..ef52b2a2 100644 --- a/lib/actions-oclif/device/index.ts +++ b/lib/actions-oclif/device/index.ts @@ -30,6 +30,15 @@ interface ExtendedDevice extends DeviceWithDeviceType { device_type?: string; commit?: string; last_seen?: string; + memory_usage_mb: number | null; + memory_total_mb: number | null; + memory_usage_percent?: number; + storage_usage_mb: number | null; + storage_total_mb: number | null; + storage_usage_percent?: number; + cpu_temp_c: number | null; + cpu_usage_percent: number | null; + undervoltage_detected?: boolean; } interface FlagsDef { @@ -85,6 +94,15 @@ export default class DeviceCmd extends Command { 'is_web_accessible', 'note', 'os_version', + 'memory_usage', + 'memory_total', + 'storage_block_device', + 'storage_usage', + 'storage_total', + 'cpu_usage', + 'cpu_temp', + 'cpu_id', + 'is_undervolted', ], ...expandForAppName, })) as ExtendedDevice; @@ -101,6 +119,39 @@ export default class DeviceCmd extends Command { device.commit = (device.is_running__release as Release[])[0].commit; device.last_seen = device.last_connectivity_event ?? undefined; + // Memory/Storage are really MiB + // Consider changing headings to MiB once we can do lowercase + + device.memory_usage_mb = device.memory_usage; + device.memory_total_mb = device.memory_total; + + device.storage_usage_mb = device.storage_usage; + device.storage_total_mb = device.storage_total; + + device.cpu_temp_c = device.cpu_temp; + device.cpu_usage_percent = device.cpu_usage; + device.undervoltage_detected = device.is_undervolted; + + if ( + device.memory_usage != null && + device.memory_total != null && + device.memory_total !== 0 + ) { + device.memory_usage_percent = Math.round( + (device.memory_usage / device.memory_total) * 100, + ); + } + + if ( + device.storage_usage != null && + device.storage_total != null && + device.storage_total !== 0 + ) { + device.storage_usage_percent = Math.round( + (device.storage_usage / device.storage_total) * 100, + ); + } + console.log( getVisuals().table.vertical(device, [ `$${device.device_name}$`, @@ -119,6 +170,17 @@ export default class DeviceCmd extends Command { 'note', 'os_version', 'dashboard_url', + 'cpu_usage_percent', + 'cpu_temp_c', + 'cpu_id', + 'memory_usage_mb', + 'memory_total_mb', + 'memory_usage_percent', + 'storage_block_device', + 'storage_usage_mb', + 'storage_total_mb', + 'storage_usage_percent', + 'undervoltage_detected', ]), ); } diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 6dfac691..4fe9e115 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -2790,9 +2790,9 @@ } }, "balena-sdk": { - "version": "15.3.7", - "resolved": "https://registry.npmjs.org/balena-sdk/-/balena-sdk-15.3.7.tgz", - "integrity": "sha512-2d4rPHd4DHAWLFL10dsle+E+Zpiu2tfFcWtgYQR8OT1yszVt4Y4bt4/ubWumlpQPMqvvgC/uGGXZx6Lt0XTdLg==", + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/balena-sdk/-/balena-sdk-15.6.0.tgz", + "integrity": "sha512-yurPtF7+loQVcoPfWjJQV9WziMaLUxvppGZPOVH5GVOoWYjQSaO6avtOw97VLmMglufQIV+PN/BoseIRG7XxXg==", "requires": { "@balena/es-version": "^1.0.0", "@types/lodash": "^4.14.159", diff --git a/package.json b/package.json index 3fce6c9e..2cbaef18 100644 --- a/package.json +++ b/package.json @@ -203,7 +203,7 @@ "balena-image-manager": "^7.0.3", "balena-preload": "^10.3.1", "balena-release": "^3.0.0", - "balena-sdk": "^15.3.7", + "balena-sdk": "^15.6.0", "balena-semver": "^2.3.0", "balena-settings-client": "^4.0.5", "balena-settings-storage": "^6.0.1", diff --git a/tests/commands/device/device.spec.ts b/tests/commands/device/device.spec.ts index c97d0e6e..5599467c 100644 --- a/tests/commands/device/device.spec.ts +++ b/tests/commands/device/device.spec.ts @@ -84,6 +84,30 @@ describe('balena device', function () { const lines = cleanOutput(out); + expect(lines).to.have.lengthOf(25); + expect(lines[0]).to.equal('== SPARKLING WOOD'); + expect(lines[6].split(':')[1].trim()).to.equal('test app'); + + expect(err).to.eql([]); + }); + + it.skip('correctly handles devices with missing fields', async () => { + api.scope + .get( + /^\/v6\/device\?.+&\$expand=belongs_to__application\(\$select=app_name\)/, + ) + .replyWithFile( + 200, + path.join(apiResponsePath, 'device-missing-fields.json'), + { + 'Content-Type': 'application/json', + }, + ); + + const { out, err } = await runCommand('device 27fda508c'); + + const lines = cleanOutput(out); + expect(lines).to.have.lengthOf(14); expect(lines[0]).to.equal('== SPARKLING WOOD'); expect(lines[6].split(':')[1].trim()).to.equal('test app'); @@ -110,7 +134,7 @@ describe('balena device', function () { const lines = cleanOutput(out); - expect(lines).to.have.lengthOf(14); + expect(lines).to.have.lengthOf(25); expect(lines[0]).to.equal('== SPARKLING WOOD'); expect(lines[6].split(':')[1].trim()).to.equal('N/a'); diff --git a/tests/test-data/api-response/device-missing-app.json b/tests/test-data/api-response/device-missing-app.json index e5b98836..fca329f1 100644 --- a/tests/test-data/api-response/device-missing-app.json +++ b/tests/test-data/api-response/device-missing-app.json @@ -17,6 +17,15 @@ "supervisor_version": "10.3.7", "is_web_accessible": false, "overall_status": "idle", + "cpu_usage" : 34, + "cpu_temp" : 56.2, + "cpu_id" : "some cpu id", + "memory_usage" : 1000, + "memory_total" : 4000, + "storage_block_device" : "/dev/mmcblk0", + "storage_usage" : 1000, + "storage_total" : 64000, + "is_undervolted" : true, "__metadata": { "uri": "/resin/device(@id)?@id=1747415" } diff --git a/tests/test-data/api-response/device-missing-fields.json b/tests/test-data/api-response/device-missing-fields.json new file mode 100644 index 00000000..3a854491 --- /dev/null +++ b/tests/test-data/api-response/device-missing-fields.json @@ -0,0 +1,30 @@ +{ + "d": [ + { + "belongs_to__application": [ + { + "app_name": "test app", + "__metadata": {} + } + ], + "id": 1747415, + "is_managed_by__device": null, + "device_name": "sparkling-wood", + "is_of__device_type": [{ "slug": "raspberrypi4-64" }], + "uuid": "fda508c8583011b8466c26abdd5159f2", + "is_running__release": [{ "commit": "18756d3386c25a044db66b89e0409804" }], + "note": null, + "is_online": false, + "last_connectivity_event": "2019-11-23T00:26:35.074Z", + "ip_address": "192.168.0.112", + "mac_address": null, + "os_version": "balenaOS 2.44.0+rev3", + "supervisor_version": "10.3.7", + "is_web_accessible": false, + "overall_status": "offline", + "__metadata": { + "uri": "/resin/device(@id)?@id=1747415" + } + } + ] +} diff --git a/tests/test-data/api-response/device.json b/tests/test-data/api-response/device.json index 3a854491..ca53aa1a 100644 --- a/tests/test-data/api-response/device.json +++ b/tests/test-data/api-response/device.json @@ -22,6 +22,15 @@ "supervisor_version": "10.3.7", "is_web_accessible": false, "overall_status": "offline", + "cpu_usage" : 34, + "cpu_temp" : 56.2, + "cpu_id" : "some cpu id", + "memory_usage" : 1000, + "memory_total" : 4000, + "storage_block_device" : "/dev/mmcblk0", + "storage_usage" : 1000, + "storage_total" : 64000, + "is_undervolted" : true, "__metadata": { "uri": "/resin/device(@id)?@id=1747415" } diff --git a/tests/test-data/api-response/devices.json b/tests/test-data/api-response/devices.json index 79b0439f..67605457 100644 --- a/tests/test-data/api-response/devices.json +++ b/tests/test-data/api-response/devices.json @@ -59,6 +59,15 @@ "created_at": "2019-11-18T12:27:37.423Z", "is_active": true, "api_heartbeat_state": "offline", + "cpu_usage" : 34, + "cpu_temp" : 56.2, + "cpu_id" : "some cpu id", + "memory_usage" : 1000, + "memory_total" : 4000, + "storage_block_device" : "/dev/mmcblk0", + "storage_usage" : 1000, + "storage_total" : 64000, + "is_undervolted" : true, "__metadata": { "uri": "/resin/device(@id)?@id=1747415" } @@ -117,6 +126,15 @@ "created_at": "2019-11-18T12:27:37.423Z", "is_active": true, "api_heartbeat_state": "offline", + "cpu_usage" : 34, + "cpu_temp" : 56.2, + "cpu_id" : "some cpu id", + "memory_usage" : 1000, + "memory_total" : 4000, + "storage_block_device" : "/dev/mmcblk0", + "storage_usage" : 1000, + "storage_total" : 64000, + "is_undervolted" : true, "__metadata": { "uri": "/resin/device(@id)?@id=1747415" }