119 lines
4.3 KiB
JavaScript
119 lines
4.3 KiB
JavaScript
'use strict';
|
|
|
|
exports = module.exports = {
|
|
getDisks: getDisks,
|
|
checkDiskSpace: checkDiskSpace
|
|
};
|
|
|
|
const apps = require('./apps.js'),
|
|
assert = require('assert'),
|
|
async = require('async'),
|
|
debug = require('debug')('box:disks'),
|
|
df = require('@sindresorhus/df'),
|
|
docker = require('./docker.js'),
|
|
notifications = require('./notifications.js'),
|
|
paths = require('./paths.js'),
|
|
util = require('util');
|
|
|
|
function DisksError(reason, errorOrMessage) {
|
|
assert.strictEqual(typeof reason, 'string');
|
|
assert(errorOrMessage instanceof Error || typeof errorOrMessage === 'string' || typeof errorOrMessage === 'undefined');
|
|
|
|
Error.call(this);
|
|
Error.captureStackTrace(this, this.constructor);
|
|
|
|
this.name = this.constructor.name;
|
|
this.reason = reason;
|
|
if (typeof errorOrMessage === 'undefined') {
|
|
this.message = reason;
|
|
} else if (typeof errorOrMessage === 'string') {
|
|
this.message = errorOrMessage;
|
|
} else {
|
|
this.message = 'Internal error';
|
|
this.nestedError = errorOrMessage;
|
|
}
|
|
}
|
|
util.inherits(DisksError, Error);
|
|
DisksError.INTERNAL_ERROR = 'Internal Error';
|
|
DisksError.EXTERNAL_ERROR = 'External Error';
|
|
|
|
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(new DisksError(DisksError.INTERNAL_ERROR, 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 DisksError(DisksError.INTERNAL_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
|
|
boxDataDisk: values[1].filesystem,
|
|
mailDataDisk: values[1].filesystem,
|
|
platformDataDisk: values[2].filesystem,
|
|
appsDataDisk: values[3].filesystem,
|
|
dockerDataDisk: values[4].filesystem,
|
|
apps: {}
|
|
};
|
|
|
|
apps.getAll(function (error, allApps) {
|
|
if (error) return callback(new DisksError(DisksError.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 DisksError(DisksError.INTERNAL_ERROR, error));
|
|
|
|
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.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);
|
|
});
|
|
}
|