diff --git a/package-lock.json b/package-lock.json index 8eeb7f3ac..4e8916ac6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -225,11 +225,68 @@ } }, "@sindresorhus/df": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/df/-/df-3.1.0.tgz", - "integrity": "sha512-lWC2M3nT61HaRsO+DH2E/UFpLHhtyjO0kQA7pVyxTPctw+O6eCMfqXB9c05Fd2kvb3pGZs5gnlCSuskbuciLFQ==", + "version": "git+ssh://git@github.com/cloudron-io/df.git#7669c60e09e23f5c50d6613d6aa5caf55b4b3f2d", + "from": "git+ssh://git@github.com/cloudron-io/df.git#type", "requires": { - "execa": "^1.0.0" + "execa": "^2.0.1" + }, + "dependencies": { + "execa": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/execa/-/execa-2.0.4.tgz", + "integrity": "sha512-VcQfhuGD51vQUQtKIq2fjGDLDbL6N1DTQVpYzxZ7LPIXw3HqTuIz6uxRmpV1qf8i31LHf2kjiaGI+GdHwRgbnQ==", + "requires": { + "cross-spawn": "^6.0.5", + "get-stream": "^5.0.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^3.0.0", + "onetime": "^5.1.0", + "p-finally": "^2.0.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "requires": { + "pump": "^3.0.0" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "npm-run-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", + "integrity": "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==", + "requires": { + "path-key": "^3.0.0" + } + }, + "p-finally": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", + "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==" + }, + "path-key": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz", + "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } } }, "@types/caseless": { @@ -2748,6 +2805,11 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -4727,6 +4789,11 @@ "resolved": false, "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, "strip-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", diff --git a/package.json b/package.json index b8ef2649b..f6dc57ba7 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dependencies": { "@google-cloud/dns": "^1.1.0", "@google-cloud/storage": "^2.5.0", - "@sindresorhus/df": "^3.1.0", + "@sindresorhus/df": "git+ssh://git@github.com/cloudron-io/df.git#type", "async": "^2.6.2", "aws-sdk": "^2.476.0", "body-parser": "^1.19.0", diff --git a/src/cloudron.js b/src/cloudron.js index 86662a2cd..9d60201e3 100644 --- a/src/cloudron.js +++ b/src/cloudron.js @@ -169,26 +169,46 @@ function runStartupTasks() { function getDisks(callback) { assert.strictEqual(typeof callback, 'function'); - var disks = { - boxDataDisk: null, - platformDataDisk: null, - appsDataDisk: null - }; + const dfAsync = async.asyncify(df), dfFileAsync = async.asyncify(df.file); - df.file(paths.BOX_DATA_DIR).then(function (result) { - disks.boxDataDisk = result.filesystem; + async.series([ + dfAsync, + dfFileAsync.bind(null, paths.BOX_DATA_DIR), + dfFileAsync.bind(null, paths.PLATFORM_DATA_DIR), + dfFileAsync.bind(null, paths.APPS_DATA_DIR), + ], function (error, values) { + if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); - return df.file(paths.PLATFORM_DATA_DIR); - }).then(function (result) { - disks.platformDataDisk = result.filesystem; + // filter by ext4 and then sort to make sure root disk is first + const ext4Disks = values[0].filter((r) => r.type === 'ext4').sort((a, b) => a.mountpoint.localeCompare(b.mountpoint)); - return df.file(paths.APPS_DATA_DIR); - }).then(function (result) { - disks.appsDataDisk = result.filesystem; + const disks = { + disks: ext4Disks, // root disk is first + boxDataDisk: values[1].filesystem, + platformDataDisk: values[2].filesystem, + appsDataDisk: values[3].filesystem, + apps: {} + }; - callback(null, disks); - }).catch(function (error) { - callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); + apps.getAll(function (error, allApps) { + if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); + + async.eachSeries(allApps, function (app, iteratorDone) { + if (!app.dataDir) { + disks.apps[app.id] = disks.appsDataDisk; + return iteratorDone(); + } + + dfFileAsync(app.dataDir, function (error, result) { + disks.apps[app.id] = error ? disks.appsDataDisk : result.filesystem; // ignore any errors + iteratorDone(); + }); + }, function (error) { + if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); + + callback(null, disks); + }); + }); }); } @@ -257,35 +277,20 @@ function checkDiskSpace(callback) { getDisks(function (error, disks) { if (error) { - debug('df error %s', error.message); + debug('checkDiskSpace: error getting disks %s', error.message); return callback(); } - df().then(function (entries) { - /* - [{ - filesystem: '/dev/disk1', - size: 499046809600, - used: 443222245376, - available: 55562420224, - capacity: 0.89, - mountpoint: '/' - }, ...] - */ - var oos = entries.some(function (entry) { - // ignore other filesystems but where box, app and platform data is - if (entry.filesystem !== disks.boxDataDisk && entry.filesystem !== disks.platformDataDisk && entry.filesystem !== disks.appsDataDisk) return false; + var oos = disks.disks.some(function (entry) { + // ignore other filesystems but where box, app and platform data is + if (entry.filesystem !== disks.boxDataDisk && entry.filesystem !== disks.platformDataDisk && entry.filesystem !== disks.appsDataDisk) return false; - return (entry.available <= (1.25 * 1024 * 1024 * 1024)); // 1.5G - }); - - debug('Disk space checked. ok: %s', !oos); - - notifications.alert(notifications.ALERT_DISK_SPACE, 'Server is running out of disk space', oos ? JSON.stringify(entries, null, 4) : '', callback); - }).catch(function (error) { - if (error) console.error(error); - callback(); + return (entry.available <= (1.25 * 1024 * 1024 * 1024)); // 1.5G }); + + debug('checkDiskSpace: disk space checked. ok: %s', !oos); + + notifications.alert(notifications.ALERT_DISK_SPACE, 'Server is running out of disk space', oos ? JSON.stringify(disks.disks, null, 4) : '', callback); }); }