volumes: wait for mount during add/update
this is a better feedback mechanism for the user
This commit is contained in:
+23
-3
@@ -4,7 +4,8 @@ exports = module.exports = {
|
||||
writeMountFile,
|
||||
removeMountFile,
|
||||
validateMountOptions,
|
||||
getStatus
|
||||
getStatus,
|
||||
waitForMount
|
||||
};
|
||||
|
||||
const assert = require('assert'),
|
||||
@@ -16,6 +17,7 @@ const assert = require('assert'),
|
||||
paths = require('./paths.js'),
|
||||
safe = require('safetydance'),
|
||||
shell = require('./shell.js');
|
||||
const promiseRetry = require('./promise-retry.js');
|
||||
|
||||
const ADD_MOUNT_CMD = path.join(__dirname, 'scripts/addmount.sh');
|
||||
const RM_MOUNT_CMD = path.join(__dirname, 'scripts/rmmount.sh');
|
||||
@@ -79,7 +81,7 @@ async function writeMountFile(volume) {
|
||||
what = mountOptions.diskPath; // like /dev/disk/by-uuid/uuid or /dev/disk/by-id/scsi-id
|
||||
options = 'discard,defaults,noatime';
|
||||
break;
|
||||
case 'sshfs':
|
||||
case 'sshfs': {
|
||||
const keyFilePath = path.join(paths.SSHFS_KEYS_DIR, `id_rsa_${mountOptions.host}`);
|
||||
|
||||
safe.fs.mkdirSync(paths.SSHFS_KEYS_DIR);
|
||||
@@ -90,6 +92,10 @@ async function writeMountFile(volume) {
|
||||
options = `defaults,allow_other,port=${mountOptions.port},IdentityFile=${keyFilePath},reconnect,uid=yellowtent,gid=yellowtent`;
|
||||
break;
|
||||
}
|
||||
case 'noop': // volume provider
|
||||
case 'mountpoint': // backup provider
|
||||
return;
|
||||
}
|
||||
|
||||
const mountFileContents = ejs.render(SYSTEMD_MOUNT_EJS, { name, what, where: hostPath, options, type });
|
||||
await shell.promises.sudo('generateMountFile', [ ADD_MOUNT_CMD, mountFileContents ], {});
|
||||
@@ -116,7 +122,7 @@ async function getStatus(mountType, hostPath) {
|
||||
}
|
||||
|
||||
let output = safe.child_process.execSync(`systemctl show --value -p ActiveState $(systemd-escape -p --suffix=mount ${hostPath})`, { encoding: 'utf8' });
|
||||
let state = output ? output.trim() : '';
|
||||
const state = output ? output.trim() : '';
|
||||
let message;
|
||||
|
||||
if (state !== 'active') { // find why it failed
|
||||
@@ -134,3 +140,17 @@ async function getStatus(mountType, hostPath) {
|
||||
|
||||
return { state, message };
|
||||
}
|
||||
|
||||
async function waitForMount(mountType, hostPath, options) {
|
||||
assert.strictEqual(typeof mountType, 'string');
|
||||
assert.strictEqual(typeof hostPath, 'string');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
if (mountType === 'noop' || mountType === 'mountpoint') return; // noop is from volume provider and mountpoint is from backup provider
|
||||
|
||||
await promiseRetry(options, async function () {
|
||||
const status = await getStatus(mountType, hostPath);
|
||||
if (status.state === 'active') return true;
|
||||
throw new BoxError(BoxError.MOUNT_ERROR, `Mount is not active (${status.state}): ${status.message}`);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user