mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-06-02 07:40:48 +00:00
Refactor system information filtering
Change-type: patch Signed-off-by: Cameron Diver <cameron@balena.io>
This commit is contained in:
parent
13c29db540
commit
a2ceb5c931
@ -122,38 +122,10 @@ const getStateDiff = (): DeviceStatus => {
|
|||||||
.value(),
|
.value(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const shouldReportSysInfo = (type: string, past: number, now: number) => {
|
const toOmit: string[] = sysInfo.filterNonSignificantChanges(
|
||||||
if (!past) {
|
lastReportedLocal as sysInfo.SystemInfo,
|
||||||
return true;
|
stateForReport.local as sysInfo.SystemInfo,
|
||||||
}
|
);
|
||||||
// TODO: Deduplicate this code
|
|
||||||
switch (type) {
|
|
||||||
case 'cpu_usage':
|
|
||||||
// The bucket size of cpu usage is 20
|
|
||||||
return Math.floor(past / 20) !== Math.floor(now / 20);
|
|
||||||
case 'cpu_temp':
|
|
||||||
return Math.floor(past / 5) !== Math.floor(now / 5);
|
|
||||||
case 'memory_usage':
|
|
||||||
return Math.floor(past / 10) !== Math.floor(now / 10);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const toOmit: string[] = [];
|
|
||||||
_.each(diff.local, (value, key) => {
|
|
||||||
// if we have some system information that has changed, we check that it's
|
|
||||||
// within a certain range before reporting
|
|
||||||
if (
|
|
||||||
!shouldReportSysInfo(
|
|
||||||
key,
|
|
||||||
(lastReportedLocal as any)[key],
|
|
||||||
value as number,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
toOmit.push(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
diff.local = _.omit(diff.local, toOmit);
|
diff.local = _.omit(diff.local, toOmit);
|
||||||
return _.omitBy(diff, _.isEmpty);
|
return _.omitBy(diff, _.isEmpty);
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import * as systeminformation from 'systeminformation';
|
import * as systeminformation from 'systeminformation';
|
||||||
import * as osUtils from 'os-utils';
|
import * as osUtils from 'os-utils';
|
||||||
|
import * as _ from 'lodash';
|
||||||
import { fs, child_process } from 'mz';
|
import { fs, child_process } from 'mz';
|
||||||
|
|
||||||
export function getCpuUsage() {
|
export function getCpuUsage(): Promise<number> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
osUtils.cpuUsage((percent) => {
|
osUtils.cpuUsage((percent) => {
|
||||||
resolve(Math.round(percent * 100));
|
resolve(Math.round(percent * 100));
|
||||||
@ -11,7 +12,11 @@ export function getCpuUsage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const blockDeviceRegex = /(\/dev\/.*)p\d+/;
|
const blockDeviceRegex = /(\/dev\/.*)p\d+/;
|
||||||
export async function getStorageInfo() {
|
export async function getStorageInfo(): Promise<{
|
||||||
|
blockDevice: string;
|
||||||
|
storageUsed?: number;
|
||||||
|
storageTotal?: number;
|
||||||
|
}> {
|
||||||
const fsInfo = await systeminformation.fsSize();
|
const fsInfo = await systeminformation.fsSize();
|
||||||
let mainFs: string | undefined;
|
let mainFs: string | undefined;
|
||||||
let total = 0;
|
let total = 0;
|
||||||
@ -51,7 +56,10 @@ export async function getStorageInfo() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getMemoryInformation() {
|
export async function getMemoryInformation(): Promise<{
|
||||||
|
used: number;
|
||||||
|
total: number;
|
||||||
|
}> {
|
||||||
const mem = await systeminformation.mem();
|
const mem = await systeminformation.mem();
|
||||||
return {
|
return {
|
||||||
used: bytesToMb(mem.used),
|
used: bytesToMb(mem.used),
|
||||||
@ -59,11 +67,11 @@ export async function getMemoryInformation() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getCpuTemp() {
|
export async function getCpuTemp(): Promise<number> {
|
||||||
return Math.round((await systeminformation.cpuTemperature()).main);
|
return Math.round((await systeminformation.cpuTemperature()).main);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getCpuId() {
|
export async function getCpuId(): Promise<string | undefined> {
|
||||||
// Read /proc/device-tree/serial-number
|
// Read /proc/device-tree/serial-number
|
||||||
// if it's not there, return undefined
|
// if it's not there, return undefined
|
||||||
try {
|
try {
|
||||||
@ -76,7 +84,7 @@ export async function getCpuId() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const undervoltageRegex = /under.*voltage/;
|
const undervoltageRegex = /under.*voltage/;
|
||||||
export async function undervoltageDetected() {
|
export async function undervoltageDetected(): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
const [dmesgStdout] = await child_process.exec('dmesg');
|
const [dmesgStdout] = await child_process.exec('dmesg');
|
||||||
return undervoltageRegex.test(dmesgStdout.toString());
|
return undervoltageRegex.test(dmesgStdout.toString());
|
||||||
@ -107,6 +115,39 @@ export async function getSysInfoToReport() {
|
|||||||
is_undervolted: undervoltage,
|
is_undervolted: undervoltage,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
export type SystemInfo = UnwrappedPromise<
|
||||||
|
ReturnType<typeof getSysInfoToReport>
|
||||||
|
>;
|
||||||
|
|
||||||
|
const significantChange: { [key in keyof SystemInfo]?: number } = {
|
||||||
|
cpu_usage: 20,
|
||||||
|
cpu_temp: 5,
|
||||||
|
memory_usage: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function filterNonSignificantChanges(
|
||||||
|
past: Partial<SystemInfo>,
|
||||||
|
current: SystemInfo,
|
||||||
|
): Array<keyof SystemInfo> {
|
||||||
|
return Object.keys(
|
||||||
|
_.omitBy(current, (value, key: keyof SystemInfo) => {
|
||||||
|
// If we didn't have a value for this in the past, include it
|
||||||
|
if (past[key] == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const bucketSize = significantChange[key];
|
||||||
|
// If we don't have any requirements on this value, include it
|
||||||
|
if (bucketSize == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
Math.floor((value as number) / bucketSize) !==
|
||||||
|
Math.floor((past[key] as number) / bucketSize)
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
) as Array<keyof SystemInfo>;
|
||||||
|
}
|
||||||
|
|
||||||
function bytesToMb(bytes: number) {
|
function bytesToMb(bytes: number) {
|
||||||
return Math.floor(bytes / 1024 / 1024);
|
return Math.floor(bytes / 1024 / 1024);
|
||||||
|
58
test/38-sys-info.spec.ts
Normal file
58
test/38-sys-info.spec.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { expect } from 'chai';
|
||||||
|
import * as sysInfo from '../src/lib/system-info';
|
||||||
|
|
||||||
|
describe('System information', () => {
|
||||||
|
describe('Delta-based filtering', () => {
|
||||||
|
it('should correctly filter cpu usage', () => {
|
||||||
|
expect(
|
||||||
|
sysInfo.filterNonSignificantChanges({ cpu_usage: 21 }, {
|
||||||
|
cpu_usage: 20,
|
||||||
|
} as sysInfo.SystemInfo),
|
||||||
|
).to.deep.equal(['cpu_usage']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
sysInfo.filterNonSignificantChanges({ cpu_usage: 10 }, {
|
||||||
|
cpu_usage: 20,
|
||||||
|
} as sysInfo.SystemInfo),
|
||||||
|
).to.deep.equal([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly filter cpu temperature', () => {
|
||||||
|
expect(
|
||||||
|
sysInfo.filterNonSignificantChanges({ cpu_temp: 21 }, {
|
||||||
|
cpu_temp: 22,
|
||||||
|
} as sysInfo.SystemInfo),
|
||||||
|
).to.deep.equal(['cpu_temp']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
sysInfo.filterNonSignificantChanges({ cpu_temp: 10 }, {
|
||||||
|
cpu_temp: 20,
|
||||||
|
} as sysInfo.SystemInfo),
|
||||||
|
).to.deep.equal([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly filter memory usage', () => {
|
||||||
|
expect(
|
||||||
|
sysInfo.filterNonSignificantChanges({ memory_usage: 21 }, {
|
||||||
|
memory_usage: 22,
|
||||||
|
} as sysInfo.SystemInfo),
|
||||||
|
).to.deep.equal(['memory_usage']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
sysInfo.filterNonSignificantChanges({ memory_usage: 10 }, {
|
||||||
|
memory_usage: 20,
|
||||||
|
} as sysInfo.SystemInfo),
|
||||||
|
).to.deep.equal([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not filter if we didnt have a past value', () => {
|
||||||
|
expect(
|
||||||
|
sysInfo.filterNonSignificantChanges({}, {
|
||||||
|
memory_usage: 22,
|
||||||
|
cpu_usage: 10,
|
||||||
|
cpu_temp: 5,
|
||||||
|
} as sysInfo.SystemInfo),
|
||||||
|
).to.deep.equal([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user