reorder functions for no-use-before-define

This commit is contained in:
Girish Ramakrishnan
2026-02-14 16:34:34 +01:00
parent 36aa641cb9
commit e9f96593c3
31 changed files with 2621 additions and 2648 deletions

View File

@@ -31,11 +31,6 @@ import _ from './underscore.js';
const debug = debugModule('box:apptask');
const shell = shellModule('apptask');
const _createAppDir = createAppDir;
const _deleteAppDir = deleteAppDir;
const _verifyManifest = verifyManifest;
const LOGROTATE_CONFIG_EJS = fs.readFileSync(import.meta.dirname + '/logrotate.ejs', { encoding: 'utf8' }),
CONFIGURE_LOGROTATE_CMD = path.join(import.meta.dirname, 'scripts/configurelogrotate.sh');
@@ -76,35 +71,6 @@ async function allocateContainerIp(app) {
});
}
async function createContainer(app) {
assert.strictEqual(typeof app, 'object');
assert(!app.containerId); // otherwise, it will trigger volumeFrom
if (app.manifest.id === constants.PROXY_APP_APPSTORE_ID) return;
debug('createContainer: creating container');
const container = await docker.createContainer(app);
await updateApp(app, { containerId: container.id });
// re-generate configs that rely on container id
await addLogrotateConfig(app);
}
async function deleteContainers(app, options) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof options, 'object');
debug('deleteContainer: deleting app containers (app, scheduler)');
// remove configs that rely on container id
await removeLogrotateConfig(app);
await docker.stopContainers(app.id);
await docker.deleteContainers(app.id, options);
await updateApp(app, { containerId: null });
}
async function createAppDir(app) {
assert.strictEqual(typeof app, 'object');
@@ -158,25 +124,6 @@ async function deleteAppDir(app, options) {
}
}
async function addLogrotateConfig(app) {
assert.strictEqual(typeof app, 'object');
const result = await docker.inspect(app.containerId);
const runVolume = result.Mounts.find(function (mount) { return mount.Destination === '/run'; });
if (!runVolume) throw new BoxError(BoxError.DOCKER_ERROR, 'App does not have /run mounted');
// logrotate configs can have arbitrary commands, so the config files must be owned by root
const logrotateConf = ejs.render(LOGROTATE_CONFIG_EJS, { volumePath: runVolume.Source, appId: app.id });
const tmpFilePath = path.join(os.tmpdir(), app.id + '.logrotate');
safe.fs.writeFileSync(tmpFilePath, logrotateConf);
if (safe.error) throw new BoxError(BoxError.FS_ERROR, `Error writing logrotate config: ${safe.error.message}`);
const [error] = await safe(shell.sudo([ CONFIGURE_LOGROTATE_CMD, 'add', app.id, tmpFilePath ], {}));
if (error) throw new BoxError(BoxError.LOGROTATE_ERROR, `Error adding logrotate config: ${error.message}`);
}
async function removeLogrotateConfig(app) {
assert.strictEqual(typeof app, 'object');
@@ -184,6 +131,19 @@ async function removeLogrotateConfig(app) {
if (error) throw new BoxError(BoxError.LOGROTATE_ERROR, `Error removing logrotate config: ${error.message}`);
}
async function deleteContainers(app, options) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof options, 'object');
debug('deleteContainer: deleting app containers (app, scheduler)');
// remove configs that rely on container id
await removeLogrotateConfig(app);
await docker.stopContainers(app.id);
await docker.deleteContainers(app.id, options);
await updateApp(app, { containerId: null });
}
async function cleanupLogs(app) {
assert.strictEqual(typeof app, 'object');
@@ -301,6 +261,131 @@ async function startApp(app) {
await docker.startContainer(app.id);
}
async function startCommand(app, args, progressCallback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof args, 'object');
assert.strictEqual(typeof progressCallback, 'function');
await progressCallback({ percent: 10, message: 'Starting app services' });
await services.startAppServices(app);
if (app.manifest.id !== constants.PROXY_APP_APPSTORE_ID) {
await progressCallback({ percent: 35, message: 'Starting container' });
await docker.startContainer(app.id);
}
// stopped apps do not renew certs. currently, we don't do DNS to not overwrite existing user settings
await progressCallback({ percent: 80, message: 'Configuring reverse proxy' });
await reverseProxy.configureApp(app, AuditSource.APPTASK);
await progressCallback({ percent: 100, message: 'Done' });
await updateApp(app, { installationState: apps.ISTATE_INSTALLED, error: null, health: null });
}
async function stopCommand(app, args, progressCallback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof args, 'object');
assert.strictEqual(typeof progressCallback, 'function');
// we don't delete the containers. app containers are created with the unless-stopped restart policy. there is no danger of apps getting restarted on reboot
await progressCallback({ percent: 20, message: 'Stopping container' });
await reverseProxy.unconfigureApp(app); // removing nginx configs also means that we can auto-cleanup old certs since they are not referenced
await docker.stopContainers(app.id);
await progressCallback({ percent: 50, message: 'Stopping app services' });
await services.stopAppServices(app);
await progressCallback({ percent: 100, message: 'Done' });
await updateApp(app, { installationState: apps.ISTATE_INSTALLED, error: null, health: null });
}
async function restartCommand(app, args, progressCallback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof args, 'object');
assert.strictEqual(typeof progressCallback, 'function');
if (app.manifest.id !== constants.PROXY_APP_APPSTORE_ID) {
await progressCallback({ percent: 10, message: 'Starting app services' });
await services.startAppServices(app);
await progressCallback({ percent: 20, message: 'Restarting container' });
await docker.restartContainer(app.id);
}
// stopped apps do not renew certs. currently, we don't do DNS to not overwrite existing user settings
await progressCallback({ percent: 80, message: 'Configuring reverse proxy' });
await reverseProxy.configureApp(app, AuditSource.APPTASK);
await progressCallback({ percent: 100, message: 'Done' });
await updateApp(app, { installationState: apps.ISTATE_INSTALLED, error: null, health: null });
}
// this command can also be called when the app is stopped. do not touch services
async function uninstallCommand(app, args, progressCallback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof args, 'object');
assert.strictEqual(typeof progressCallback, 'function');
await progressCallback({ percent: 20, message: 'Deleting container' });
await reverseProxy.unconfigureApp(app);
await deleteContainers(app, {});
await progressCallback({ percent: 30, message: 'Teardown addons' });
await services.teardownAddons(app, app.manifest.addons);
await progressCallback({ percent: 40, message: 'Cleanup file manager' });
await progressCallback({ percent: 50, message: 'Deleting app data directory' });
await deleteAppDir(app, { removeDirectory: true });
await progressCallback({ percent: 60, message: 'Deleting image' });
await docker.deleteImage(app.manifest.dockerImage);
await progressCallback({ percent: 70, message: 'Unregistering domains' });
await dns.unregisterLocations([ { subdomain: app.subdomain, domain: app.domain } ].concat(app.secondaryDomains).concat(app.redirectDomains).concat(app.aliasDomains), progressCallback);
await progressCallback({ percent: 90, message: 'Cleanup logs' });
await cleanupLogs(app);
await progressCallback({ percent: 95, message: 'Remove app from database' });
await apps.del(app.id);
}
async function addLogrotateConfig(app) {
assert.strictEqual(typeof app, 'object');
const result = await docker.inspect(app.containerId);
const runVolume = result.Mounts.find(function (mount) { return mount.Destination === '/run'; });
if (!runVolume) throw new BoxError(BoxError.DOCKER_ERROR, 'App does not have /run mounted');
// logrotate configs can have arbitrary commands, so the config files must be owned by root
const logrotateConf = ejs.render(LOGROTATE_CONFIG_EJS, { volumePath: runVolume.Source, appId: app.id });
const tmpFilePath = path.join(os.tmpdir(), app.id + '.logrotate');
safe.fs.writeFileSync(tmpFilePath, logrotateConf);
if (safe.error) throw new BoxError(BoxError.FS_ERROR, `Error writing logrotate config: ${safe.error.message}`);
const [error] = await safe(shell.sudo([ CONFIGURE_LOGROTATE_CMD, 'add', app.id, tmpFilePath ], {}));
if (error) throw new BoxError(BoxError.LOGROTATE_ERROR, `Error adding logrotate config: ${error.message}`);
}
async function createContainer(app) {
assert.strictEqual(typeof app, 'object');
assert(!app.containerId); // otherwise, it will trigger volumeFrom
if (app.manifest.id === constants.PROXY_APP_APPSTORE_ID) return;
debug('createContainer: creating container');
const container = await docker.createContainer(app);
await updateApp(app, { containerId: container.id });
// re-generate configs that rely on container id
await addLogrotateConfig(app);
}
async function installCommand(app, args, progressCallback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof args, 'object');
@@ -412,7 +497,7 @@ async function installCommand(app, args, progressCallback) {
await updateApp(app, { installationState: apps.ISTATE_INSTALLED, error: null, health: null });
}
// this command can also be called when the app is stopped. do not touch services
// configure is called for an infra update and repair to re-create container, reverseproxy config. it's all "local"
async function recreateCommand(app, args, progressCallback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof args, 'object');
@@ -552,7 +637,6 @@ async function migrateDataDirCommand(app, args, progressCallback) {
await updateApp(app, { installationState: apps.ISTATE_INSTALLED, error: null, health: null });
}
// configure is called for an infra update and repair to re-create container, reverseproxy config. it's all "local"
async function configureCommand(app, args, progressCallback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof args, 'object');
@@ -703,95 +787,6 @@ async function updateCommand(app, args, progressCallback) {
await updateApp(app, { installationState: apps.ISTATE_INSTALLED, error: null, health: null, updateInfo: null, updateTime: new Date() });
}
async function startCommand(app, args, progressCallback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof args, 'object');
assert.strictEqual(typeof progressCallback, 'function');
await progressCallback({ percent: 10, message: 'Starting app services' });
await services.startAppServices(app);
if (app.manifest.id !== constants.PROXY_APP_APPSTORE_ID) {
await progressCallback({ percent: 35, message: 'Starting container' });
await docker.startContainer(app.id);
}
// stopped apps do not renew certs. currently, we don't do DNS to not overwrite existing user settings
await progressCallback({ percent: 80, message: 'Configuring reverse proxy' });
await reverseProxy.configureApp(app, AuditSource.APPTASK);
await progressCallback({ percent: 100, message: 'Done' });
await updateApp(app, { installationState: apps.ISTATE_INSTALLED, error: null, health: null });
}
async function stopCommand(app, args, progressCallback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof args, 'object');
assert.strictEqual(typeof progressCallback, 'function');
// we don't delete the containers. app containers are created with the unless-stopped restart policy. there is no danger of apps getting restarted on reboot
await progressCallback({ percent: 20, message: 'Stopping container' });
await reverseProxy.unconfigureApp(app); // removing nginx configs also means that we can auto-cleanup old certs since they are not referenced
await docker.stopContainers(app.id);
await progressCallback({ percent: 50, message: 'Stopping app services' });
await services.stopAppServices(app);
await progressCallback({ percent: 100, message: 'Done' });
await updateApp(app, { installationState: apps.ISTATE_INSTALLED, error: null, health: null });
}
async function restartCommand(app, args, progressCallback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof args, 'object');
assert.strictEqual(typeof progressCallback, 'function');
if (app.manifest.id !== constants.PROXY_APP_APPSTORE_ID) {
await progressCallback({ percent: 10, message: 'Starting app services' });
await services.startAppServices(app);
await progressCallback({ percent: 20, message: 'Restarting container' });
await docker.restartContainer(app.id);
}
// stopped apps do not renew certs. currently, we don't do DNS to not overwrite existing user settings
await progressCallback({ percent: 80, message: 'Configuring reverse proxy' });
await reverseProxy.configureApp(app, AuditSource.APPTASK);
await progressCallback({ percent: 100, message: 'Done' });
await updateApp(app, { installationState: apps.ISTATE_INSTALLED, error: null, health: null });
}
async function uninstallCommand(app, args, progressCallback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof args, 'object');
assert.strictEqual(typeof progressCallback, 'function');
await progressCallback({ percent: 20, message: 'Deleting container' });
await reverseProxy.unconfigureApp(app);
await deleteContainers(app, {});
await progressCallback({ percent: 30, message: 'Teardown addons' });
await services.teardownAddons(app, app.manifest.addons);
await progressCallback({ percent: 40, message: 'Cleanup file manager' });
await progressCallback({ percent: 50, message: 'Deleting app data directory' });
await deleteAppDir(app, { removeDirectory: true });
await progressCallback({ percent: 60, message: 'Deleting image' });
await docker.deleteImage(app.manifest.dockerImage);
await progressCallback({ percent: 70, message: 'Unregistering domains' });
await dns.unregisterLocations([ { subdomain: app.subdomain, domain: app.domain } ].concat(app.secondaryDomains).concat(app.redirectDomains).concat(app.aliasDomains), progressCallback);
await progressCallback({ percent: 90, message: 'Cleanup logs' });
await cleanupLogs(app);
await progressCallback({ percent: 95, message: 'Remove app from database' });
await apps.del(app.id);
}
async function run(appId, args, progressCallback) {
assert.strictEqual(typeof appId, 'string');
assert.strictEqual(typeof args, 'object');
@@ -867,9 +862,13 @@ async function run(appId, args, progressCallback) {
return result || null;
}
const _createAppDir = createAppDir;
const _deleteAppDir = deleteAppDir;
export default {
run,
_createAppDir,
_deleteAppDir,
_verifyManifest,
_verifyManifest: verifyManifest,
};