const cp = require("child_process"); const GeneralUtils = require("./general"); const DEFAULT_TIMEOUT = process.env.MOUNT_DEFAULT_TIMEOUT || 30000; const EXIT_CODES = { 64: "administrator can not mount filesystems", 65: "unable to decrypt using passphrase", 78: "missing or invalid passphrase", }; /** * https://objectivefs.com/ */ class ObjectiveFS { constructor(options = {}) { const objectivefs = this; objectivefs.options = options; options.paths = options.paths || {}; if (!options.paths.objectivefs) { options.paths.objectivefs = "mount.objectivefs"; } if (!options.paths.sudo) { options.paths.sudo = "/usr/bin/sudo"; } if (!options.paths.chroot) { options.paths.chroot = "/usr/sbin/chroot"; } if (!options.env) { options.env = {}; } if (!options.executor) { options.executor = { spawn: cp.spawn, //spawn: cp.execFile, }; } } /** * mount.objectivefs [-o [,]..] * * @param {*} env * @param {*} filesystem * @param {*} target * @param {*} options */ async mount(env, filesystem, target, options = []) { if (!env) { env = {}; } const objectivefs = this; let args = []; if (options.length > 0) { // TODO: maybe do -o -o ? args = args.concat(["-o", options.join(",")]); } args = args.concat([filesystem, target]); let result; try { result = await objectivefs.exec( objectivefs.options.paths.objectivefs, args, { env, operation: "mount" } ); return result; } catch (err) { throw err; } } /** * mount.objectivefs create * mount.objectivefs create -f / * * @param {*} env * @param {*} filesystem * @param {*} options */ async create(env, filesystem, options = []) { if (!env) { env = {}; } const objectivefs = this; let args = ["create"]; args = args.concat(options); args = args.concat([filesystem]); let result; try { result = await objectivefs.exec( objectivefs.options.paths.objectivefs, args, { env } ); return result; } catch (err) { if (err.code == 1 && err.stderr.includes("filesystem already exists")) { return; } throw err; } } /** * echo 'y' | mount.objectivefs destroy / * * @param {*} env * @param {*} filesystem * @param {*} options */ async destroy(env, filesystem, options = []) { const objectivefs = this; if (!env) { env = {}; } filesystem = await objectivefs.stripObjectStoreFromFilesystem(filesystem); /** * delete safety checks for filesystem * * while it is possible to delete a fs without a pool we * should never be doing that in democratic-csi */ let fs_parts = filesystem.split("/"); if (fs_parts.length != 2) { throw new Error(`filesystem safety check failed for fs: ${filesystem}`); } if (!fs_parts[0]) { throw new Error(`filesystem safety check failed for fs: ${filesystem}`); } let pool = objectivefs.options.pool; pool = await objectivefs.stripObjectStoreFromFilesystem(pool); if (!pool) { throw new Error(`filesystem safety check failed for fs: ${filesystem}`); } if (fs_parts[0].trim() != pool.trim()) { throw new Error(`filesystem safety check failed for fs: ${filesystem}`); } if (!fs_parts[1]) { throw new Error(`filesystem safety check failed for fs: ${filesystem}`); } let args = ["destroy"]; args = args.concat(options); args = args.concat([filesystem]); let result; try { result = await objectivefs.exec( "/bin/bash", [ "-c", `echo y | ${objectivefs.options.paths.objectivefs} ${args.join(" ")}`, ], { env } ); return result; } catch (err) { if ( err.code == 68 && err.stdout.includes("does not look like an ObjectiveFS filesystem") ) { return; } throw err; } } parseListOutput(data) { const lines = data.split("\n"); let headers = []; let entries = []; lines.forEach((line, i) => { if (line.length < 1) { return; } const parts = line.split("\t"); if (i == 0) { headers = parts.map((header) => { return header.trim(); }); return; } let entry = {}; headers.forEach((name, index) => { entry[name.trim()] = parts[index].trim(); }); entries.push(entry); }); return entries; } /** * mount.objectivefs list [-asvz] [[@