diff --git a/README.md b/README.md index be7c5f9..8494523 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,17 @@ driver: registry: containers.flowforge.com privateCA: /full/path/to/chain.pem logPassthrough: true + storage: + enabled: true + path: /opt/flowfuse/storage ``` - `registry` is the Docker Registry to load Stack Containers from (default: Docker Hub) - `socket` is the path to the docker unix domain socket (default: /var/run/docker.sock) - `privateCA`: is the fully qualified path to a pem file containing trusted CA cert chain (default: not set) - `logPassthrough` Have Node-RED logs printed in JSON format to container stdout (default: false) + - `storage.enabled` enables mounting a directory into each Node-RED instance as persistence storage (default: false) + - `storage.path` is the fully qualified path to the root directory for the storage on the host (default: not set) ### Configuration via environment variables diff --git a/docker.js b/docker.js index 1ac1ab9..b941a0c 100644 --- a/docker.js +++ b/docker.js @@ -1,5 +1,7 @@ const got = require('got') const Docker = require('dockerode') +const path = require('path') +const { chownSync, mkdirSync, rmSync } = require('fs') const createContainer = async (project, domain) => { const stack = project.ProjectStack.properties @@ -99,6 +101,25 @@ const createContainer = async (project, domain) => { contOptions.Env.push('NODE_EXTRA_CA_CERTS=/usr/local/ssl-certs/chain.pem') } + if (this._app.config.driver.options?.storage?.enabled || this._app.config.driver.options?.storage?.path) { + try { + const localPath = path.join('/opt/persistent-storage', project.id) + console.log(`Creating dir in container ${localPath}`) + mkdirSync(localPath) + chownSync(localPath, 1000, 1000) + } catch (err) { + this._app.log.info(`[docker] problem creating persistent storage for ${project.id}`) + } + const projectPath = path.join(this._app.config.driver.options?.storage?.path, project.id) + if (Array.isArray(contOptions.HostConfig?.Binds)) { + contOptions.HostConfig.Binds.push(`${projectPath}:/data/storage`) + } else { + contOptions.HostConfig.Binds = [ + `${projectPath}:/data/storage` + ] + } + } + const containerList = await this._docker.listImages() let containerFound = false let stackName = stack.container @@ -342,6 +363,16 @@ module.exports = { await container.remove() } catch (err) {} } + if (this._app.config.driver.options?.storage?.enabled) { + // need to be sure we have permission to delete the dir and it's contents? + try { + // This is better and assumes that directory is mounted on `/opt/storage` + const projectPersistentPath = path.join('/opt/persistent-storage', project.id) + rmSync(projectPersistentPath, { recursive: true, force: true }) + } catch (err) { + this._app.log.error(`[docker] Project ${project.id} - error deleting persistent storage: ${err.stack}`) + } + } delete this._projects[project.id] }, /**