From 507bd113686857cd31010f3fc1ef0d2efaa597b4 Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Fri, 21 Jun 2024 10:22:01 +0100 Subject: [PATCH 1/5] Assume that storage is mounted on `/opt/storage` This is so we can clean up --- README.md | 5 +++++ docker.js | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) 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 acddb7f..ac0e74b 100644 --- a/docker.js +++ b/docker.js @@ -1,5 +1,7 @@ const got = require('got') const Docker = require('dockerode') +const path = require('path') +const { mkdirSync, rmSync } = require('fs') const createContainer = async (project, domain) => { const networks = await this._docker.listNetworks({ filters: { label: ['com.docker.compose.network=flowforge'] } }) @@ -100,6 +102,18 @@ 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) { + const projectPath = path.join(this._app.config.driver.options?.storage?.path, project.id) + mkdirSync(projectPath) + 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 @@ -314,6 +328,19 @@ 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 the wrong path, the directory will need mounting into the forge-docker container + // const projectPersistentPath = path.join(this._app.config.driver.options?.storage?.path, project.id) + // rmSync(projectPersistentPath, { recursive: true, force: true}) + // This is better and assumes that directory is mounted on `/opt/storage` + const projectPersistentPath = path.join('/opt/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] }, /** From 5a61f719630d8b70b30f76272dac1f1b3746e15c Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Mon, 15 Jul 2024 14:33:33 +0100 Subject: [PATCH 2/5] Set ownership --- docker.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docker.js b/docker.js index ac0e74b..6ae1b9c 100644 --- a/docker.js +++ b/docker.js @@ -1,7 +1,7 @@ const got = require('got') const Docker = require('dockerode') const path = require('path') -const { mkdirSync, rmSync } = require('fs') +const { chownSync, mkdirSync, rmSync } = require('fs') const createContainer = async (project, domain) => { const networks = await this._docker.listNetworks({ filters: { label: ['com.docker.compose.network=flowforge'] } }) @@ -103,8 +103,10 @@ const createContainer = async (project, domain) => { } if (this._app.config.driver.options?.storage?.enabled || this._app.config.driver.options?.storage?.path) { + const localPath = path.join('/opt/persistent-storage', project.id) + mkdirSync(localPath) + chownSync(localPath, 1000, 1000) const projectPath = path.join(this._app.config.driver.options?.storage?.path, project.id) - mkdirSync(projectPath) if (Array.isArray(contOptions.HostConfig?.Binds)) { contOptions.HostConfig.Binds.push(`${projectPath}:/data/storage`) } else { @@ -335,7 +337,7 @@ module.exports = { // const projectPersistentPath = path.join(this._app.config.driver.options?.storage?.path, project.id) // rmSync(projectPersistentPath, { recursive: true, force: true}) // This is better and assumes that directory is mounted on `/opt/storage` - const projectPersistentPath = path.join('/opt/storage', project.id) + 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}`) From 2603d7bd8e534705dc70f1ef99efd31de693cb64 Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Mon, 15 Jul 2024 15:52:01 +0100 Subject: [PATCH 3/5] Fix up paths and logging --- docker.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docker.js b/docker.js index 6ae1b9c..bd3ec19 100644 --- a/docker.js +++ b/docker.js @@ -103,9 +103,14 @@ const createContainer = async (project, domain) => { } if (this._app.config.driver.options?.storage?.enabled || this._app.config.driver.options?.storage?.path) { - const localPath = path.join('/opt/persistent-storage', project.id) - mkdirSync(localPath) - chownSync(localPath, 1000, 1000) + 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`) From 1a7199b7010dbb2cf6c11655aa968f0d9c452b5b Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Mon, 15 Jul 2024 16:47:05 +0100 Subject: [PATCH 4/5] fix lint --- docker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker.js b/docker.js index bd3ec19..b8772f1 100644 --- a/docker.js +++ b/docker.js @@ -343,7 +343,7 @@ module.exports = { // rmSync(projectPersistentPath, { recursive: true, force: true}) // 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}) + rmSync(projectPersistentPath, { recursive: true, force: true }) } catch (err) { this._app.log.error(`[docker] Project ${project.id} - error deleting persistent storage: ${err.stack}`) } From e932deba6ca49b681090b151e983e73567d6c3a5 Mon Sep 17 00:00:00 2001 From: Ben Hardill Date: Tue, 16 Jul 2024 12:50:00 +0100 Subject: [PATCH 5/5] Update docker.js Co-authored-by: Stephen McLaughlin <44235289+Steve-Mcl@users.noreply.github.com> --- docker.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/docker.js b/docker.js index b8772f1..a1da7f1 100644 --- a/docker.js +++ b/docker.js @@ -338,9 +338,6 @@ module.exports = { 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 the wrong path, the directory will need mounting into the forge-docker container - // const projectPersistentPath = path.join(this._app.config.driver.options?.storage?.path, project.id) - // rmSync(projectPersistentPath, { recursive: true, force: true}) // 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 })