From 1bd33fea9824b065024e6937701da0cf7b526f48 Mon Sep 17 00:00:00 2001 From: Aaron Styles Date: Fri, 8 Apr 2022 17:12:01 +1000 Subject: [PATCH 1/3] Added expose port for applications --- package.json | 1 + pnpm-lock.yaml | 41 +++++++++++++++++++ .../migration.sql | 2 + prisma/schema.prisma | 1 + src/lib/database/applications.ts | 2 + src/lib/queues/builder.ts | 3 ++ src/routes/applications/[id]/check.json.ts | 16 +++++++- src/routes/applications/[id]/deploy.json.ts | 1 + src/routes/applications/[id]/index.json.ts | 10 +++++ src/routes/applications/[id]/index.svelte | 20 +++++++-- src/routes/webhooks/github/events.ts | 1 + src/routes/webhooks/gitlab/events.ts | 1 + 12 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 prisma/migrations/20220408070805_added_expose_port/migration.sql diff --git a/package.json b/package.json index 2aa11b114..52b9ca453 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@sveltejs/adapter-node": "1.0.0-next.73", "@sveltejs/kit": "1.0.0-next.303", "@types/bcrypt": "5.0.0", + "@types/dockerode": "^3.3.8", "@types/js-cookie": "3.0.1", "@types/js-yaml": "4.0.5", "@types/node": "17.0.23", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 175ba2285..b87591e81 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,7 @@ specifiers: '@sveltejs/adapter-node': 1.0.0-next.73 '@sveltejs/kit': 1.0.0-next.303 '@types/bcrypt': 5.0.0 + '@types/dockerode': ^3.3.8 '@types/js-cookie': 3.0.1 '@types/js-yaml': 4.0.5 '@types/node': 17.0.23 @@ -87,6 +88,7 @@ devDependencies: '@sveltejs/adapter-node': 1.0.0-next.73 '@sveltejs/kit': 1.0.0-next.303_svelte@3.46.4 '@types/bcrypt': 5.0.0 + '@types/dockerode': 3.3.8 '@types/js-cookie': 3.0.1 '@types/js-yaml': 4.0.5 '@types/node': 17.0.23 @@ -505,6 +507,26 @@ packages: '@types/responselike': 1.0.0 dev: false + /@types/docker-modem/3.0.2: + resolution: + { + integrity: sha512-qC7prjoEYR2QEe6SmCVfB1x3rfcQtUr1n4x89+3e0wSTMQ/KYCyf+/RAA9n2tllkkNc6//JMUZePdFRiGIWfaQ== + } + dependencies: + '@types/node': 17.0.23 + '@types/ssh2': 0.5.52 + dev: true + + /@types/dockerode/3.3.8: + resolution: + { + integrity: sha512-/Hip29GzPBWfbSS87lyQDVoB7Ja+kr8oOFWXsySxNFa7jlyj3Yws8LaZRmn1xZl7uJH3Xxsg0oI09GHpT1pIBw== + } + dependencies: + '@types/docker-modem': 3.0.2 + '@types/node': 17.0.23 + dev: true + /@types/http-cache-semantics/4.0.1: resolution: { @@ -589,6 +611,25 @@ packages: '@types/node': 17.0.23 dev: true + /@types/ssh2-streams/0.1.9: + resolution: + { + integrity: sha512-I2J9jKqfmvXLR5GomDiCoHrEJ58hAOmFrekfFqmCFd+A6gaEStvWnPykoWUwld1PNg4G5ag1LwdA+Lz1doRJqg== + } + dependencies: + '@types/node': 17.0.23 + dev: true + + /@types/ssh2/0.5.52: + resolution: + { + integrity: sha512-lbLLlXxdCZOSJMCInKH2+9V/77ET2J6NPQHpFI0kda61Dd1KglJs+fPQBchizmzYSOJBgdTajhPqBO1xxLywvg== + } + dependencies: + '@types/node': 17.0.23 + '@types/ssh2-streams': 0.1.9 + dev: true + /@typescript-eslint/eslint-plugin/4.31.1_8ede7edd7694646e12d33c52460f622c: resolution: { diff --git a/prisma/migrations/20220408070805_added_expose_port/migration.sql b/prisma/migrations/20220408070805_added_expose_port/migration.sql new file mode 100644 index 000000000..a23afd64a --- /dev/null +++ b/prisma/migrations/20220408070805_added_expose_port/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Application" ADD COLUMN "exposePort" INTEGER; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 986a773bf..0a758bc60 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -81,6 +81,7 @@ model Application { buildPack String? projectId Int? port Int? + exposePort Int? installCommand String? buildCommand String? startCommand String? diff --git a/src/lib/database/applications.ts b/src/lib/database/applications.ts index 1d8140144..556188169 100644 --- a/src/lib/database/applications.ts +++ b/src/lib/database/applications.ts @@ -210,6 +210,7 @@ export async function configureApplication({ name, fqdn, port, + exposePort, installCommand, buildCommand, startCommand, @@ -226,6 +227,7 @@ export async function configureApplication({ buildPack, fqdn, port, + exposePort, installCommand, buildCommand, startCommand, diff --git a/src/lib/queues/builder.ts b/src/lib/queues/builder.ts index f6d57862e..0134bad20 100644 --- a/src/lib/queues/builder.ts +++ b/src/lib/queues/builder.ts @@ -38,6 +38,7 @@ export default async function (job) { build_id: buildId, configHash, port, + exposePort, installCommand, buildCommand, startCommand, @@ -143,6 +144,7 @@ export default async function (job) { JSON.stringify({ buildPack, port, + exposePort, installCommand, buildCommand, startCommand, @@ -284,6 +286,7 @@ export default async function (job) { env_file: envFound ? [`${workdir}/.env`] : [], networks: [docker.network], labels: labels, + ports: exposePort ? [`${exposePort}:${port}`] : [], depends_on: [], restart: 'always' } diff --git a/src/routes/applications/[id]/check.json.ts b/src/routes/applications/[id]/check.json.ts index dc1b8ea98..56ea05ee1 100644 --- a/src/routes/applications/[id]/check.json.ts +++ b/src/routes/applications/[id]/check.json.ts @@ -4,13 +4,14 @@ import * as db from '$lib/database'; import { ErrorHandler } from '$lib/database'; import type { RequestHandler } from '@sveltejs/kit'; import { promises as dns } from 'dns'; +import getPort from 'get-port'; export const post: RequestHandler = async (event) => { const { status, body } = await getUserDetails(event); if (status === 401) return { status, body }; const { id } = event.params; - let { fqdn, forceSave } = await event.request.json(); + let { exposePort, fqdn, forceSave } = await event.request.json(); fqdn = fqdn.toLowerCase(); try { @@ -42,6 +43,19 @@ export const post: RequestHandler = async (event) => { } } + if (exposePort) { + exposePort = Number(exposePort); + + if (exposePort < 1024 || exposePort > 65535) { + throw { message: `Expose Port needs to be between 1024 and 65535` }; + } + + const publicPort = await getPort({ port: exposePort }); + if (exposePort !== publicPort) { + throw { message: `Expose Port ${exposePort} is already in use` }; + } + } + return { status: 200 }; diff --git a/src/routes/applications/[id]/deploy.json.ts b/src/routes/applications/[id]/deploy.json.ts index 59bd7d001..e8589cf16 100644 --- a/src/routes/applications/[id]/deploy.json.ts +++ b/src/routes/applications/[id]/deploy.json.ts @@ -22,6 +22,7 @@ export const post: RequestHandler = async (event) => { JSON.stringify({ buildPack: applicationFound.buildPack, port: applicationFound.port, + exposePort: applicationFound.exposePort, installCommand: applicationFound.installCommand, buildCommand: applicationFound.buildCommand, startCommand: applicationFound.startCommand diff --git a/src/routes/applications/[id]/index.json.ts b/src/routes/applications/[id]/index.json.ts index 8a67242d2..4b9e88d79 100644 --- a/src/routes/applications/[id]/index.json.ts +++ b/src/routes/applications/[id]/index.json.ts @@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit'; import jsonwebtoken from 'jsonwebtoken'; import { get as getRequest } from '$lib/api'; import { setDefaultConfiguration } from '$lib/buildPacks/common'; +import getPort from 'get-port'; export const get: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -49,6 +50,7 @@ export const post: RequestHandler = async (event) => { buildPack, fqdn, port, + exposePort, installCommand, buildCommand, startCommand, @@ -59,6 +61,13 @@ export const post: RequestHandler = async (event) => { pythonVariable } = await event.request.json(); if (port) port = Number(port); + if (exposePort) { + exposePort = Number(exposePort); + const publicPort = await getPort({ port: exposePort }); + if (exposePort !== publicPort) { + exposePort = -1; + } + } try { const defaultConfiguration = await setDefaultConfiguration({ @@ -76,6 +85,7 @@ export const post: RequestHandler = async (event) => { name, fqdn, port, + exposePort, installCommand, buildCommand, startCommand, diff --git a/src/routes/applications/[id]/index.svelte b/src/routes/applications/[id]/index.svelte index 4b7d6b497..c7c0ca125 100644 --- a/src/routes/applications/[id]/index.svelte +++ b/src/routes/applications/[id]/index.svelte @@ -125,7 +125,11 @@ async function handleSubmit() { loading = true; try { - await post(`/applications/${id}/check.json`, { fqdn: application.fqdn, forceSave }); + await post(`/applications/${id}/check.json`, { + fqdn: application.fqdn, + forceSave, + exposePort: application.exposePort + }); await post(`/applications/${id}.json`, { ...application }); return window.location.reload(); } catch ({ error }) { @@ -326,7 +330,6 @@ bind:value={application.fqdn} pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$" placeholder="eg: https://coollabs.io" - required />
@@ -385,7 +388,18 @@ />
{/if} - + {#if !staticDeployments.includes(application.buildPack)} +
+ + +
+ {/if} {#if !notNodeDeployments.includes(application.buildPack)}
+ + {#if showExposePort} +
+ + +
+ {/if} {/if} {#if !notNodeDeployments.includes(application.buildPack)}
diff --git a/src/routes/services/[id]/wordpress/settings.json.ts b/src/routes/services/[id]/wordpress/settings.json.ts index 4f9c1f9b2..cee85bc41 100644 --- a/src/routes/services/[id]/wordpress/settings.json.ts +++ b/src/routes/services/[id]/wordpress/settings.json.ts @@ -8,7 +8,6 @@ import type { ComposeFile } from '$lib/types/composeFile'; import type { RequestHandler } from '@sveltejs/kit'; import cuid from 'cuid'; import fs from 'fs/promises'; -import getPort, { portNumbers } from 'get-port'; import yaml from 'js-yaml'; export const post: RequestHandler = async (event) => { From f94e17134e511ffcc7e5fce91f88922bd2ad33de Mon Sep 17 00:00:00 2001 From: Aaron Styles Date: Sat, 30 Apr 2022 22:47:00 +1000 Subject: [PATCH 3/3] Added expose port for Services --- .../migration.sql | 2 ++ prisma/schema.prisma | 1 + src/lib/components/common.ts | 8 +++++ src/lib/database/services.ts | 32 ++++++++++++++----- src/lib/queues/builder.ts | 2 +- .../services/[id]/_Services/_Services.svelte | 27 ++++++++++++++++ src/routes/services/[id]/ghost/index.json.ts | 3 +- src/routes/services/[id]/ghost/start.json.ts | 5 +++ .../services/[id]/languagetool/index.json.ts | 6 ++-- .../services/[id]/languagetool/start.json.ts | 6 +++- .../services/[id]/meilisearch/index.json.ts | 5 +-- .../services/[id]/meilisearch/start.json.ts | 6 +++- src/routes/services/[id]/minio/index.json.ts | 5 +-- src/routes/services/[id]/minio/start.json.ts | 4 +++ src/routes/services/[id]/n8n/index.json.ts | 5 +-- src/routes/services/[id]/n8n/start.json.ts | 5 ++- src/routes/services/[id]/nocodb/index.json.ts | 5 +-- src/routes/services/[id]/nocodb/start.json.ts | 6 +++- .../[id]/plausibleanalytics/index.json.ts | 4 ++- .../[id]/plausibleanalytics/start.json.ts | 4 +++ src/routes/services/[id]/umami/index.json.ts | 5 +-- src/routes/services/[id]/umami/start.json.ts | 4 +++ .../services/[id]/uptimekuma/index.json.ts | 5 +-- .../services/[id]/uptimekuma/start.json.ts | 6 +++- .../services/[id]/vaultwarden/index.json.ts | 5 +-- .../services/[id]/vaultwarden/start.json.ts | 6 +++- .../services/[id]/vscodeserver/index.json.ts | 5 +-- .../services/[id]/vscodeserver/start.json.ts | 4 +++ .../services/[id]/wordpress/index.json.ts | 4 ++- .../services/[id]/wordpress/start.json.ts | 4 +++ 30 files changed, 153 insertions(+), 36 deletions(-) create mode 100644 prisma/migrations/20220430124553_expose_port_for_services/migration.sql diff --git a/prisma/migrations/20220430124553_expose_port_for_services/migration.sql b/prisma/migrations/20220430124553_expose_port_for_services/migration.sql new file mode 100644 index 000000000..fdbab5713 --- /dev/null +++ b/prisma/migrations/20220430124553_expose_port_for_services/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Service" ADD COLUMN "exposePort" INTEGER; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 6cd94b395..20f655cee 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -287,6 +287,7 @@ model Service { id String @id @default(cuid()) name String fqdn String? + exposePort Int? dualCerts Boolean @default(false) type String? version String? diff --git a/src/lib/components/common.ts b/src/lib/components/common.ts index 760653cfa..e39c529bb 100644 --- a/src/lib/components/common.ts +++ b/src/lib/components/common.ts @@ -193,3 +193,11 @@ export const supportedServiceTypesAndVersions = [ } } ]; + +export const getServiceMainPort = (service: string) => { + const serviceType = supportedServiceTypesAndVersions.find((s) => s.name === service); + if (serviceType) { + return serviceType.ports.main; + } + return null; +}; diff --git a/src/lib/database/services.ts b/src/lib/database/services.ts index 4cb2e8b22..1831385cb 100644 --- a/src/lib/database/services.ts +++ b/src/lib/database/services.ts @@ -276,95 +276,109 @@ export async function updatePlausibleAnalyticsService({ id, fqdn, email, + exposePort, username, name }: { id: string; fqdn: string; + exposePort?: number; name: string; email: string; username: string; }): Promise { await prisma.plausibleAnalytics.update({ where: { serviceId: id }, data: { email, username } }); - await prisma.service.update({ where: { id }, data: { name, fqdn } }); + await prisma.service.update({ where: { id }, data: { name, fqdn, exposePort } }); } export async function updateService({ id, fqdn, + exposePort, name }: { id: string; fqdn: string; + exposePort?: number; name: string; }): Promise { - return await prisma.service.update({ where: { id }, data: { fqdn, name } }); + return await prisma.service.update({ where: { id }, data: { fqdn, name, exposePort } }); } export async function updateLanguageToolService({ id, fqdn, + exposePort, name }: { id: string; fqdn: string; + exposePort?: number; name: string; }): Promise { - return await prisma.service.update({ where: { id }, data: { fqdn, name } }); + return await prisma.service.update({ where: { id }, data: { fqdn, name, exposePort } }); } export async function updateMeiliSearchService({ id, fqdn, + exposePort, name }: { id: string; fqdn: string; + exposePort?: number; name: string; }): Promise { - return await prisma.service.update({ where: { id }, data: { fqdn, name } }); + return await prisma.service.update({ where: { id }, data: { fqdn, name, exposePort } }); } export async function updateVaultWardenService({ id, fqdn, + exposePort, name }: { id: string; fqdn: string; + exposePort?: number; name: string; }): Promise { - return await prisma.service.update({ where: { id }, data: { fqdn, name } }); + return await prisma.service.update({ where: { id }, data: { fqdn, name, exposePort } }); } export async function updateVsCodeServer({ id, fqdn, + exposePort, name }: { id: string; fqdn: string; + exposePort?: number; name: string; }): Promise { - return await prisma.service.update({ where: { id }, data: { fqdn, name } }); + return await prisma.service.update({ where: { id }, data: { fqdn, name, exposePort } }); } export async function updateWordpress({ id, fqdn, name, + exposePort, mysqlDatabase, extraConfig }: { id: string; fqdn: string; name: string; + exposePort?: number; mysqlDatabase: string; extraConfig: string; }): Promise { return await prisma.service.update({ where: { id }, - data: { fqdn, name, wordpress: { update: { mysqlDatabase, extraConfig } } } + data: { fqdn, name, exposePort, wordpress: { update: { mysqlDatabase, extraConfig } } } }); } @@ -382,16 +396,18 @@ export async function updateGhostService({ id, fqdn, name, + exposePort, mariadbDatabase }: { id: string; fqdn: string; name: string; + exposePort?: number; mariadbDatabase: string; }): Promise { return await prisma.service.update({ where: { id }, - data: { fqdn, name, ghost: { update: { mariadbDatabase } } } + data: { fqdn, name, exposePort, ghost: { update: { mariadbDatabase } } } }); } diff --git a/src/lib/queues/builder.ts b/src/lib/queues/builder.ts index a6cf0af75..6d5cbb263 100644 --- a/src/lib/queues/builder.ts +++ b/src/lib/queues/builder.ts @@ -189,7 +189,7 @@ export default async function (job: Job): Promise !isRunning && changeSettings('dualCerts')} />
+
+ { + showExposePort = !showExposePort; + service.exposePort = undefined; + }} + title={$t('application.expose_a_port')} + description="Expose a port to the host system" + /> +
+ + {#if showExposePort} +
+ + +
+ {/if} + {#if service.type === 'plausibleanalytics'} {:else if service.type === 'minio'} diff --git a/src/routes/services/[id]/ghost/index.json.ts b/src/routes/services/[id]/ghost/index.json.ts index 81ca8ade1..1b1225f59 100644 --- a/src/routes/services/[id]/ghost/index.json.ts +++ b/src/routes/services/[id]/ghost/index.json.ts @@ -11,11 +11,12 @@ export const post: RequestHandler = async (event) => { let { name, fqdn, + exposePort, ghost: { mariadbDatabase } } = await event.request.json(); if (fqdn) fqdn = fqdn.toLowerCase(); try { - await db.updateGhostService({ id, fqdn, name, mariadbDatabase }); + await db.updateGhostService({ id, fqdn, name, exposePort, mariadbDatabase }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/services/[id]/ghost/start.json.ts b/src/routes/services/[id]/ghost/start.json.ts index 45c6936fe..67e9364b9 100644 --- a/src/routes/services/[id]/ghost/start.json.ts +++ b/src/routes/services/[id]/ghost/start.json.ts @@ -12,6 +12,7 @@ import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; import type { ComposeFile } from '$lib/types/composeFile'; +import { getServiceMainPort } from '$lib/components/common'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -19,6 +20,8 @@ export const post: RequestHandler = async (event) => { const { id } = event.params; + const port = getServiceMainPort('ghost'); + try { const service = await db.getService({ id, teamId }); const { @@ -27,6 +30,7 @@ export const post: RequestHandler = async (event) => { destinationDockerId, destinationDocker, serviceSecret, + exposePort, fqdn, ghost: { defaultEmail, @@ -89,6 +93,7 @@ export const post: RequestHandler = async (event) => { volumes: [config.ghost.volume], environment: config.ghost.environmentVariables, restart: 'always', + ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), labels: makeLabelForServices('ghost'), depends_on: [`${id}-mariadb`], deploy: { diff --git a/src/routes/services/[id]/languagetool/index.json.ts b/src/routes/services/[id]/languagetool/index.json.ts index d717502c5..dcba0b6f8 100644 --- a/src/routes/services/[id]/languagetool/index.json.ts +++ b/src/routes/services/[id]/languagetool/index.json.ts @@ -9,13 +9,15 @@ export const post: RequestHandler = async (event) => { const { id } = event.params; - let { name, fqdn } = await event.request.json(); + let { name, fqdn, exposePort } = await event.request.json(); if (fqdn) fqdn = fqdn.toLowerCase(); + if (exposePort) exposePort = Number(exposePort); try { - await db.updateService({ id, fqdn, name }); + await db.updateService({ id, fqdn, name, exposePort }); return { status: 201 }; } catch (error) { + console.log(error); return ErrorHandler(error); } }; diff --git a/src/routes/services/[id]/languagetool/start.json.ts b/src/routes/services/[id]/languagetool/start.json.ts index e11263161..0818ac6f7 100644 --- a/src/routes/services/[id]/languagetool/start.json.ts +++ b/src/routes/services/[id]/languagetool/start.json.ts @@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; import type { ComposeFile } from '$lib/types/composeFile'; +import { getServiceMainPort } from '$lib/components/common'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -15,9 +16,11 @@ export const post: RequestHandler = async (event) => { try { const service = await db.getService({ id, teamId }); - const { type, version, destinationDockerId, destinationDocker, serviceSecret } = service; + const { type, version, destinationDockerId, destinationDocker, serviceSecret, exposePort } = + service; const network = destinationDockerId && destinationDocker.network; const host = getEngine(destinationDocker.engine); + const port = getServiceMainPort('languagetool'); const { workdir } = await createDirectories({ repository: type, buildId: id }); const image = getServiceImage(type); @@ -42,6 +45,7 @@ export const post: RequestHandler = async (event) => { networks: [network], environment: config.environmentVariables, restart: 'always', + ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), volumes: [config.volume], labels: makeLabelForServices('languagetool'), deploy: { diff --git a/src/routes/services/[id]/meilisearch/index.json.ts b/src/routes/services/[id]/meilisearch/index.json.ts index d717502c5..ff98ede6d 100644 --- a/src/routes/services/[id]/meilisearch/index.json.ts +++ b/src/routes/services/[id]/meilisearch/index.json.ts @@ -9,11 +9,12 @@ export const post: RequestHandler = async (event) => { const { id } = event.params; - let { name, fqdn } = await event.request.json(); + let { name, fqdn, exposePort } = await event.request.json(); if (fqdn) fqdn = fqdn.toLowerCase(); + if (exposePort) exposePort = Number(exposePort); try { - await db.updateService({ id, fqdn, name }); + await db.updateService({ id, fqdn, name, exposePort }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/services/[id]/meilisearch/start.json.ts b/src/routes/services/[id]/meilisearch/start.json.ts index 1f11054a8..b019d69b9 100644 --- a/src/routes/services/[id]/meilisearch/start.json.ts +++ b/src/routes/services/[id]/meilisearch/start.json.ts @@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; import type { ComposeFile } from '$lib/types/composeFile'; +import { getServiceMainPort } from '$lib/components/common'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -18,9 +19,11 @@ export const post: RequestHandler = async (event) => { const { meiliSearch: { masterKey } } = service; - const { type, version, destinationDockerId, destinationDocker, serviceSecret } = service; + const { type, version, destinationDockerId, destinationDocker, serviceSecret, exposePort } = + service; const network = destinationDockerId && destinationDocker.network; const host = getEngine(destinationDocker.engine); + const port = getServiceMainPort('meilisearch'); const { workdir } = await createDirectories({ repository: type, buildId: id }); const image = getServiceImage(type); @@ -47,6 +50,7 @@ export const post: RequestHandler = async (event) => { networks: [network], environment: config.environmentVariables, restart: 'always', + ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), volumes: [config.volume], labels: makeLabelForServices('meilisearch'), deploy: { diff --git a/src/routes/services/[id]/minio/index.json.ts b/src/routes/services/[id]/minio/index.json.ts index d717502c5..ff98ede6d 100644 --- a/src/routes/services/[id]/minio/index.json.ts +++ b/src/routes/services/[id]/minio/index.json.ts @@ -9,11 +9,12 @@ export const post: RequestHandler = async (event) => { const { id } = event.params; - let { name, fqdn } = await event.request.json(); + let { name, fqdn, exposePort } = await event.request.json(); if (fqdn) fqdn = fqdn.toLowerCase(); + if (exposePort) exposePort = Number(exposePort); try { - await db.updateService({ id, fqdn, name }); + await db.updateService({ id, fqdn, name, exposePort }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/services/[id]/minio/start.json.ts b/src/routes/services/[id]/minio/start.json.ts index c744eae80..3782bf467 100644 --- a/src/routes/services/[id]/minio/start.json.ts +++ b/src/routes/services/[id]/minio/start.json.ts @@ -7,6 +7,7 @@ import { startHttpProxy } from '$lib/haproxy'; import { ErrorHandler, getFreePort, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; import type { ComposeFile } from '$lib/types/composeFile'; +import { getServiceMainPort } from '$lib/components/common'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -22,12 +23,14 @@ export const post: RequestHandler = async (event) => { fqdn, destinationDockerId, destinationDocker, + exposePort, minio: { rootUser, rootUserPassword }, serviceSecret } = service; const network = destinationDockerId && destinationDocker.network; const host = getEngine(destinationDocker.engine); + const port = getServiceMainPort('minio'); const publicPort = await getFreePort(); @@ -62,6 +65,7 @@ export const post: RequestHandler = async (event) => { networks: [network], volumes: [config.volume], restart: 'always', + ...(exposePort && { ports: [`${port}:${port}`] }), labels: makeLabelForServices('minio'), deploy: { restart_policy: { diff --git a/src/routes/services/[id]/n8n/index.json.ts b/src/routes/services/[id]/n8n/index.json.ts index 5ec3fa69a..e269e8fe7 100644 --- a/src/routes/services/[id]/n8n/index.json.ts +++ b/src/routes/services/[id]/n8n/index.json.ts @@ -8,11 +8,12 @@ export const post: RequestHandler = async (event) => { if (status === 401) return { status, body }; const { id } = event.params; - let { name, fqdn } = await event.request.json(); + let { name, fqdn, exposePort } = await event.request.json(); if (fqdn) fqdn = fqdn.toLowerCase(); + if (exposePort) exposePort = Number(exposePort); try { - await db.updateService({ id, fqdn, name }); + await db.updateService({ id, fqdn, name, exposePort }); 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 index 7386a4fd9..cca55b61e 100644 --- a/src/routes/services/[id]/n8n/start.json.ts +++ b/src/routes/services/[id]/n8n/start.json.ts @@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; import type { ComposeFile } from '$lib/types/composeFile'; +import { getServiceMainPort } from '$lib/components/common'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -15,9 +16,11 @@ export const post: RequestHandler = async (event) => { try { const service = await db.getService({ id, teamId }); - const { type, version, destinationDockerId, destinationDocker, serviceSecret } = service; + const { type, version, destinationDockerId, destinationDocker, serviceSecret, exposePort } = + service; const network = destinationDockerId && destinationDocker.network; const host = getEngine(destinationDocker.engine); + const port = getServiceMainPort('n8n'); const { workdir } = await createDirectories({ repository: type, buildId: id }); const image = getServiceImage(type); diff --git a/src/routes/services/[id]/nocodb/index.json.ts b/src/routes/services/[id]/nocodb/index.json.ts index 5ec3fa69a..e269e8fe7 100644 --- a/src/routes/services/[id]/nocodb/index.json.ts +++ b/src/routes/services/[id]/nocodb/index.json.ts @@ -8,11 +8,12 @@ export const post: RequestHandler = async (event) => { if (status === 401) return { status, body }; const { id } = event.params; - let { name, fqdn } = await event.request.json(); + let { name, fqdn, exposePort } = await event.request.json(); if (fqdn) fqdn = fqdn.toLowerCase(); + if (exposePort) exposePort = Number(exposePort); try { - await db.updateService({ id, fqdn, name }); + await db.updateService({ id, fqdn, name, exposePort }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/services/[id]/nocodb/start.json.ts b/src/routes/services/[id]/nocodb/start.json.ts index 4933a5347..bf3a702df 100644 --- a/src/routes/services/[id]/nocodb/start.json.ts +++ b/src/routes/services/[id]/nocodb/start.json.ts @@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; import type { ComposeFile } from '$lib/types/composeFile'; +import { getServiceMainPort } from '$lib/components/common'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -15,9 +16,11 @@ export const post: RequestHandler = async (event) => { try { const service = await db.getService({ id, teamId }); - const { type, version, destinationDockerId, destinationDocker, serviceSecret } = service; + const { type, version, destinationDockerId, destinationDocker, serviceSecret, exposePort } = + service; const network = destinationDockerId && destinationDocker.network; const host = getEngine(destinationDocker.engine); + const port = getServiceMainPort('nocodb'); const { workdir } = await createDirectories({ repository: type, buildId: id }); const image = getServiceImage(type); @@ -40,6 +43,7 @@ export const post: RequestHandler = async (event) => { networks: [network], environment: config.environmentVariables, restart: 'always', + ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), labels: makeLabelForServices('nocodb'), deploy: { restart_policy: { diff --git a/src/routes/services/[id]/plausibleanalytics/index.json.ts b/src/routes/services/[id]/plausibleanalytics/index.json.ts index 519b582a2..0a5d375e7 100644 --- a/src/routes/services/[id]/plausibleanalytics/index.json.ts +++ b/src/routes/services/[id]/plausibleanalytics/index.json.ts @@ -11,14 +11,16 @@ export const post: RequestHandler = async (event) => { let { name, fqdn, + exposePort, plausibleAnalytics: { email, username } } = await event.request.json(); if (fqdn) fqdn = fqdn.toLowerCase(); if (email) email = email.toLowerCase(); + if (exposePort) exposePort = Number(exposePort); try { - await db.updatePlausibleAnalyticsService({ id, fqdn, name, email, username }); + await db.updatePlausibleAnalyticsService({ id, fqdn, name, email, username, exposePort }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/services/[id]/plausibleanalytics/start.json.ts b/src/routes/services/[id]/plausibleanalytics/start.json.ts index 8b61e1ff8..8adce773a 100644 --- a/src/routes/services/[id]/plausibleanalytics/start.json.ts +++ b/src/routes/services/[id]/plausibleanalytics/start.json.ts @@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; import type { ComposeFile } from '$lib/types/composeFile'; +import { getServiceMainPort } from '$lib/components/common'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -22,6 +23,7 @@ export const post: RequestHandler = async (event) => { destinationDockerId, destinationDocker, serviceSecret, + exposePort, plausibleAnalytics: { id: plausibleDbId, username, @@ -78,6 +80,7 @@ export const post: RequestHandler = async (event) => { } const network = destinationDockerId && destinationDocker.network; const host = getEngine(destinationDocker.engine); + const port = getServiceMainPort('plausibleanalytics'); const { workdir } = await createDirectories({ repository: type, buildId: id }); @@ -132,6 +135,7 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`; networks: [network], environment: config.plausibleAnalytics.environmentVariables, restart: 'always', + ...(exposePort && { ports: [`${port}:${exposePort}`] }), depends_on: [`${id}-postgresql`, `${id}-clickhouse`], labels: makeLabelForServices('plausibleAnalytics'), deploy: { diff --git a/src/routes/services/[id]/umami/index.json.ts b/src/routes/services/[id]/umami/index.json.ts index d717502c5..ff98ede6d 100644 --- a/src/routes/services/[id]/umami/index.json.ts +++ b/src/routes/services/[id]/umami/index.json.ts @@ -9,11 +9,12 @@ export const post: RequestHandler = async (event) => { const { id } = event.params; - let { name, fqdn } = await event.request.json(); + let { name, fqdn, exposePort } = await event.request.json(); if (fqdn) fqdn = fqdn.toLowerCase(); + if (exposePort) exposePort = Number(exposePort); try { - await db.updateService({ id, fqdn, name }); + await db.updateService({ id, fqdn, name, exposePort }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/services/[id]/umami/start.json.ts b/src/routes/services/[id]/umami/start.json.ts index 6a51e5cde..c2cd78fe4 100644 --- a/src/routes/services/[id]/umami/start.json.ts +++ b/src/routes/services/[id]/umami/start.json.ts @@ -8,6 +8,7 @@ import { makeLabelForServices } from '$lib/buildPacks/common'; import type { ComposeFile } from '$lib/types/composeFile'; import type { Service, DestinationDocker, Prisma } from '@prisma/client'; import bcrypt from 'bcryptjs'; +import { getServiceMainPort } from '$lib/components/common'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -24,6 +25,7 @@ export const post: RequestHandler = async (event) => { destinationDockerId, destinationDocker, serviceSecret, + exposePort, umami: { umamiAdminPassword, postgresqlUser, @@ -34,6 +36,7 @@ export const post: RequestHandler = async (event) => { } = service; const network = destinationDockerId && destinationDocker.network; const host = getEngine(destinationDocker.engine); + const port = getServiceMainPort('umami'); const { workdir } = await createDirectories({ repository: type, buildId: id }); const image = getServiceImage(type); @@ -156,6 +159,7 @@ export const post: RequestHandler = async (event) => { networks: [network], volumes: [], restart: 'always', + ...(exposePort ? { ports: [`${port}:${port}`] } : {}), labels: makeLabelForServices('umami'), deploy: { restart_policy: { diff --git a/src/routes/services/[id]/uptimekuma/index.json.ts b/src/routes/services/[id]/uptimekuma/index.json.ts index 5ec3fa69a..e269e8fe7 100644 --- a/src/routes/services/[id]/uptimekuma/index.json.ts +++ b/src/routes/services/[id]/uptimekuma/index.json.ts @@ -8,11 +8,12 @@ export const post: RequestHandler = async (event) => { if (status === 401) return { status, body }; const { id } = event.params; - let { name, fqdn } = await event.request.json(); + let { name, fqdn, exposePort } = await event.request.json(); if (fqdn) fqdn = fqdn.toLowerCase(); + if (exposePort) exposePort = Number(exposePort); try { - await db.updateService({ id, fqdn, name }); + await db.updateService({ id, fqdn, name, exposePort }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/services/[id]/uptimekuma/start.json.ts b/src/routes/services/[id]/uptimekuma/start.json.ts index 6327db0ec..9032ce469 100644 --- a/src/routes/services/[id]/uptimekuma/start.json.ts +++ b/src/routes/services/[id]/uptimekuma/start.json.ts @@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; import type { ComposeFile } from '$lib/types/composeFile'; +import { getServiceMainPort } from '$lib/components/common'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -15,9 +16,11 @@ export const post: RequestHandler = async (event) => { try { const service = await db.getService({ id, teamId }); - const { type, version, destinationDockerId, destinationDocker, serviceSecret } = service; + const { type, version, destinationDockerId, destinationDocker, serviceSecret, exposePort } = + service; const network = destinationDockerId && destinationDocker.network; const host = getEngine(destinationDocker.engine); + const port = getServiceMainPort('uptimekuma'); const { workdir } = await createDirectories({ repository: type, buildId: id }); const image = getServiceImage(type); @@ -42,6 +45,7 @@ export const post: RequestHandler = async (event) => { volumes: [config.volume], environment: config.environmentVariables, restart: 'always', + ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), labels: makeLabelForServices('uptimekuma'), deploy: { restart_policy: { diff --git a/src/routes/services/[id]/vaultwarden/index.json.ts b/src/routes/services/[id]/vaultwarden/index.json.ts index 5ec3fa69a..e269e8fe7 100644 --- a/src/routes/services/[id]/vaultwarden/index.json.ts +++ b/src/routes/services/[id]/vaultwarden/index.json.ts @@ -8,11 +8,12 @@ export const post: RequestHandler = async (event) => { if (status === 401) return { status, body }; const { id } = event.params; - let { name, fqdn } = await event.request.json(); + let { name, fqdn, exposePort } = await event.request.json(); if (fqdn) fqdn = fqdn.toLowerCase(); + if (exposePort) exposePort = Number(exposePort); try { - await db.updateService({ id, fqdn, name }); + await db.updateService({ id, fqdn, name, exposePort }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/services/[id]/vaultwarden/start.json.ts b/src/routes/services/[id]/vaultwarden/start.json.ts index 511b040a3..41b790266 100644 --- a/src/routes/services/[id]/vaultwarden/start.json.ts +++ b/src/routes/services/[id]/vaultwarden/start.json.ts @@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit'; import { getServiceImage, ErrorHandler } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; import type { ComposeFile } from '$lib/types/composeFile'; +import { getServiceMainPort } from '$lib/components/common'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -15,10 +16,12 @@ export const post: RequestHandler = async (event) => { try { const service = await db.getService({ id, teamId }); - const { type, version, destinationDockerId, destinationDocker, serviceSecret } = service; + const { type, version, destinationDockerId, destinationDocker, serviceSecret, exposePort } = + service; const network = destinationDockerId && destinationDocker.network; const host = getEngine(destinationDocker.engine); + const port = getServiceMainPort('vaultwarden'); const { workdir } = await createDirectories({ repository: type, buildId: id }); const image = getServiceImage(type); @@ -43,6 +46,7 @@ export const post: RequestHandler = async (event) => { networks: [network], volumes: [config.volume], restart: 'always', + ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), labels: makeLabelForServices('vaultWarden'), deploy: { restart_policy: { diff --git a/src/routes/services/[id]/vscodeserver/index.json.ts b/src/routes/services/[id]/vscodeserver/index.json.ts index d717502c5..ff98ede6d 100644 --- a/src/routes/services/[id]/vscodeserver/index.json.ts +++ b/src/routes/services/[id]/vscodeserver/index.json.ts @@ -9,11 +9,12 @@ export const post: RequestHandler = async (event) => { const { id } = event.params; - let { name, fqdn } = await event.request.json(); + let { name, fqdn, exposePort } = await event.request.json(); if (fqdn) fqdn = fqdn.toLowerCase(); + if (exposePort) exposePort = Number(exposePort); try { - await db.updateService({ id, fqdn, name }); + await db.updateService({ id, fqdn, name, exposePort }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/services/[id]/vscodeserver/start.json.ts b/src/routes/services/[id]/vscodeserver/start.json.ts index 4ca29c215..1501a43c6 100644 --- a/src/routes/services/[id]/vscodeserver/start.json.ts +++ b/src/routes/services/[id]/vscodeserver/start.json.ts @@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; import type { ComposeFile } from '$lib/types/composeFile'; +import { getServiceMainPort } from '$lib/components/common'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -22,11 +23,13 @@ export const post: RequestHandler = async (event) => { destinationDocker, serviceSecret, persistentStorage, + exposePort, vscodeserver: { password } } = service; const network = destinationDockerId && destinationDocker.network; const host = getEngine(destinationDocker.engine); + const port = getServiceMainPort('vscodeserver'); const { workdir } = await createDirectories({ repository: type, buildId: id }); const image = getServiceImage(type); @@ -75,6 +78,7 @@ export const post: RequestHandler = async (event) => { networks: [network], volumes: [config.volume, ...volumes], restart: 'always', + ...(exposePort ? { ports: [`${port}:${exposePort}`] } : {}), labels: makeLabelForServices('vscodeServer'), deploy: { restart_policy: { diff --git a/src/routes/services/[id]/wordpress/index.json.ts b/src/routes/services/[id]/wordpress/index.json.ts index 413bd1f75..c76cd1a92 100644 --- a/src/routes/services/[id]/wordpress/index.json.ts +++ b/src/routes/services/[id]/wordpress/index.json.ts @@ -11,12 +11,14 @@ export const post: RequestHandler = async (event) => { let { name, fqdn, + exposePort, wordpress: { extraConfig, mysqlDatabase } } = await event.request.json(); if (fqdn) fqdn = fqdn.toLowerCase(); + if (exposePort) exposePort = Number(exposePort); try { - await db.updateWordpress({ id, fqdn, name, extraConfig, mysqlDatabase }); + await db.updateWordpress({ id, fqdn, name, extraConfig, mysqlDatabase, exposePort }); return { status: 201 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/services/[id]/wordpress/start.json.ts b/src/routes/services/[id]/wordpress/start.json.ts index 0572be971..43bab2e9d 100644 --- a/src/routes/services/[id]/wordpress/start.json.ts +++ b/src/routes/services/[id]/wordpress/start.json.ts @@ -6,6 +6,7 @@ import type { RequestHandler } from '@sveltejs/kit'; import { ErrorHandler, getServiceImage } from '$lib/database'; import { makeLabelForServices } from '$lib/buildPacks/common'; import type { ComposeFile } from '$lib/types/composeFile'; +import { getServiceMainPort } from '$lib/components/common'; export const post: RequestHandler = async (event) => { const { teamId, status, body } = await getUserDetails(event); @@ -22,6 +23,7 @@ export const post: RequestHandler = async (event) => { destinationDockerId, serviceSecret, destinationDocker, + exposePort, wordpress: { mysqlDatabase, mysqlUser, @@ -35,6 +37,7 @@ export const post: RequestHandler = async (event) => { const network = destinationDockerId && destinationDocker.network; const host = getEngine(destinationDocker.engine); const image = getServiceImage(type); + const port = getServiceMainPort('wordpress'); const { workdir } = await createDirectories({ repository: type, buildId: id }); const config = { @@ -76,6 +79,7 @@ export const post: RequestHandler = async (event) => { volumes: [config.wordpress.volume], networks: [network], restart: 'always', + ...(exposePort ? { ports: [`${port}:${port}`] } : {}), depends_on: [`${id}-mysql`], labels: makeLabelForServices('wordpress'), deploy: {