diff --git a/src/apptask.js b/src/apptask.js index b0062d7f8..c3bc1c5cf 100644 --- a/src/apptask.js +++ b/src/apptask.js @@ -45,6 +45,7 @@ var addons = require('./addons.js'), rimraf = require('rimraf'), safe = require('safetydance'), settings = require('./settings.js'), + sftp = require('./sftp.js'), shell = require('./shell.js'), superagent = require('superagent'), sysinfo = require('./sysinfo.js'), @@ -740,7 +741,12 @@ function migrateDataDir(app, args, progressCallback, callback) { debugApp(app, 'error migrating data dir : %s', error); return updateApp(app, { installationState: apps.ISTATE_ERROR, error: makeTaskError(error, app) }, callback.bind(null, error)); } - callback(null); + + // We do this after the app has the new data commited to the database + sftp.rebuild(function (error) { + if (error) console.error('Failed to rebuild sftp addon:', error); + callback(); + }); }); } diff --git a/src/sftp.js b/src/sftp.js index 0ed01afdb..74aed0476 100644 --- a/src/sftp.js +++ b/src/sftp.js @@ -1,10 +1,14 @@ 'use strict'; exports = module.exports = { - startSftp: startSftp + startSftp: startSftp, + rebuild: rebuild }; -var assert = require('assert'), +var apps = require('./apps.js'), + assert = require('assert'), + async = require('async'), + debug = require('debug')('box:sftp'), infra = require('./infra_version.js'), paths = require('./paths.js'), shell = require('./shell.js'); @@ -13,28 +17,64 @@ function startSftp(existingInfra, callback) { assert.strictEqual(typeof existingInfra, 'object'); assert.strictEqual(typeof callback, 'function'); + if (existingInfra.version === infra.version && infra.images.sftp.tag === existingInfra.images.sftp.tag) return callback(); + + rebuild(callback); +} + +function rebuild(callback) { + assert.strictEqual(typeof callback, 'function'); + + debug('rebuilding container'); + const tag = infra.images.sftp.tag; const memoryLimit = 256; - if (existingInfra.version === infra.version && infra.images.sftp.tag === existingInfra.images.sftp.tag) return callback(); + apps.getAll(function (error, result) { + if (error) return callback(error); - const cmd = `docker run --restart=always -d --name="sftp" \ - --hostname sftp \ - --net cloudron \ - --net-alias sftp \ - --log-driver syslog \ - --log-opt syslog-address=udp://127.0.0.1:2514 \ - --log-opt syslog-format=rfc5424 \ - --log-opt tag=sftp \ - -m ${memoryLimit}m \ - --memory-swap ${memoryLimit * 2}m \ - --dns 172.18.0.1 \ - --dns-search=. \ - -p 222:22 \ - -v "${paths.APPS_DATA_DIR}:/app/data" \ - -v "/etc/ssh:/etc/ssh:ro" \ - --label isCloudronManaged=true \ - --read-only -v /tmp -v /run "${tag}"`; + let dataDirs = []; + result.forEach(function (app) { + if (!app.dataDir) return; - shell.exec('startSftp', cmd, callback); + dataDirs.push({ + hostDir: app.dataDir, + // /data is required since this is where the localstorage data would be in APPS_DATA_DIR + mountDir: `/app/data/${app.id}/data` + }); + }); + + debug('extra app volume mounts', dataDirs); + + // ignore error if container not found (and fail later) so that this code works across restarts + async.series([ + shell.exec.bind(null, 'stopSftpContainer', 'docker stop sftp || true'), + shell.exec.bind(null, 'stopSftpContainer', 'docker rm -f sftp || true') + ], function (error) { + if (error) debug('Failed to stop sftp container. Possibly not running.'); + + const extraAppDataVolumes = dataDirs.map(function (v) { return `-v "${v.hostDir}:${v.mountDir}"`; }).join(' '); + + const cmd = `docker run --restart=always -d --name="sftp" \ + --hostname sftp \ + --net cloudron \ + --net-alias sftp \ + --log-driver syslog \ + --log-opt syslog-address=udp://127.0.0.1:2514 \ + --log-opt syslog-format=rfc5424 \ + --log-opt tag=sftp \ + -m ${memoryLimit}m \ + --memory-swap ${memoryLimit * 2}m \ + --dns 172.18.0.1 \ + --dns-search=. \ + -p 222:22 \ + -v "${paths.APPS_DATA_DIR}:/app/data" \ + ${extraAppDataVolumes} \ + -v "/etc/ssh:/etc/ssh:ro" \ + --label isCloudronManaged=true \ + --read-only -v /tmp -v /run "${tag}"`; + + shell.exec('startSftp', cmd, callback); + }); + }); }