From a6ebfb08f7a8eec49d2de0a6528bb71c3e25f184 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Sun, 27 Mar 2022 13:49:04 +0200 Subject: [PATCH] feat: Add n8n.io service --- src/lib/components/svg/services/N8n.svelte | 24 +++++++ src/lib/database/common.ts | 9 +++ src/lib/database/services.ts | 9 ++- .../services/[id]/configuration/type.svelte | 3 + src/routes/services/[id]/index.svelte | 5 ++ src/routes/services/[id]/minio/index.json.ts | 2 +- src/routes/services/[id]/n8n/index.json.ts | 20 ++++++ src/routes/services/[id]/n8n/start.json.ts | 72 +++++++++++++++++++ src/routes/services/[id]/n8n/stop.json.ts | 35 +++++++++ src/routes/services/[id]/nocodb/index.json.ts | 2 +- 10 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 src/lib/components/svg/services/N8n.svelte create mode 100644 src/routes/services/[id]/n8n/index.json.ts create mode 100644 src/routes/services/[id]/n8n/start.json.ts create mode 100644 src/routes/services/[id]/n8n/stop.json.ts diff --git a/src/lib/components/svg/services/N8n.svelte b/src/lib/components/svg/services/N8n.svelte new file mode 100644 index 000000000..04b2e8216 --- /dev/null +++ b/src/lib/components/svg/services/N8n.svelte @@ -0,0 +1,24 @@ + + + + + + + diff --git a/src/lib/database/common.ts b/src/lib/database/common.ts index 4638e483e..67316fd06 100644 --- a/src/lib/database/common.ts +++ b/src/lib/database/common.ts @@ -165,6 +165,15 @@ export const supportedServiceTypesAndVersions = [ ports: { main: 8010 } + }, + { + name: 'n8n', + fancyName: 'n8n', + baseImage: 'n8nio/n8n', + versions: ['latest'], + ports: { + main: 5678 + } } ]; diff --git a/src/lib/database/services.ts b/src/lib/database/services.ts index ea0be0a83..4ed11f7fe 100644 --- a/src/lib/database/services.ts +++ b/src/lib/database/services.ts @@ -119,6 +119,13 @@ export async function configureServiceType({ id, type }) { type } }); + } else if (type === 'n8n') { + await prisma.service.update({ + where: { id }, + data: { + type + } + }); } } export async function setServiceVersion({ id, version }) { @@ -139,7 +146,7 @@ export async function updatePlausibleAnalyticsService({ id, fqdn, email, usernam await prisma.plausibleAnalytics.update({ where: { serviceId: id }, data: { email, username } }); await prisma.service.update({ where: { id }, data: { name, fqdn } }); } -export async function updateNocoDbOrMinioService({ id, fqdn, name }) { +export async function updateService({ id, fqdn, name }) { return await prisma.service.update({ where: { id }, data: { fqdn, name } }); } export async function updateLanguageToolService({ id, fqdn, name }) { diff --git a/src/routes/services/[id]/configuration/type.svelte b/src/routes/services/[id]/configuration/type.svelte index 0dec45c5f..af10189a2 100644 --- a/src/routes/services/[id]/configuration/type.svelte +++ b/src/routes/services/[id]/configuration/type.svelte @@ -38,6 +38,7 @@ import { post } from '$lib/api'; import VaultWarden from '$lib/components/svg/services/VaultWarden.svelte'; import LanguageTool from '$lib/components/svg/services/LanguageTool.svelte'; + import N8n from '$lib/components/svg/services/N8n.svelte'; const { id } = $page.params; const from = $page.url.searchParams.get('from'); @@ -77,6 +78,8 @@ {:else if type.name === 'languagetool'} + {:else if type.name === 'n8n'} + {/if}{type.fancyName} diff --git a/src/routes/services/[id]/index.svelte b/src/routes/services/[id]/index.svelte index 573ec26ac..6dbf5b6f6 100644 --- a/src/routes/services/[id]/index.svelte +++ b/src/routes/services/[id]/index.svelte @@ -39,6 +39,7 @@ import cuid from 'cuid'; import { browser } from '$app/env'; import LanguageTool from '$lib/components/svg/services/LanguageTool.svelte'; + import N8n from '$lib/components/svg/services/N8n.svelte'; export let service; export let isRunning; @@ -109,6 +110,10 @@ + {:else if service.type === 'n8n'} + + + {/if} diff --git a/src/routes/services/[id]/minio/index.json.ts b/src/routes/services/[id]/minio/index.json.ts index be5c0525f..d717502c5 100644 --- a/src/routes/services/[id]/minio/index.json.ts +++ b/src/routes/services/[id]/minio/index.json.ts @@ -13,7 +13,7 @@ export const post: RequestHandler = async (event) => { if (fqdn) fqdn = fqdn.toLowerCase(); try { - await db.updateNocoDbOrMinioService({ id, fqdn, name }); + await db.updateService({ id, fqdn, name }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/services/[id]/n8n/index.json.ts b/src/routes/services/[id]/n8n/index.json.ts new file mode 100644 index 000000000..5ec3fa69a --- /dev/null +++ b/src/routes/services/[id]/n8n/index.json.ts @@ -0,0 +1,20 @@ +import { getUserDetails } from '$lib/common'; +import * as db from '$lib/database'; +import { ErrorHandler } from '$lib/database'; +import type { RequestHandler } from '@sveltejs/kit'; + +export const post: RequestHandler = async (event) => { + const { status, body } = await getUserDetails(event); + if (status === 401) return { status, body }; + const { id } = event.params; + + let { name, fqdn } = await event.request.json(); + if (fqdn) fqdn = fqdn.toLowerCase(); + + try { + await db.updateService({ id, fqdn, name }); + return { status: 201 }; + } catch (error) { + return ErrorHandler(error); + } +}; diff --git a/src/routes/services/[id]/n8n/start.json.ts b/src/routes/services/[id]/n8n/start.json.ts new file mode 100644 index 000000000..6c9f63b76 --- /dev/null +++ b/src/routes/services/[id]/n8n/start.json.ts @@ -0,0 +1,72 @@ +import { asyncExecShell, createDirectories, getEngine, getUserDetails } from '$lib/common'; +import * as db from '$lib/database'; +import { promises as fs } from 'fs'; +import yaml from 'js-yaml'; +import type { RequestHandler } from '@sveltejs/kit'; +import { ErrorHandler, getServiceImage } from '$lib/database'; +import { makeLabelForServices } from '$lib/buildPacks/common'; + +export const post: RequestHandler = async (event) => { + const { teamId, status, body } = await getUserDetails(event); + if (status === 401) return { status, body }; + + const { id } = event.params; + + try { + const service = await db.getService({ id, teamId }); + const { type, version, destinationDockerId, destinationDocker, serviceSecret } = service; + const network = destinationDockerId && destinationDocker.network; + const host = getEngine(destinationDocker.engine); + + const { workdir } = await createDirectories({ repository: type, buildId: id }); + const image = getServiceImage(type); + + const config = { + image: `${image}:${version}`, + volume: `${id}-n8n:/root/.n8n`, + environmentVariables: {} + }; + if (serviceSecret.length > 0) { + serviceSecret.forEach((secret) => { + config.environmentVariables[secret.name] = secret.value; + }); + } + const composeFile = { + version: '3.8', + services: { + [id]: { + container_name: id, + image: config.image, + networks: [network], + volumes: [config.volume], + environment: config.environmentVariables, + restart: 'always', + labels: makeLabelForServices('n8n') + } + }, + networks: { + [network]: { + external: true + } + }, + volumes: { + [config.volume.split(':')[0]]: { + name: config.volume.split(':')[0] + } + } + }; + const composeFileDestination = `${workdir}/docker-compose.yaml`; + await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); + + try { + await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); + return { + status: 200 + }; + } catch (error) { + return ErrorHandler(error); + } + } catch (error) { + return ErrorHandler(error); + } +}; diff --git a/src/routes/services/[id]/n8n/stop.json.ts b/src/routes/services/[id]/n8n/stop.json.ts new file mode 100644 index 000000000..c604e1cc3 --- /dev/null +++ b/src/routes/services/[id]/n8n/stop.json.ts @@ -0,0 +1,35 @@ +import { getUserDetails, removeDestinationDocker } from '$lib/common'; +import * as db from '$lib/database'; +import { ErrorHandler } from '$lib/database'; +import { checkContainer } from '$lib/haproxy'; +import type { RequestHandler } from '@sveltejs/kit'; + +export const post: RequestHandler = async (event) => { + const { teamId, status, body } = await getUserDetails(event); + if (status === 401) return { status, body }; + + const { id } = event.params; + + try { + const service = await db.getService({ id, teamId }); + const { destinationDockerId, destinationDocker, fqdn } = service; + if (destinationDockerId) { + const engine = destinationDocker.engine; + + try { + const found = await checkContainer(engine, id); + if (found) { + await removeDestinationDocker({ id, engine }); + } + } catch (error) { + console.error(error); + } + } + + return { + status: 200 + }; + } catch (error) { + return ErrorHandler(error); + } +}; diff --git a/src/routes/services/[id]/nocodb/index.json.ts b/src/routes/services/[id]/nocodb/index.json.ts index bc9f1a0d1..5ec3fa69a 100644 --- a/src/routes/services/[id]/nocodb/index.json.ts +++ b/src/routes/services/[id]/nocodb/index.json.ts @@ -12,7 +12,7 @@ export const post: RequestHandler = async (event) => { if (fqdn) fqdn = fqdn.toLowerCase(); try { - await db.updateNocoDbOrMinioService({ id, fqdn, name }); + await db.updateService({ id, fqdn, name }); return { status: 201 }; } catch (error) { return ErrorHandler(error);