117 lines
3.9 KiB
JavaScript
117 lines
3.9 KiB
JavaScript
'use strict';
|
|
|
|
exports = module.exports = {
|
|
add,
|
|
get,
|
|
del,
|
|
list
|
|
};
|
|
|
|
const assert = require('assert'),
|
|
BoxError = require('./boxerror.js'),
|
|
collectd = require('./collectd.js'),
|
|
debug = require('debug')('box:volumes'),
|
|
ejs = require('ejs'),
|
|
eventlog = require('./eventlog.js'),
|
|
fs = require('fs'),
|
|
path = require('path'),
|
|
safe = require('safetydance'),
|
|
services = require('./services.js'),
|
|
uuid = require('uuid'),
|
|
volumedb = require('./volumedb.js');
|
|
|
|
const COLLECTD_CONFIG_EJS = fs.readFileSync(__dirname + '/collectd/volume.ejs', { encoding: 'utf8' });
|
|
const NOOP_CALLBACK = function (error) { if (error) debug(error); };
|
|
|
|
function validateName(name) {
|
|
assert.strictEqual(typeof name, 'string');
|
|
|
|
if (!/^[-\w^&'@{}[\],$=!#().%+~ ]+$/.test(name)) return new BoxError(BoxError.BAD_FIELD, 'Invalid name');
|
|
|
|
return null;
|
|
}
|
|
|
|
function validateHostPath(hostPath) {
|
|
assert.strictEqual(typeof hostPath, 'string');
|
|
|
|
if (path.normalize(hostPath) !== hostPath) return new BoxError(BoxError.BAD_FIELD, 'hostPath must contain a normalized path', { field: 'hostPath' });
|
|
if (!path.isAbsolute(hostPath)) return new BoxError(BoxError.BAD_FIELD, 'backupFolder must be an absolute path', { field: 'hostPath' });
|
|
|
|
if (hostPath === '/') return new BoxError(BoxError.BAD_FIELD, 'hostPath cannot be /', { field: 'hostPath' });
|
|
|
|
if (!hostPath.endsWith('/')) hostPath = hostPath + '/'; // ensure trailing slash for the prefix matching to work
|
|
const allowedPaths = [ '/mnt/', '/media/', '/srv/', '/opt/' ];
|
|
|
|
if (!allowedPaths.some(p => hostPath.startsWith(p))) return new BoxError(BoxError.BAD_FIELD, 'hostPath must be under /mnt, /media, /opt or /srv', { field: 'hostPath' });
|
|
|
|
const stat = safe.fs.lstatSync(hostPath);
|
|
if (!stat) return new BoxError(BoxError.BAD_FIELD, 'hostPath does not exist. Please create it on the server first', { field: 'hostPath' });
|
|
if (!stat.isDirectory()) return new BoxError(BoxError.BAD_FIELD, 'hostPath is not a directory', { field: 'hostPath' });
|
|
|
|
return null;
|
|
}
|
|
|
|
function add(name, hostPath, auditSource, callback) {
|
|
assert.strictEqual(typeof name, 'string');
|
|
assert.strictEqual(typeof hostPath, 'string');
|
|
assert.strictEqual(typeof auditSource, 'object');
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
let error = validateName(name);
|
|
if (error) return callback(error);
|
|
|
|
error = validateHostPath(hostPath);
|
|
if (error) return callback(error);
|
|
|
|
const id = uuid.v4();
|
|
|
|
volumedb.add(id, name, hostPath, function (error) {
|
|
if (error) return callback(error);
|
|
|
|
eventlog.add(eventlog.ACTION_VOLUME_ADD, auditSource, { id, name, hostPath });
|
|
services.rebuildService('sftp', NOOP_CALLBACK);
|
|
|
|
const collectdConf = ejs.render(COLLECTD_CONFIG_EJS, { volumeId: id, hostPath });
|
|
collectd.addProfile(id, collectdConf, NOOP_CALLBACK);
|
|
|
|
callback(null, id);
|
|
});
|
|
}
|
|
|
|
function get(id, callback) {
|
|
assert.strictEqual(typeof id, 'string');
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
volumedb.get(id, function (error, result) {
|
|
if (error) return callback(error);
|
|
|
|
callback(null, result);
|
|
});
|
|
}
|
|
|
|
function list(callback) {
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
volumedb.list(function (error, result) {
|
|
if (error) return callback(error);
|
|
|
|
return callback(null, result);
|
|
});
|
|
}
|
|
|
|
function del(volume, auditSource, callback) {
|
|
assert.strictEqual(typeof volume, 'object');
|
|
assert.strictEqual(typeof auditSource, 'object');
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
volumedb.del(volume.id, function (error) {
|
|
if (error) return callback(error);
|
|
|
|
eventlog.add(eventlog.ACTION_VOLUME_REMOVE, auditSource, { volume });
|
|
services.rebuildService('sftp', NOOP_CALLBACK);
|
|
collectd.removeProfile(volume.id, NOOP_CALLBACK);
|
|
|
|
return callback(null);
|
|
});
|
|
}
|