diff --git a/src/sftp.js b/src/sftp.js index 5687da2ab..f1ffb9128 100644 --- a/src/sftp.js +++ b/src/sftp.js @@ -11,7 +11,8 @@ var apps = require('./apps.js'), debug = require('debug')('box:sftp'), infra = require('./infra_version.js'), safe = require('safetydance'), - shell = require('./shell.js'); + shell = require('./shell.js'), + _ = require('underscore'); function startSftp(existingInfra, callback) { assert.strictEqual(typeof existingInfra, 'object'); @@ -60,31 +61,49 @@ function rebuild(callback) { dataDirs.push({ hostDir, mountDir }); }); - const appDataVolumes = 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 \ - ${appDataVolumes} \ - -v "/etc/ssh:/etc/ssh:ro" \ - --label isCloudronManaged=true \ - --read-only -v /tmp -v /run "${tag}"`; + shell.exec('inspectSftp', 'docker inspect --format="{{json .Mounts }}" sftp', function (error, result) { + if (!error && result) { + let currentDataDirs = safe.JSON.parse(result); + if (currentDataDirs) { + currentDataDirs = currentDataDirs.filter(function (d) { return d.Destination.indexOf('/app/data/') === 0; }).map(function (d) { return { hostDir: d.Source, mountDir: d.Destination }; }); - // ignore error if container not found (and fail later) so that this code works across restarts - async.series([ - shell.exec.bind(null, 'stopSftp', 'docker stop sftp || true'), - shell.exec.bind(null, 'removeSftp', 'docker rm -f sftp || true'), - shell.exec.bind(null, 'startSftp', cmd) - ], done); + // sort for comparison + currentDataDirs.sort(function (a, b) { return a.hostDir < b.hostDir ? -1 : 1; }); + dataDirs.sort(function (a, b) { return a.hostDir < b.hostDir ? -1 : 1; }); + + if (_.isEqual(currentDataDirs, dataDirs)) { + debug('Skipping rebuild, no changes'); + return done(); + } + } + } + + const appDataVolumes = 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 \ + ${appDataVolumes} \ + -v "/etc/ssh:/etc/ssh:ro" \ + --label isCloudronManaged=true \ + --read-only -v /tmp -v /run "${tag}"`; + + // ignore error if container not found (and fail later) so that this code works across restarts + async.series([ + shell.exec.bind(null, 'stopSftp', 'docker stop sftp || true'), + shell.exec.bind(null, 'removeSftp', 'docker rm -f sftp || true'), + shell.exec.bind(null, 'startSftp', cmd) + ], done); + }); }); } diff --git a/src/shell.js b/src/shell.js index 20d1588e8..a57e9fc95 100644 --- a/src/shell.js +++ b/src/shell.js @@ -23,10 +23,12 @@ function exec(tag, cmd, callback) { debug(`${tag} exec: ${cmd}`); child_process.exec(cmd, function (error, stdout, stderr) { - debug(`${tag} (stdout): %s`, stdout.toString('utf8')); + const stdoutResult = stdout.toString('utf8'); + + debug(`${tag} (stdout): %s`, stdoutResult); debug(`${tag} (stderr): %s`, stderr.toString('utf8')); - callback(error); + callback(error, stdoutResult); }); }