'use strict'; exports = module.exports = { getDisks: getDisks, checkDiskSpace: checkDiskSpace, getMemory: getMemory }; const apps = require('./apps.js'), assert = require('assert'), async = require('async'), BoxError = require('./boxerror.js'), debug = require('debug')('box:disks'), df = require('@sindresorhus/df'), docker = require('./docker.js'), notifications = require('./notifications.js'), os = require('os'), paths = require('./paths.js'), safe = require('safetydance'), settings = require('./settings.js'); function getDisks(callback) { assert.strictEqual(typeof callback, 'function'); const dfAsync = async.asyncify(df), dfFileAsync = async.asyncify(df.file); docker.info(function (error, info) { if (error) return callback(error); async.series([ dfAsync, dfFileAsync.bind(null, paths.BOX_DATA_DIR), dfFileAsync.bind(null, paths.PLATFORM_DATA_DIR), dfFileAsync.bind(null, paths.APPS_DATA_DIR), dfFileAsync.bind(null, info.DockerRootDir) ], function (error, values) { if (error) return callback(new BoxError(BoxError.FS_ERROR, error)); // 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)); const disks = { disks: ext4Disks, // root disk is first. { filesystem, type, size, used, avialable, capacity, mountpoint } boxDataDisk: values[1].filesystem, mailDataDisk: values[1].filesystem, platformDataDisk: values[2].filesystem, appsDataDisk: values[3].filesystem, dockerDataDisk: values[4].filesystem, backupsDisk: null, apps: {} }; apps.getAll(function (error, allApps) { if (error) return callback(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(error); settings.getBackupConfig(function (error, backupConfig) { if (error) return callback(error); if (backupConfig.provider !== 'filesystem') return callback(null, disks); dfFileAsync(backupConfig.backupFolder, function (error, result) { if (error) return callback(error); disks.backupsDisk = result.filesystem; callback(null, disks); }); }); }); }); }); }); } function checkDiskSpace(callback) { assert.strictEqual(typeof callback, 'function'); debug('Checking disk space'); getDisks(function (error, disks) { if (error) { debug('checkDiskSpace: error getting disks %s', error.message); return callback(); } 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 && entry.filesystem !== disks.backupsDisk && entry.filesystem !== disks.dockerDataDisk) return false; 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); }); } function getMemory(callback) { assert.strictEqual(typeof callback, 'function'); const stdout = safe.child_process.execSync('swapon --noheadings --raw --bytes --show=SIZE', { encoding: 'utf8' }); const swap = !stdout ? 0 : stdout.trim().split('\n').map(x => parseInt(x, 10) || 0).reduce((acc, cur) => acc + cur); callback(null, { memory: os.totalmem(), swap: swap }); }