add sqlite3 addon take 2
- there is no container id during the addon lifecycle - sqlite3 requires the localstorage addon to be inited. so this has to become like the ftp option - remove all that child_process streaming stuff. too complicated
This commit is contained in:
+53
-107
@@ -42,7 +42,6 @@ const addonConfigs = require('./addonconfigs.js'),
|
||||
assert = require('assert'),
|
||||
blobs = require('./blobs.js'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
child_process = require('child_process'),
|
||||
constants = require('./constants.js'),
|
||||
crypto = require('crypto'),
|
||||
dashboard = require('./dashboard.js'),
|
||||
@@ -106,8 +105,8 @@ const ADDONS = {
|
||||
localstorage: {
|
||||
setup: setupLocalStorage,
|
||||
teardown: teardownLocalStorage,
|
||||
backup: NOOP, // no backup because it's already inside app data
|
||||
restore: NOOP,
|
||||
backup: backupLocalStorage, // no backup because it's already inside app data
|
||||
restore: restoreLocalStorage,
|
||||
getDynamicEnvironment: NOOP,
|
||||
clear: clearLocalStorage,
|
||||
},
|
||||
@@ -206,15 +205,7 @@ const ADDONS = {
|
||||
restore: setupOidc,
|
||||
getDynamicEnvironment: getDynamicEnvironmentOidc,
|
||||
clear: NOOP,
|
||||
},
|
||||
sqlite: {
|
||||
setup: setupSqlite,
|
||||
teardown: NOOP,
|
||||
backup: backupSqlite,
|
||||
restore: restoreSqlite,
|
||||
getDynamicEnvironment: NOOP,
|
||||
clear: clearSqlite,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// services are actual containers that are running. addons are the concepts requested by app
|
||||
@@ -912,6 +903,56 @@ async function teardownLocalStorage(app, options) {
|
||||
if (error) throw new BoxError(BoxError.FS_ERROR, error);
|
||||
}
|
||||
|
||||
async function backupSqlite(app, options) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
debug('Backing up sqlite');
|
||||
|
||||
const volumeDataDir = await apps.getStorageDir(app);
|
||||
|
||||
const cmd = `sqlite3 ${options.path} ".dump"`;
|
||||
const runCmd = `docker run --rm --name=sqlite-${app.id} \
|
||||
--net cloudron \
|
||||
-v ${volumeDataDir}:/app/data \
|
||||
--label isCloudronManaged=true \
|
||||
--read-only -v /tmp -v /run ${infra.images.base} ${cmd} > ${dumpPath('sqlite', app.id)}`;
|
||||
|
||||
await shell.bash(runCmd, { encoding: 'utf8' });
|
||||
}
|
||||
|
||||
async function backupLocalStorage(app, options) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
if (options.sqlite) await backupSqlite(app, options.sqlite);
|
||||
}
|
||||
|
||||
async function restoreSqlite(app, options) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
debug('Restoring sqlite');
|
||||
|
||||
const volumeDataDir = await apps.getStorageDir(app);
|
||||
|
||||
const cmd = `sqlite3 ${options.path}`;
|
||||
const runCmd = `docker run --rm --name=sqlite-${app.id} \
|
||||
--net cloudron \
|
||||
-v ${volumeDataDir}:/app/data \
|
||||
--label isCloudronManaged=true \
|
||||
--read-only -v /tmp -v /run ${infra.images.base} ${cmd} < ${dumpPath('sqlite', app.id)}`;
|
||||
|
||||
await shell.bash(runCmd, { encoding: 'utf8' });
|
||||
}
|
||||
|
||||
async function restoreLocalStorage(app, options) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
if (options.sqlite) await restoreSqlite(app, options.sqlite);
|
||||
}
|
||||
|
||||
async function setupTurn(app, options) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
@@ -1688,101 +1729,6 @@ async function restartMongodb() {
|
||||
return await docker.restartContainer('mongodb');
|
||||
}
|
||||
|
||||
async function setupSqlite(app, options) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
debug(`Setting up sqlite`);
|
||||
|
||||
await shell.spawn('docker', ['exec', '-t', app.containerId, 'sqlite3', options.path], {});
|
||||
}
|
||||
|
||||
async function pipeProcessToFile(program, args, filename) {
|
||||
assert.strictEqual(typeof program, 'string');
|
||||
assert(Array.isArray(args));
|
||||
assert.strictEqual(typeof filename, 'string');
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const writeStream = fs.createWriteStream(filename);
|
||||
const cp = child_process.spawn(program, args);
|
||||
pipeline(cp.stdout, writeStream, (error) => {
|
||||
if (error) return reject(new BoxError(BoxError.ADDONS_ERROR, `Error piping ${program} ${JSON.stringify(args)} to ${filename}: ${error.message}`));
|
||||
resolve();
|
||||
});
|
||||
|
||||
cp.on('close', function (code, signal) { // always called. after 'exit' or 'error'
|
||||
if (code === 0) return; // program exited, we still have to wait for write stream to finish
|
||||
|
||||
const e = new BoxError(BoxError.SHELL_ERROR, `${program} exited with code ${code} signal ${signal}`);
|
||||
e.code = code;
|
||||
e.signal = signal;
|
||||
debug(`${program} ${args.join(' ').replace(/\n/g, '\\n')} errored`, e);
|
||||
reject(e);
|
||||
});
|
||||
|
||||
cp.on('error', function (error) { // when the command itself could not be started
|
||||
debug(`${program} ${args.join(' ').replace(/\n/g, '\\n')} errored`, error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function backupSqlite(app, options) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
debug('Backing up sqlite');
|
||||
|
||||
await pipeProcessToFile('docker', ['exec', '-t', app.containerId, 'sqlite3', options.path, '.dump'], dumpPath('sqlite', app.id));
|
||||
}
|
||||
|
||||
async function pipeFileToProcess(filename, program, args) {
|
||||
assert.strictEqual(typeof url, 'string');
|
||||
assert.strictEqual(typeof program, 'string');
|
||||
assert(Array.isArray(args));
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const readStream = fs.createReadStream(filename);
|
||||
const cp = child_process.spawn(program, args);
|
||||
pipeline(readStream, cp.stdin, function (error) {
|
||||
if (error) return reject(new BoxError(BoxError.ADDONS_ERROR, `Error piping ${filename} to ${program} ${JSON.stringify(args)}: ${error.message}`));
|
||||
resolve();
|
||||
});
|
||||
|
||||
cp.on('close', function (code, signal) { // always called. after 'exit' or 'error'
|
||||
if (code === 0) return; // program exited, we still have to wait for write stream to finish
|
||||
|
||||
const e = new BoxError(BoxError.SHELL_ERROR, `${program} exited with code ${code} signal ${signal}`);
|
||||
e.code = code;
|
||||
e.signal = signal;
|
||||
debug(`${program} ${args.join(' ').replace(/\n/g, '\\n')} errored`, e);
|
||||
reject(e);
|
||||
});
|
||||
|
||||
cp.on('error', function (error) { // when the command itself could not be started
|
||||
debug(`${program} ${args.join(' ').replace(/\n/g, '\\n')} errored`, error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function restoreSqlite(app, options) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
debug('Restoring sqlite');
|
||||
|
||||
await pipeFileToProcess(dumpPath, 'docker', ['exec', '-t', app.containerId, 'sqlite3', dumpPath('sqlite', app.id)]);
|
||||
}
|
||||
|
||||
async function clearSqlite(app, options) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
debug(`Clearing sqlite`);
|
||||
|
||||
await shell.spawn('docker', ['exec', '-t', app.containerId, 'rm', '-f', options.path], {});
|
||||
await shell.spawn('docker', ['exec', '-t', app.containerId, 'sqlite3', options.path], {});
|
||||
}
|
||||
|
||||
async function startGraphite(existingInfra) {
|
||||
assert.strictEqual(typeof existingInfra, 'object');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user