2020-10-27 22:39:05 -07:00
'use strict' ;
exports = module . exports = {
add ,
get ,
del ,
2020-10-28 16:51:33 -07:00
list
2020-10-27 22:39:05 -07:00
} ;
const assert = require ( 'assert' ) ,
BoxError = require ( './boxerror.js' ) ,
2021-01-04 11:05:42 -08:00
collectd = require ( './collectd.js' ) ,
2020-10-30 11:07:24 -07:00
debug = require ( 'debug' ) ( 'box:volumes' ) ,
2021-01-04 11:05:42 -08:00
ejs = require ( 'ejs' ) ,
2020-10-27 22:39:05 -07:00
eventlog = require ( './eventlog.js' ) ,
2021-01-04 11:05:42 -08:00
fs = require ( 'fs' ) ,
2020-12-03 23:05:06 -08:00
path = require ( 'path' ) ,
2020-12-03 23:13:20 -08:00
safe = require ( 'safetydance' ) ,
2021-01-21 12:53:38 -08:00
services = require ( './services.js' ) ,
2020-10-30 11:07:24 -07:00
uuid = require ( 'uuid' ) ,
volumedb = require ( './volumedb.js' ) ;
2020-10-27 22:39:05 -07:00
2021-01-04 11:05:42 -08:00
const COLLECTD _CONFIG _EJS = fs . readFileSync ( _ _dirname + '/collectd/volume.ejs' , { encoding : 'utf8' } ) ;
const NOOP _CALLBACK = function ( error ) { if ( error ) debug ( error ) ; } ;
2020-10-27 22:39:05 -07:00
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' ) ;
2020-12-03 23:05:06 -08:00
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' } ) ;
2020-10-27 22:39:05 -07:00
2020-12-03 23:13:20 -08:00
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' } ) ;
2020-10-27 22:39:05 -07:00
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 ) ;
2021-02-17 23:14:47 -08:00
const id = uuid . v4 ( ) ;
2020-10-27 22:39:05 -07:00
volumedb . add ( id , name , hostPath , function ( error ) {
if ( error ) return callback ( error ) ;
eventlog . add ( eventlog . ACTION _VOLUME _ADD , auditSource , { id , name , hostPath } ) ;
2021-01-21 12:53:38 -08:00
services . rebuildService ( 'sftp' , NOOP _CALLBACK ) ;
2021-01-04 11:05:42 -08:00
const collectdConf = ejs . render ( COLLECTD _CONFIG _EJS , { volumeId : id , hostPath } ) ;
collectd . addProfile ( id , collectdConf , NOOP _CALLBACK ) ;
2020-10-27 22:39:05 -07:00
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 ) ;
} ) ;
}
2020-10-28 15:51:43 -07:00
function del ( volume , auditSource , callback ) {
assert . strictEqual ( typeof volume , 'object' ) ;
2020-10-27 22:39:05 -07:00
assert . strictEqual ( typeof auditSource , 'object' ) ;
assert . strictEqual ( typeof callback , 'function' ) ;
2020-10-28 15:51:43 -07:00
volumedb . del ( volume . id , function ( error ) {
2020-10-27 22:39:05 -07:00
if ( error ) return callback ( error ) ;
2020-10-28 15:51:43 -07:00
eventlog . add ( eventlog . ACTION _VOLUME _REMOVE , auditSource , { volume } ) ;
2021-01-21 12:53:38 -08:00
services . rebuildService ( 'sftp' , NOOP _CALLBACK ) ;
2021-01-04 11:05:42 -08:00
collectd . removeProfile ( volume . id , NOOP _CALLBACK ) ;
2020-10-27 22:39:05 -07:00
return callback ( null ) ;
} ) ;
}