rework backup root

notes:
* backup root cannot come from backend. for dynamic mounts backend cannot know where it is mounted
* backupConfig is 3 parts - format / mount / password . there is also this rootPath (which should not be in db)
* password should be stored separately in settings at some point
* format has to be passed along everywhere because we allow restore from  same backupConfig but different format. we do this by saving the format in the backups table

fixes #819
This commit is contained in:
Girish Ramakrishnan
2023-08-15 20:24:54 +05:30
parent da49a69562
commit aa8c23c8b3
14 changed files with 94 additions and 154 deletions

View File

@@ -1,7 +1,6 @@
'use strict';
exports = module.exports = {
getBackupRootPath,
getProviderStatus,
getAvailableSize,
@@ -43,25 +42,6 @@ const assert = require('assert'),
safe = require('safetydance'),
shell = require('../shell.js');
// storage api
function getBackupRootPath(apiConfig) {
assert.strictEqual(typeof apiConfig, 'object');
switch (apiConfig.provider) {
case PROVIDER_SSHFS:
case PROVIDER_NFS:
case PROVIDER_CIFS:
case PROVIDER_EXT4:
case PROVIDER_XFS:
case PROVIDER_DISK:
return path.join(paths.MANAGED_BACKUP_MOUNT_DIR, apiConfig.prefix);
case PROVIDER_MOUNTPOINT:
return path.join(apiConfig.mountPoint, apiConfig.prefix);
case PROVIDER_FILESYSTEM:
return apiConfig.backupFolder;
}
}
async function getProviderStatus(apiConfig) {
assert.strictEqual(typeof apiConfig, 'object');
@@ -76,7 +56,7 @@ async function getProviderStatus(apiConfig) {
async function getAvailableSize(apiConfig) {
assert.strictEqual(typeof apiConfig, 'object');
const [error, dfResult] = await safe(df.file(getBackupRootPath(apiConfig)));
const [error, dfResult] = await safe(df.file(apiConfig.rootPath));
if (error) throw new BoxError(BoxError.FS_ERROR, `Error when checking for disk space: ${error.message}`);
return dfResult.available;
@@ -280,20 +260,20 @@ async function testConfig(apiConfig) {
if (!safe.child_process.execSync(`mountpoint -q -- ${apiConfig.mountPoint}`)) throw new BoxError(BoxError.BAD_FIELD, `${apiConfig.mountPoint} is not mounted`);
}
const basePath = getBackupRootPath(apiConfig);
const rootPath = apiConfig.rootPath;
const field = apiConfig.provider === PROVIDER_FILESYSTEM ? 'backupFolder' : 'mountPoint';
if (!safe.fs.mkdirSync(path.join(basePath, 'snapshot'), { recursive: true }) && safe.error.code !== 'EEXIST') {
if (safe.error && safe.error.code === 'EACCES') throw new BoxError(BoxError.BAD_FIELD, `Access denied. Create the directory and run "chown yellowtent:yellowtent ${basePath}" on the server`, { field });
if (!safe.fs.mkdirSync(path.join(rootPath, 'snapshot'), { recursive: true }) && safe.error.code !== 'EEXIST') {
if (safe.error && safe.error.code === 'EACCES') throw new BoxError(BoxError.BAD_FIELD, `Access denied. Create the directory and run "chown yellowtent:yellowtent ${rootPath}" on the server`, { field });
throw new BoxError(BoxError.BAD_FIELD, safe.error.message, { field });
}
if (!safe.fs.writeFileSync(path.join(basePath, 'cloudron-testfile'), 'testcontent')) {
throw new BoxError(BoxError.BAD_FIELD, `Unable to create test file as 'yellowtent' user in ${basePath}: ${safe.error.message}. Check dir/mount permissions`, { field });
if (!safe.fs.writeFileSync(path.join(rootPath, 'cloudron-testfile'), 'testcontent')) {
throw new BoxError(BoxError.BAD_FIELD, `Unable to create test file as 'yellowtent' user in ${rootPath}: ${safe.error.message}. Check dir/mount permissions`, { field });
}
if (!safe.fs.unlinkSync(path.join(basePath, 'cloudron-testfile'))) {
throw new BoxError(BoxError.BAD_FIELD, `Unable to remove test file as 'yellowtent' user in ${basePath}: ${safe.error.message}. Check dir/mount permissions`, { field });
if (!safe.fs.unlinkSync(path.join(rootPath, 'cloudron-testfile'))) {
throw new BoxError(BoxError.BAD_FIELD, `Unable to remove test file as 'yellowtent' user in ${rootPath}: ${safe.error.message}. Check dir/mount permissions`, { field });
}
}