Skip to content

Commit fdc6b3a

Browse files
authored
started working on disk size warning on controller level (#2662)
* started working on disk size warning on controller level - closes #2432 * generate notification if not enough disk space left * added the actual notification in io-pack + readme * update import after esm port * execute df -k on root dir to get correct disk space in all cases for linux and macos * try to fix redis install macos
1 parent 4a8b180 commit fdc6b3a

File tree

7 files changed

+241
-154
lines changed

7 files changed

+241
-154
lines changed

.github/workflows/ci-tests.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,8 @@ jobs:
6161
run: |
6262
brew update
6363
# temporary ignore brew problems
64-
brew install redis || true
65-
ln -sfv /usr/local/opt/redis/*.plist ~/Library/LaunchAgents
66-
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.redis.plist
64+
brew install redis
65+
brew services start redis
6766
6867
- name: Prepare installation (Windows)
6968
if: ${{ matrix.os == 'windows-latest' }}

README.md

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,30 @@ or
7171
The main configuration is stored in `iobroker-data/iobroker.json`. Normally, there is no need to edit this file because the ioBroker CLI commands can control most of the settings.
7272

7373
## Feature Overview
74+
- [Admin UI](#admin-ui)
75+
- [Automatic adapter upgrade](#automatic-adapter-upgrade)
76+
- [Command Line Interface](#command-line-interface)
77+
- [Adapter Upgrade with Webserver](#adapter-upgrade-with-webserver)
78+
- [Controller UI Upgrade](#controller-ui-upgrade)
79+
- [Per host adapter objects](#per-host-adapter-objects)
80+
- [Operating system package management](#operating-system-package-management)
81+
- [Hostname](#hostname)
82+
- [Adapter process memory limitation](#adapter-process-memory-limitation)
83+
- [Directly executing TypeScript adapters](#directly-executing-typescript-adapters)
84+
- [Statistics](#statistics)
85+
- [Error Reporting via ioBroker Sentry](#error-reporting-via-iobroker-sentry)
86+
- [Notification System](#notification-system)
87+
- [Disk space warnings](#disk-space-warnings)
88+
- [Controlling and monitoring of adapter processes](#controlling-and-monitoring-of-adapter-processes)
89+
- [Multihost](#multihost)
90+
- [TIERS: Start instances in an ordered manner](#tiers-start-instances-in-an-ordered-manner)
91+
- [Custom Node.js process arguments](#custom-nodejs-process-arguments)
92+
- [IPv6 DNS resolution support](#ipv6-dns-resolution-support)
93+
- [Object and State Aliases](#object-and-state-aliases)
94+
- [State and objects databases and files](#state-and-objects-databases-and-files)
95+
- [Certificate Handling](#certificate-handling)
96+
- [js-controller Host Messages](#js-controller-host-messages)
97+
- [Adapter Development](#adapter-development)
7498

7599
### Admin UI
76100
**Feature status:** stable
@@ -349,7 +373,7 @@ All of this helps me to provide an error-free smart home system that basically n
349373
If you want to disable the error reporting, you can do this by setting the state "system.host.NAME.plugins.sentry.enabled" to false. You should see a log message stating that sentry was disabled. After disabling the plugin no crashes from your system are reported and so cannot be fixed without reporting them by yourself manually!
350374

351375
### Notification System
352-
**Feature status:** Technology preview since js-controller 3.2.0
376+
**Feature status:** Stable since js-controller 5.0.0
353377

354378
The notification system in ioBroker allows setting, detecting and storing notifications per Host and allows querying the details.
355379

@@ -471,6 +495,12 @@ The message needs to take the following parameters in the message object:
471495

472496
All three are optional and can be a string or null/undefined if ommited.
473497

498+
### Disk space warnings
499+
**Feature status:** New in 6.0.0
500+
501+
The js-controller will generate a notification of in the scope `system` and the category `diskSpaceIssues` on warning level, if your free disk space falls under a specified threshold.
502+
By default, this threshold is 5 % of disk space. Via the state `system.host.<hostname>.diskWarning` you can override this level to any level between `0` and `100`.
503+
474504
### Logging
475505
#### Log levels
476506
**Feature status:** stable
@@ -995,8 +1025,6 @@ With such a setup, ioBroker will connect to one of these sentinel processes to g
9951025
##### Using Password for Redis Databases
9961026
**Feature status:** Stable
9971027

998-
999-
10001028
### Certificate Handling
10011029
... CLI
10021030
... Files vs PEM content

packages/common/src/lib/common/tools.ts

Lines changed: 47 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1816,96 +1816,64 @@ export interface GetDiskInfoResponse {
18161816

18171817
/**
18181818
* Read disk free space
1819-
*
1820-
* @param platform result of os.platform() (win32 => Windows, darwin => OSX)
1821-
* @param callback return result
1822-
* <pre><code>
1823-
* function (err, infos) {
1824-
* adapter.log.debug('Disks sizes is: ' + info['Disk size'] + ' - ' + info['Disk free']);
1825-
* }
1826-
* </code></pre>
18271819
*/
1828-
export function getDiskInfo(
1829-
platform: NodeJS.Platform,
1830-
callback: (err?: Error | null, infos?: null | GetDiskInfoResponse) => void
1831-
): void {
1832-
platform = platform || os.platform();
1820+
export async function getDiskInfo(): Promise<GetDiskInfoResponse | null> {
1821+
const platform = process.platform;
18331822
if (diskusage) {
18341823
try {
18351824
const path = platform === 'win32' ? thisDir.substring(0, 2) : '/';
18361825
const info = diskusage.checkSync(path);
1837-
return callback && callback(null, { 'Disk size': info.total, 'Disk free': info.free });
1838-
} catch (err) {
1839-
console.log(err);
1826+
return { 'Disk size': info.total, 'Disk free': info.free };
1827+
} catch (e) {
1828+
console.log(e.message);
18401829
}
18411830
} else {
1842-
try {
1843-
if (platform === 'win32') {
1844-
// Caption FreeSpace Size
1845-
// A:
1846-
// C: 66993807360 214640357376
1847-
// D:
1848-
// Y: 116649795584 148368257024
1849-
// Z: 116649795584 148368257024
1850-
const disk = thisDir.substring(0, 2).toUpperCase();
1851-
1852-
exec(
1853-
'wmic logicaldisk get size,freespace,caption',
1854-
{
1855-
encoding: 'utf8',
1856-
windowsHide: true
1857-
},
1858-
(error, stdout) => {
1859-
//, stderr) {
1860-
if (stdout) {
1861-
const lines = stdout.split('\n');
1862-
const line = lines.find(line => {
1863-
const parts = line.split(/\s+/);
1864-
return parts[0].toUpperCase() === disk;
1865-
});
1866-
if (line) {
1867-
const parts = line.split(/\s+/);
1868-
return (
1869-
callback &&
1870-
callback(error, {
1871-
'Disk size': parseInt(parts[2]),
1872-
'Disk free': parseInt(parts[1])
1873-
})
1874-
);
1875-
}
1876-
}
1877-
callback && callback(error, null);
1878-
}
1879-
);
1880-
} else {
1881-
exec('df -k /', { encoding: 'utf8', windowsHide: true }, (error, stdout) => {
1882-
//, stderr) {
1883-
// Filesystem 1K-blocks Used Available Use% Mounted on
1884-
// /dev/mapper/vg00-lv01 162544556 9966192 145767152 7% /
1885-
try {
1886-
if (stdout) {
1887-
const parts = stdout.split('\n')[1].split(/\s+/);
1888-
return (
1889-
callback &&
1890-
callback(error, {
1891-
'Disk size': parseInt(parts[1]) * 1024,
1892-
'Disk free': parseInt(parts[3]) * 1024
1893-
})
1894-
);
1895-
}
1896-
} catch {
1897-
// continue regardless of error
1898-
}
1899-
callback && callback(error, null);
1831+
if (platform === 'win32') {
1832+
// Caption FreeSpace Size
1833+
// A:
1834+
// C: 66993807360 214640357376
1835+
// D:
1836+
// Y: 116649795584 148368257024
1837+
// Z: 116649795584 148368257024
1838+
const disk = thisDir.substring(0, 2).toUpperCase();
1839+
1840+
const { stdout } = await execAsync('wmic logicaldisk get size,freespace,caption');
1841+
1842+
if (typeof stdout === 'string') {
1843+
const lines = stdout.split('\n');
1844+
const line = lines.find(line => {
1845+
const parts = line.split(/\s+/);
1846+
return parts[0].toUpperCase() === disk;
19001847
});
1848+
if (line) {
1849+
const parts = line.split(/\s+/);
1850+
return {
1851+
'Disk size': parseInt(parts[2]),
1852+
'Disk free': parseInt(parts[1])
1853+
};
1854+
}
1855+
}
1856+
} else {
1857+
const { stdout } = await execAsync(`df -k ${getRootDir()}`);
1858+
//, stderr) {
1859+
// Filesystem 1K-blocks Used Available Use% Mounted on
1860+
// /dev/mapper/vg00-lv01 162544556 9966192 145767152 7% /
1861+
try {
1862+
if (typeof stdout === 'string') {
1863+
const parts = stdout.split('\n')[1].split(/\s+/);
1864+
return {
1865+
'Disk size': parseInt(parts[1]) * 1024,
1866+
'Disk free': parseInt(parts[3]) * 1024
1867+
};
1868+
}
1869+
} catch {
1870+
// continue regardless of error
19011871
}
1902-
} catch (e) {
1903-
callback && callback(e, null);
19041872
}
19051873
}
1906-
}
19071874

1908-
const getDiskInfoAsync = promisify(getDiskInfo);
1875+
return null;
1876+
}
19091877

19101878
export interface CertificateInfo {
19111879
certificateFilename: string | null;
@@ -2164,7 +2132,7 @@ export async function getHostInfo(objects: any): Promise<HostInfo> {
21642132
}
21652133

21662134
try {
2167-
const info = await getDiskInfoAsync(data.Platform);
2135+
const info = await getDiskInfo();
21682136
if (info) {
21692137
Object.assign(data, info);
21702138
}

packages/controller/io-package.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,38 @@
702702
"zh-cn": "这些通知由ioBroker系统收集,并指出您应检查并修复的问题"
703703
},
704704
"categories": [
705+
{
706+
"category": "diskSpaceIssues",
707+
"name": {
708+
"en": "Issues with insufficient disk space",
709+
"de": "Probleme mit unzureichendem Speicherplatz",
710+
"ru": "Проблемы с недостаточным дисковым пространством",
711+
"pt": "Problemas com espaço insuficiente no disco",
712+
"nl": "Problemen met onvoldoende schijfruimte",
713+
"fr": "Problèmes liés à un espace disque insuffisant",
714+
"it": "Problemi di spazio su disco insufficiente",
715+
"es": "Problemas de espacio insuficiente en disco",
716+
"pl": "Problemy z niewystarczającą ilością miejsca na dysku",
717+
"uk": "Проблеми з нестачею місця на диску",
718+
"zh-cn": "磁盘空间不足的问题"
719+
},
720+
"severity": "alert",
721+
"description": {
722+
"en": "Your system is running out of disk space. Please free space on the disk to avoid problems.",
723+
"de": "Ihr System verfügt nicht mehr über genügend Speicherplatz. Bitte geben Sie Speicherplatz auf der Festplatte frei, um Probleme zu vermeiden.",
724+
"ru": "В вашей системе не хватает места на диске. Во избежание проблем освободите место на диске.",
725+
"pt": "O seu sistema está a ficar sem espaço no disco. Liberte espaço no disco para evitar problemas.",
726+
"nl": "Je systeem heeft bijna geen schijfruimte meer. Maak ruimte vrij op de schijf om problemen te voorkomen.",
727+
"fr": "Votre système manque d'espace disque. Veuillez libérer de l'espace sur le disque pour éviter tout problème.",
728+
"it": "Il sistema sta esaurendo lo spazio su disco. Liberare spazio sul disco per evitare problemi.",
729+
"es": "Su sistema se está quedando sin espacio en disco. Por favor, libere espacio en el disco para evitar problemas.",
730+
"pl": "W systemie zaczyna brakować miejsca na dysku. Aby uniknąć problemów, zwolnij miejsce na dysku.",
731+
"uk": "У вашій системі закінчується місце на диску. Будь ласка, звільніть місце на диску, щоб уникнути проблем.",
732+
"zh-cn": "您的系统正在耗尽磁盘空间。请释放磁盘空间,以免出现问题。"
733+
},
734+
"regex": [],
735+
"limit": 1
736+
},
705737
{
706738
"category": "memIssues",
707739
"name": {

packages/controller/src/lib/objects.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import fs from 'fs-extra';
2+
import { DEFAULT_DISK_WARNING_LEVEL } from '@/lib/utils.js';
23

34
interface GetHostOptions {
45
/** The host base id */
@@ -383,11 +384,11 @@ export function getHostObjects(options: GetHostOptions): TaskObject[] {
383384
type: 'state',
384385
common: {
385386
name: `${hostname} - disk warning level`,
386-
desc: 'Show warning in admin if the free disk space is below this value',
387+
desc: 'Generate a warning if the free disk space is below this value',
387388
type: 'number',
388389
read: true,
389390
write: true,
390-
def: 5,
391+
def: DEFAULT_DISK_WARNING_LEVEL,
391392
role: 'level',
392393
unit: '%'
393394
},

packages/controller/src/lib/utils.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* Get disk warning level from state
3+
*
4+
* @param state disk warning state, normally with value of type number in %
5+
* @returns The new disk warning level in %
6+
*/
7+
export function getDiskWarningLevel(state: ioBroker.State): number {
8+
let warningLevel = 0;
9+
if (typeof state.val === 'number' && state.val <= 100 && state.val >= 0) {
10+
warningLevel = state.val;
11+
}
12+
13+
return warningLevel;
14+
}
15+
16+
/** Default value for disk warning level */
17+
export const DEFAULT_DISK_WARNING_LEVEL = 5;

0 commit comments

Comments
 (0)