diff --git a/CHANGES b/CHANGES index 6f321bf09..739f50b32 100644 --- a/CHANGES +++ b/CHANGES @@ -2204,3 +2204,5 @@ * update solr to 8.8.0 * firewall: fix issue where script errored when having more than 15 wl/bl ports * If groups are used, do not allow app installation without choosing the access settings +* tls addon + diff --git a/src/docker.js b/src/docker.js index c564af10c..7f2c2c8fb 100644 --- a/src/docker.js +++ b/src/docker.js @@ -43,6 +43,7 @@ const apps = require('./apps.js'), Docker = require('dockerode'), os = require('os'), path = require('path'), + reverseProxy = require('./reverseproxy.js'), services = require('./services.js'), settings = require('./settings.js'), shell = require('./shell.js'), @@ -191,25 +192,97 @@ function downloadImage(manifest, callback) { }); } -function getBinds(app, callback) { +function getVolumeMounts(app, callback) { assert.strictEqual(typeof app, 'object'); assert.strictEqual(typeof callback, 'function'); - if (app.mounts.length === 0) return callback(null); + let mounts = []; - let binds = []; + if (app.mounts.length === 0) return callback(null, []); volumes.list(function (error, result) { if (error) return callback(error); + let volumesById = {}; result.forEach(r => volumesById[r.id] = r); for (const mount of app.mounts) { const volume = volumesById[mount.volumeId]; - binds.push(`${volume.hostPath}:/media/${volume.name}:${mount.readOnly ? 'ro' : 'rw'}`); + + mounts.push({ + Source: volume.hostPath, + Target: `/media/${volume.name}`, + Type: 'bind', + ReadOnly: mount.readOnly + }); } - callback(null, binds); + callback(null, mounts); + }); +} + +function getAddonMounts(app, callback) { + assert.strictEqual(typeof app, 'object'); + assert.strictEqual(typeof callback, 'function'); + + let mounts = []; + + const addons = app.manifest.addons; + if (!addons) return callback(null, mounts); + + async.eachSeries(Object.keys(addons), function (addon, iteratorDone) { + switch (addon) { + case 'localstorage': + mounts.push({ + Target: '/app/data', + Source: `${app.id}-localstorage`, + Type: 'volume', + ReadOnly: false + }); + + return iteratorDone(); + case 'tls': + reverseProxy.getCertificate(app.fqdn, app.domain, function (error, bundle) { + if (error) return iteratorDone(error); + + mounts.push({ + Target: '/etc/certs/tls_cert.pem', + Source: bundle.certFilePath, + Type: 'bind', + ReadOnly: true + }); + + mounts.push({ + Target: '/etc/certs/tls_key.pem', + Source: bundle.keyFilePath, + Type: 'bind', + ReadOnly: true + }); + + iteratorDone(); + }); + + return; + default: + iteratorDone(); + } + }, function (error) { + callback(error, mounts); + }); +} + +function getMounts(app, callback) { + assert.strictEqual(typeof app, 'object'); + assert.strictEqual(typeof callback, 'function'); + + getVolumeMounts(app, function (error, volumeMounts) { + if (error) return callback(error); + + getAddonMounts(app, function (error, addonMounts) { + if (error) return callback(error); + + callback(null, volumeMounts.concat(addonMounts)); + }); }); } @@ -278,7 +351,7 @@ function createSubcontainer(app, name, cmd, options, callback) { services.getEnvironment(app, function (error, addonEnv) { if (error) return callback(error); - getBinds(app, function (error, binds) { + getMounts(app, function (error, mounts) { if (error) return callback(error); let containerOptions = { @@ -299,8 +372,7 @@ function createSubcontainer(app, name, cmd, options, callback) { 'isCloudronManaged': String(true) }, HostConfig: { - Mounts: services.getMountsSync(app, app.manifest.addons), - Binds: binds, // ideally, we have to use 'Mounts' but we have to create volumes then + Mounts: mounts, LogConfig: { Type: 'syslog', Config: { diff --git a/src/services.js b/src/services.js index 6d1d43350..1f5445f2f 100644 --- a/src/services.js +++ b/src/services.js @@ -22,7 +22,6 @@ exports = module.exports = { clearAddons, getEnvironment, - getMountsSync, getContainerNamesSync, getContainerDetails, @@ -160,6 +159,13 @@ var ADDONS = { restore: NOOP, clear: NOOP, }, + tls: { + setup: NOOP, + teardown: NOOP, + backup: NOOP, + restore: NOOP, + clear: NOOP, + }, oauth: { // kept for backward compatibility. keep teardown for uninstall to work setup: NOOP, teardown: teardownOauth, @@ -884,31 +890,6 @@ function getEnvironment(app, callback) { }); } -function getMountsSync(app, addons) { - assert.strictEqual(typeof app, 'object'); - assert(!addons || typeof addons === 'object'); - - let mounts = [ ]; - - if (!addons) return mounts; - - for (let addon in addons) { - switch (addon) { - case 'localstorage': - mounts.push({ - Target: '/app/data', - Source: `${app.id}-localstorage`, - Type: 'volume', - ReadOnly: false - }); - break; - default: break; - } - } - - return mounts; -} - function getContainerNamesSync(app, addons) { assert.strictEqual(typeof app, 'object'); assert(!addons || typeof addons === 'object');