volumes: wait for mount during add/update

this is a better feedback mechanism for the user
This commit is contained in:
Girish Ramakrishnan
2021-05-19 09:50:50 -07:00
parent 449d6b2de4
commit 59db625ad9
4 changed files with 68 additions and 31 deletions
+23 -3
View File
@@ -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}`);
});
}