From 1bd33fea9824b065024e6937701da0cf7b526f48 Mon Sep 17 00:00:00 2001 From: Aaron Styles Date: Fri, 8 Apr 2022 17:12:01 +1000 Subject: [PATCH 001/118] 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 003/118] 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: { From 3543a9c809e86c0b32268f5d30f6fbe11bf064ab Mon Sep 17 00:00:00 2001 From: Cyril Beeckman Date: Mon, 2 May 2022 16:25:24 +0200 Subject: [PATCH 004/118] Added MariaDB database --- src/lib/components/DatabaseLinks.svelte | 3 + src/lib/components/common.ts | 6 + .../components/svg/databases/MariaDB.svelte | 10 ++ src/lib/database/common.ts | 127 +++++++++++------- src/lib/database/databases.ts | 4 + .../[id]/_Databases/_Databases.svelte | 3 + .../databases/[id]/_Databases/_MariaDB.svelte | 79 +++++++++++ .../databases/[id]/configuration/type.svelte | 3 + src/routes/databases/index.svelte | 5 + 9 files changed, 190 insertions(+), 50 deletions(-) create mode 100644 src/lib/components/svg/databases/MariaDB.svelte create mode 100644 src/routes/databases/[id]/_Databases/_MariaDB.svelte diff --git a/src/lib/components/DatabaseLinks.svelte b/src/lib/components/DatabaseLinks.svelte index 9ef11a238..5927c405c 100644 --- a/src/lib/components/DatabaseLinks.svelte +++ b/src/lib/components/DatabaseLinks.svelte @@ -3,6 +3,7 @@ import Clickhouse from './svg/databases/Clickhouse.svelte'; import CouchDb from './svg/databases/CouchDB.svelte'; import MongoDb from './svg/databases/MongoDB.svelte'; + import MariaDb from './svg/databases/MariaDB.svelte'; import MySql from './svg/databases/MySQL.svelte'; import PostgreSql from './svg/databases/PostgreSQL.svelte'; import Redis from './svg/databases/Redis.svelte'; @@ -17,6 +18,8 @@ {:else if database.type === 'mysql'} + {:else if database.type === 'mariadb'} + {:else if database.type === 'postgresql'} {:else if database.type === 'redis'} diff --git a/src/lib/components/common.ts b/src/lib/components/common.ts index d6ff2f8ea..b854fe623 100644 --- a/src/lib/components/common.ts +++ b/src/lib/components/common.ts @@ -52,6 +52,12 @@ export const supportedDatabaseTypesAndVersions = [ versions: ['5.0', '4.4', '4.2'] }, { name: 'mysql', fancyName: 'MySQL', baseImage: 'bitnami/mysql', versions: ['8.0', '5.7'] }, + { + name: 'mariadb', + fancyName: 'MariaDB', + baseImage: 'bitnami/mariadb', + versions: ['10.7', '10.6', '10.5', '10.4', '10.3', '10.2'] + }, { name: 'postgresql', fancyName: 'PostgreSQL', diff --git a/src/lib/components/svg/databases/MariaDB.svelte b/src/lib/components/svg/databases/MariaDB.svelte new file mode 100644 index 000000000..cb83268f1 --- /dev/null +++ b/src/lib/components/svg/databases/MariaDB.svelte @@ -0,0 +1,10 @@ + + + + + diff --git a/src/lib/database/common.ts b/src/lib/database/common.ts index 314f77b08..e83308878 100644 --- a/src/lib/database/common.ts +++ b/src/lib/database/common.ts @@ -127,60 +127,73 @@ export function getServiceImages(type: string): string[] { export function generateDatabaseConfiguration(database: Database & { settings: DatabaseSettings }): | { - volume: string; - image: string; - ulimits: Record; - privatePort: number; - environmentVariables: { - MYSQL_DATABASE: string; - MYSQL_PASSWORD: string; - MYSQL_ROOT_USER: string; - MYSQL_USER: string; - MYSQL_ROOT_PASSWORD: string; - }; - } + volume: string; + image: string; + ulimits: Record; + privatePort: number; + environmentVariables: { + MYSQL_DATABASE: string; + MYSQL_PASSWORD: string; + MYSQL_ROOT_USER: string; + MYSQL_USER: string; + MYSQL_ROOT_PASSWORD: string; + }; + } | { - volume: string; - image: string; - ulimits: Record; - privatePort: number; - environmentVariables: { - MONGODB_ROOT_USER: string; - MONGODB_ROOT_PASSWORD: string; - }; - } + volume: string; + image: string; + ulimits: Record; + privatePort: number; + environmentVariables: { + MONGODB_ROOT_USER: string; + MONGODB_ROOT_PASSWORD: string; + }; + } | { - volume: string; - image: string; - ulimits: Record; - privatePort: number; - environmentVariables: { - POSTGRESQL_POSTGRES_PASSWORD: string; - POSTGRESQL_USERNAME: string; - POSTGRESQL_PASSWORD: string; - POSTGRESQL_DATABASE: string; - }; - } + volume: string; + image: string; + ulimits: Record; + privatePort: number; + environmentVariables: { + MARIADB_ROOT_USER: string; + MARIADB_ROOT_PASSWORD: string; + MARIADB_USER: string; + MARIADB_PASSWORD: string; + MARIADB_DATABASE: string; + }; + } | { - volume: string; - image: string; - ulimits: Record; - privatePort: number; - environmentVariables: { - REDIS_AOF_ENABLED: string; - REDIS_PASSWORD: string; - }; - } + volume: string; + image: string; + ulimits: Record; + privatePort: number; + environmentVariables: { + POSTGRESQL_POSTGRES_PASSWORD: string; + POSTGRESQL_USERNAME: string; + POSTGRESQL_PASSWORD: string; + POSTGRESQL_DATABASE: string; + }; + } | { - volume: string; - image: string; - ulimits: Record; - privatePort: number; - environmentVariables: { - COUCHDB_PASSWORD: string; - COUCHDB_USER: string; - }; - } { + volume: string; + image: string; + ulimits: Record; + privatePort: number; + environmentVariables: { + REDIS_AOF_ENABLED: string; + REDIS_PASSWORD: string; + }; + } + | { + volume: string; + image: string; + ulimits: Record; + privatePort: number; + environmentVariables: { + COUCHDB_PASSWORD: string; + COUCHDB_USER: string; + }; + } { const { id, dbUser, @@ -207,6 +220,20 @@ export function generateDatabaseConfiguration(database: Database & { settings: D volume: `${id}-${type}-data:/bitnami/mysql/data`, ulimits: {} }; + } else if (type === 'mariadb') { + return { + privatePort: 3306, + environmentVariables: { + MARIADB_ROOT_USER: rootUser, + MARIADB_ROOT_PASSWORD: rootUserPassword, + MARIADB_USER: dbUser, + MARIADB_PASSWORD: dbUserPassword, + MARIADB_DATABASE: defaultDatabase + }, + image: `${baseImage}:${version}`, + volume: `${id}-${type}-data:/bitnami/mariadb`, + ulimits: {} + }; } else if (type === 'mongodb') { return { privatePort: 27017, diff --git a/src/lib/database/databases.ts b/src/lib/database/databases.ts index 388047ac3..edc15c729 100644 --- a/src/lib/database/databases.ts +++ b/src/lib/database/databases.ts @@ -184,6 +184,10 @@ export async function updatePasswordInDb(database, user, newPassword, isRoot) { await asyncExecShell( `DOCKER_HOST=${host} docker exec ${id} mysql -u ${rootUser} -p${rootUserPassword} -e \"ALTER USER '${user}'@'%' IDENTIFIED WITH caching_sha2_password BY '${newPassword}';\"` ); + } else if (type === 'mariadb') { + await asyncExecShell( + `DOCKER_HOST=${host} docker exec ${id} mysql -u ${rootUser} -p${rootUserPassword} -e \"SET PASSWORD FOR '${user}'@'%' = PASSWORD('${newPassword}');\"` + ); } else if (type === 'postgresql') { if (isRoot) { await asyncExecShell( diff --git a/src/routes/databases/[id]/_Databases/_Databases.svelte b/src/routes/databases/[id]/_Databases/_Databases.svelte index 1034a3543..b40cfb345 100644 --- a/src/routes/databases/[id]/_Databases/_Databases.svelte +++ b/src/routes/databases/[id]/_Databases/_Databases.svelte @@ -11,6 +11,7 @@ import MySql from './_MySQL.svelte'; import MongoDb from './_MongoDB.svelte'; + import MariaDb from './_MariaDB.svelte'; import PostgreSql from './_PostgreSQL.svelte'; import Redis from './_Redis.svelte'; import CouchDb from './_CouchDb.svelte'; @@ -190,6 +191,8 @@ {:else if database.type === 'mongodb'} + {:else if database.type === 'mariadb'} + {:else if database.type === 'redis'} {:else if database.type === 'couchdb'} diff --git a/src/routes/databases/[id]/_Databases/_MariaDB.svelte b/src/routes/databases/[id]/_Databases/_MariaDB.svelte new file mode 100644 index 000000000..3bb135421 --- /dev/null +++ b/src/routes/databases/[id]/_Databases/_MariaDB.svelte @@ -0,0 +1,79 @@ + + +
+
MariaDB
+
+
+
+ + +
+
+ + +
+
+ + + +
+
+ + +
+
+ + + +
+
diff --git a/src/routes/databases/[id]/configuration/type.svelte b/src/routes/databases/[id]/configuration/type.svelte index a73163058..fadba1365 100644 --- a/src/routes/databases/[id]/configuration/type.svelte +++ b/src/routes/databases/[id]/configuration/type.svelte @@ -37,6 +37,7 @@ import Clickhouse from '$lib/components/svg/databases/Clickhouse.svelte'; import CouchDB from '$lib/components/svg/databases/CouchDB.svelte'; import MongoDB from '$lib/components/svg/databases/MongoDB.svelte'; + import MariaDB from '$lib/components/svg/databases/MariaDB.svelte'; import MySQL from '$lib/components/svg/databases/MySQL.svelte'; import PostgreSQL from '$lib/components/svg/databases/PostgreSQL.svelte'; import Redis from '$lib/components/svg/databases/Redis.svelte'; @@ -68,6 +69,8 @@ {:else if type.name === 'mongodb'} + {:else if type.name === 'mariadb'} + {:else if type.name === 'mysql'} {:else if type.name === 'postgresql'} diff --git a/src/routes/databases/index.svelte b/src/routes/databases/index.svelte index 6717ac88a..ec6b86291 100644 --- a/src/routes/databases/index.svelte +++ b/src/routes/databases/index.svelte @@ -3,6 +3,7 @@ import Clickhouse from '$lib/components/svg/databases/Clickhouse.svelte'; import CouchDB from '$lib/components/svg/databases/CouchDB.svelte'; import MongoDB from '$lib/components/svg/databases/MongoDB.svelte'; + import MariaDB from '$lib/components/svg/databases/MariaDB.svelte'; import MySQL from '$lib/components/svg/databases/MySQL.svelte'; import PostgreSQL from '$lib/components/svg/databases/PostgreSQL.svelte'; import Redis from '$lib/components/svg/databases/Redis.svelte'; @@ -66,6 +67,8 @@ {:else if database.type === 'mysql'} + {:else if database.type === 'mariadb'} + {:else if database.type === 'postgresql'} {:else if database.type === 'redis'} @@ -98,6 +101,8 @@ {:else if database.type === 'mongodb'} + {:else if database.type === 'mariadb'} + {:else if database.type === 'mysql'} {:else if database.type === 'postgresql'} From 887d65e5129681154bc5635e6f3ade590c8abe31 Mon Sep 17 00:00:00 2001 From: Cyril Beeckman Date: Mon, 2 May 2022 17:06:25 +0200 Subject: [PATCH 005/118] Change MariaDB logo --- .../components/svg/databases/MariaDB.svelte | 68 +++++++++++++++++-- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/src/lib/components/svg/databases/MariaDB.svelte b/src/lib/components/svg/databases/MariaDB.svelte index cb83268f1..86e7871d1 100644 --- a/src/lib/components/svg/databases/MariaDB.svelte +++ b/src/lib/components/svg/databases/MariaDB.svelte @@ -2,9 +2,67 @@ export let isAbsolute = false; - - + + + + + + + + + + + + + + + + + + From b84c37cd8f0f5ce424a3fcdc8f56b5740a8698f3 Mon Sep 17 00:00:00 2001 From: Cyril Beeckman Date: Mon, 2 May 2022 20:27:39 +0200 Subject: [PATCH 006/118] Update README and remove duplicate for NextJS --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f342fd74a..7e1019685 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,6 @@ These are the predefined build packs, but with the Docker build pack, you can ho - NuxtJS - NextJS - React/Preact -- NextJS - Gatsby - Svelte - PHP @@ -64,6 +63,7 @@ These are the predefined build packs, but with the Docker build pack, you can ho One-click database is ready to be used internally or shared over the internet: - MongoDB +- MariaDB - MySQL - PostgreSQL - CouchDB From 0a7ec6bd202b5eaa3f66d9b62e4cab92f15961b8 Mon Sep 17 00:00:00 2001 From: Arpit Vasani Date: Tue, 3 May 2022 11:29:10 +0530 Subject: [PATCH 007/118] Create config.yml --- .github/ISSUE_TEMPLATE/config.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..49618c8e7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: 🤔 Questions and Help + url: https://discord.com/invite/6rDM4fkymF + about: Reach out to us on discord or our github discussions page. From 62d1011d9f8b271a66050483ed47ca620349e083 Mon Sep 17 00:00:00 2001 From: Arpit Vasani Date: Tue, 3 May 2022 11:33:19 +0530 Subject: [PATCH 008/118] Create --bug-report.yaml --- .github/ISSUE_TEMPLATE/--bug-report.yaml | 47 ++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/--bug-report.yaml diff --git a/.github/ISSUE_TEMPLATE/--bug-report.yaml b/.github/ISSUE_TEMPLATE/--bug-report.yaml new file mode 100644 index 000000000..8452b1647 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/--bug-report.yaml @@ -0,0 +1,47 @@ +name: 🐞 Bug report +description: Create a bug report to help us improve Appsmith +title: "[Bug]: " +labels: [Bug] +assignees: +- andrasbacsai +- vasani-arpit +body: +- type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! Please fill the form in English +- type: checkboxes + attributes: + label: Is there an existing issue for this? + options: + - label: I have searched the existing issues + required: true +- type: textarea + attributes: + label: Description + description: A concise description of what you're experiencing and what you expect. + placeholder: | + When I do , happens and I see the error message attached below: + ```...``` + What I expect is + validations: + required: true +- type: textarea + attributes: + label: Steps To Reproduce + description: Add steps to reproduce this behaviour, include console / network logs & videos + placeholder: | + 1. Go to '...' + 2. Click on '....' + 3. Scroll down to '....' + 4. See error + validations: + required: true +- type: input + id: version + attributes: + label: Version + description: "The version of your coolify Instance" + placeholder: "2.5.2" + validations: + required: true From ec5474b72b665f0a4274fd8cb24768461254b072 Mon Sep 17 00:00:00 2001 From: Arpit Vasani Date: Tue, 3 May 2022 11:36:13 +0530 Subject: [PATCH 009/118] Create --feature-request.yaml --- .github/ISSUE_TEMPLATE/--feature-request.yaml | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/--feature-request.yaml diff --git a/.github/ISSUE_TEMPLATE/--feature-request.yaml b/.github/ISSUE_TEMPLATE/--feature-request.yaml new file mode 100644 index 000000000..b6ba5125f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/--feature-request.yaml @@ -0,0 +1,31 @@ +name: 🛠️ Feature request +description: Suggest an idea to improve coolify +title: "[Feature]: " +labels: [Enhancement] +assignees: +- andrasbacsai +- vasani-arpit +body: +- type: markdown + attributes: + value: | + Thanks for taking the time to request a feature for coolify! +- type: checkboxes + attributes: + label: Is there an existing issue for this? + description: Please search to see if an issue related to this feature request already exists. + options: + - label: I have searched the existing issues + required: true +- type: textarea + attributes: + label: Summary + description: One paragraph description of the feature. + validations: + required: true +- type: textarea + attributes: + label: Why should this be worked on? + description: A concise description of the problems or use cases for this feature request. + validations: + required: true From 95826644069e0deffca4b9491642b396acea36ed Mon Sep 17 00:00:00 2001 From: Arpit Vasani Date: Tue, 3 May 2022 11:37:32 +0530 Subject: [PATCH 010/118] Create --task.yaml --- .github/ISSUE_TEMPLATE/--task.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/--task.yaml diff --git a/.github/ISSUE_TEMPLATE/--task.yaml b/.github/ISSUE_TEMPLATE/--task.yaml new file mode 100644 index 000000000..a1ff080c5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/--task.yaml @@ -0,0 +1,20 @@ +name: 📝 Task +description: Create a task for the team to work on +title: "[Task]: " +labels: [Task] +body: +- type: checkboxes + attributes: + label: Is there an existing issue for this? + description: Please search to see if an issue related to this already exists. + options: + - label: I have searched the existing issues + required: true +- type: textarea + attributes: + label: SubTasks + placeholder: | + - Sub Task 1 + - Sub Task 2 + validations: + required: false From 828faaf2b14a446da0ce640088eafbc3b27e4d5e Mon Sep 17 00:00:00 2001 From: Arpit Vasani Date: Tue, 3 May 2022 11:38:49 +0530 Subject: [PATCH 011/118] Update --bug-report.yaml --- .github/ISSUE_TEMPLATE/--bug-report.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/--bug-report.yaml b/.github/ISSUE_TEMPLATE/--bug-report.yaml index 8452b1647..53853d157 100644 --- a/.github/ISSUE_TEMPLATE/--bug-report.yaml +++ b/.github/ISSUE_TEMPLATE/--bug-report.yaml @@ -1,5 +1,5 @@ name: 🐞 Bug report -description: Create a bug report to help us improve Appsmith +description: Create a bug report to help us improve coolify title: "[Bug]: " labels: [Bug] assignees: From 8b813fb07a96ef1dc2964b8b87382db3b750885a Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 3 May 2022 11:40:02 +0200 Subject: [PATCH 012/118] fix: Renew certificates --- src/lib/letsencrypt/index.ts | 25 +++++++++++++++++++++++++ src/lib/queues/index.ts | 2 +- src/lib/queues/sslrenewal.ts | 13 +++++++------ src/routes/settings/index.svelte | 21 +++++++++++++++++++++ src/routes/settings/renew.json.ts | 26 ++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 src/routes/settings/renew.json.ts diff --git a/src/lib/letsencrypt/index.ts b/src/lib/letsencrypt/index.ts index f443625ae..7b64b8a9e 100644 --- a/src/lib/letsencrypt/index.ts +++ b/src/lib/letsencrypt/index.ts @@ -290,3 +290,28 @@ export async function generateSSLCerts(): Promise { } } } + +export async function renewSSLCerts(): Promise { + const host = 'unix:///var/run/docker.sock'; + await asyncExecShell(`docker pull alpine:latest`); + const certbotImage = + process.arch === 'x64' ? 'certbot/certbot' : 'certbot/certbot:arm64v8-latest'; + + const { stdout: certificates } = await asyncExecShell( + `DOCKER_HOST=${host} docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest sh -c "ls -1 /etc/letsencrypt/live/ | grep -v README"` + ); + + for (const certificate of certificates.trim().split('\n')) { + try { + await asyncExecShell( + `DOCKER_HOST=${host} docker run --rm --name certbot-renewal -p 9080:9080 -v "coolify-letsencrypt:/etc/letsencrypt" ${certbotImage} --cert-name ${certificate} --logs-dir /etc/letsencrypt/logs renew --standalone --preferred-challenges http --http-01-address 0.0.0.0 --http-01-port 9080` + ); + await asyncExecShell( + `DOCKER_HOST=${host} docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest sh -c "test -d /etc/letsencrypt/live/${certificate}/ && cat /etc/letsencrypt/live/${certificate}/fullchain.pem /etc/letsencrypt/live/${certificate}/privkey.pem > /app/ssl/${certificate}.pem"` + ); + } catch (error) { + console.log(error); + } + } + await reloadHaproxy('unix:///var/run/docker.sock'); +} diff --git a/src/lib/queues/index.ts b/src/lib/queues/index.ts index 60097680d..cc340b883 100644 --- a/src/lib/queues/index.ts +++ b/src/lib/queues/index.ts @@ -116,7 +116,7 @@ const cron = async (): Promise => { await queue.proxyTcpHttp.add('proxyTcpHttp', {}, { repeat: { every: 10000 } }); await queue.ssl.add('ssl', {}, { repeat: { every: dev ? 10000 : 60000 } }); if (!dev) await queue.cleanup.add('cleanup', {}, { repeat: { every: 300000 } }); - await queue.sslRenew.add('sslRenew', {}, { repeat: { every: 1800000 } }); + if (!dev) await queue.sslRenew.add('sslRenew', {}, { repeat: { every: 1800000 } }); await queue.autoUpdater.add('autoUpdater', {}, { repeat: { every: 60000 } }); }; cron().catch((error) => { diff --git a/src/lib/queues/sslrenewal.ts b/src/lib/queues/sslrenewal.ts index 4af5bae64..766b9c502 100644 --- a/src/lib/queues/sslrenewal.ts +++ b/src/lib/queues/sslrenewal.ts @@ -1,9 +1,10 @@ -import { asyncExecShell } from '$lib/common'; -import { reloadHaproxy } from '$lib/haproxy'; +import { renewSSLCerts } from '$lib/letsencrypt'; export default async function (): Promise { - await asyncExecShell( - `docker run --rm --name certbot-renewal -v "coolify-letsencrypt:/etc/letsencrypt" certbot/certbot --logs-dir /etc/letsencrypt/logs renew` - ); - await reloadHaproxy('unix:///var/run/docker.sock'); + try { + return await renewSSLCerts(); + } catch (error) { + console.log(error); + throw error; + } } diff --git a/src/routes/settings/index.svelte b/src/routes/settings/index.svelte index 6a9b6ba5a..20e1c788d 100644 --- a/src/routes/settings/index.svelte +++ b/src/routes/settings/index.svelte @@ -111,6 +111,14 @@ loading.save = false; } } + async function renewCerts() { + try { + toast.push('Renewing certificates...'); + return await post(`/settings/renew.json`, {}); + } catch ({ error }) { + return errorNotification(error); + } + }
@@ -219,6 +227,19 @@ on:click={() => changeSettings('isAutoUpdateEnabled')} />
+
+
+
+ Renew SSL Certificates manually +
+ +
+
+ +
+
{/if} diff --git a/src/routes/settings/renew.json.ts b/src/routes/settings/renew.json.ts new file mode 100644 index 000000000..3cbb8f4ad --- /dev/null +++ b/src/routes/settings/renew.json.ts @@ -0,0 +1,26 @@ +import { getUserDetails } from '$lib/common'; +import { ErrorHandler } from '$lib/database'; +import { renewSSLCerts } from '$lib/letsencrypt'; +import { t } from '$lib/translations'; +import type { RequestHandler } from '@sveltejs/kit'; + +export const post: RequestHandler = async (event) => { + const { teamId, status, body } = await getUserDetails(event); + if (teamId !== '0') + return { + status: 401, + body: { + message: t.get('setting.permission_denied') + } + }; + if (status === 401) return { status, body }; + + try { + renewSSLCerts(); + return { + status: 201 + }; + } catch (error) { + return ErrorHandler(error); + } +}; From fd363ec01777b2a7fc0f089eaedbeb8c42158c91 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 3 May 2022 11:40:09 +0200 Subject: [PATCH 013/118] update readme.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index f342fd74a..d73fc94df 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ These are the predefined build packs, but with the Docker build pack, you can ho - Gatsby - Svelte - PHP +- Laravel - Rust - Docker @@ -85,6 +86,8 @@ You can host cool open-source services as well: - [Uptime Kuma](https://github.com/louislam/uptime-kuma) - [MeiliSearch](https://github.com/meilisearch/meilisearch) - [Umami](https://github.com/mikecao/umami) +- [Fider](https://fider.io) +- [Hasura](https://hasura.io) ## Migration from v1 From 4b38865cc9cfe3707719cab97c5dabda8c436692 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 3 May 2022 12:07:37 +0200 Subject: [PATCH 014/118] fix: Webhook build images --- package.json | 2 +- src/lib/database/applications.ts | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 7c28949bd..ccc938119 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "coolify", "description": "An open-source & self-hostable Heroku / Netlify alternative.", - "version": "2.6.1", + "version": "2.6.2", "license": "AGPL-3.0", "scripts": { "dev": "docker-compose -f docker-compose-dev.yaml up -d && cross-env NODE_ENV=development & svelte-kit dev --host 0.0.0.0", diff --git a/src/lib/database/applications.ts b/src/lib/database/applications.ts index d64537b69..caceef396 100644 --- a/src/lib/database/applications.ts +++ b/src/lib/database/applications.ts @@ -138,7 +138,18 @@ export async function getApplicationWebhook({ return s; }); } - return { ...application }; + const { baseImage, baseBuildImage, baseBuildImages, baseImages } = setDefaultBaseImage( + application.buildPack + ); + + // Set default build images + if (!application.baseImage) { + application.baseImage = baseImage; + } + if (!application.baseBuildImage) { + application.baseBuildImage = baseBuildImage; + } + return { ...application, baseBuildImages, baseImages }; } catch (e) { throw { status: 404, body: { message: e.message } }; } From 68f5b32876f0fb85399e3b71ccd7023b46110259 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 3 May 2022 22:49:52 +0200 Subject: [PATCH 015/118] fix: missing node versions --- package.json | 2 +- src/lib/buildPacks/common.ts | 6 ++++-- src/lib/locales/en.json | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index ccc938119..ece20c8eb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "coolify", "description": "An open-source & self-hostable Heroku / Netlify alternative.", - "version": "2.6.2", + "version": "2.6.3", "license": "AGPL-3.0", "scripts": { "dev": "docker-compose -f docker-compose-dev.yaml up -d && cross-env NODE_ENV=development & svelte-kit dev --host 0.0.0.0", diff --git a/src/lib/buildPacks/common.ts b/src/lib/buildPacks/common.ts index 6ac518136..cb47b0dd5 100644 --- a/src/lib/buildPacks/common.ts +++ b/src/lib/buildPacks/common.ts @@ -8,14 +8,16 @@ import { staticDeployments } from '$lib/components/common'; const staticApps = ['static', 'react', 'vuejs', 'svelte', 'gatsby', 'astro', 'eleventy']; const nodeBased = [ 'react', + 'preact', 'vuejs', 'svelte', 'gatsby', - 'php', 'astro', 'eleventy', 'node', - 'nestjs' + 'nestjs', + 'nuxtjs', + 'nextjs' ]; export function makeLabelForStandaloneApplication({ diff --git a/src/lib/locales/en.json b/src/lib/locales/en.json index a7adfcef0..0a535db35 100644 --- a/src/lib/locales/en.json +++ b/src/lib/locales/en.json @@ -184,7 +184,7 @@ "git_source": "Git Source", "git_repository": "Git Repository", "build_pack": "Build Pack", - "base_image": "Deplyoment Image", + "base_image": "Deployment Image", "base_image_explainer": "Image that will be used for the deployment.", "base_build_image": "Build Image", "base_build_image_explainer": "Image that will be used during the build process.", From 5f3567e80899e609229ab996a12a24ddefac37c0 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 13:02:16 +0200 Subject: [PATCH 016/118] Create github-actions-demo.yml --- .github/workflows/github-actions-demo.yml | 34 +++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/github-actions-demo.yml diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml new file mode 100644 index 000000000..d3abe7d12 --- /dev/null +++ b/.github/workflows/github-actions-demo.yml @@ -0,0 +1,34 @@ +name: push-new-image + +on: + push: + branches: + - 'main' + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: coollabsio/coolify-test:latest From 4097378847974d39b0a1444c94190de453e4006b Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 13:05:01 +0200 Subject: [PATCH 017/118] Update github-actions-demo.yml --- .github/workflows/github-actions-demo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml index d3abe7d12..75e996153 100644 --- a/.github/workflows/github-actions-demo.yml +++ b/.github/workflows/github-actions-demo.yml @@ -3,7 +3,7 @@ name: push-new-image on: push: branches: - - 'main' + - 'gh-actions' jobs: docker: From 902a764ff2d5547d74b832e38911b5f7ef63ae8d Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 13:06:15 +0200 Subject: [PATCH 018/118] Update github-actions-demo.yml --- .github/workflows/github-actions-demo.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml index 75e996153..dded1acd3 100644 --- a/.github/workflows/github-actions-demo.yml +++ b/.github/workflows/github-actions-demo.yml @@ -1,4 +1,4 @@ -name: push-new-image +name: ci on: push: @@ -12,19 +12,19 @@ jobs: - name: Checkout uses: actions/checkout@v2 - - + - name: Set up QEMU uses: docker/setup-qemu-action@v1 - - + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - + - name: Login to DockerHub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - + - name: Build and push uses: docker/build-push-action@v2 with: From 435f063c365313202118075fdad79344183982a8 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 13:20:46 +0200 Subject: [PATCH 019/118] Update and rename github-actions-demo.yml to github-actions.yml --- .../workflows/{github-actions-demo.yml => github-actions.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{github-actions-demo.yml => github-actions.yml} (98%) diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions.yml similarity index 98% rename from .github/workflows/github-actions-demo.yml rename to .github/workflows/github-actions.yml index dded1acd3..f074ef559 100644 --- a/.github/workflows/github-actions-demo.yml +++ b/.github/workflows/github-actions.yml @@ -6,7 +6,7 @@ on: - 'gh-actions' jobs: - docker: + build: runs-on: ubuntu-latest steps: - From 86b7824c78ab0672a85726559178c2250d8b4fed Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 13:22:54 +0200 Subject: [PATCH 020/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index f074ef559..3608633fd 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -24,6 +24,20 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Cache pnpm modules + uses: actions/cache@v2 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}- + + - + uses: pnpm/action-setup@v2.1.0 + with: + version: 7.0.0 + run_install: false - name: Build and push uses: docker/build-push-action@v2 From a4301c5d23ff298caac4e4ee05cae857be874377 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 13:32:35 +0200 Subject: [PATCH 021/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index 3608633fd..ae6680669 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -1,4 +1,4 @@ -name: ci +name: release-coolify on: push: @@ -12,7 +12,7 @@ jobs: - name: Checkout uses: actions/checkout@v2 - - + - name: Set up QEMU uses: docker/setup-qemu-action@v1 - @@ -24,20 +24,6 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Cache pnpm modules - uses: actions/cache@v2 - with: - path: ~/.pnpm-store - key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}- - - - - uses: pnpm/action-setup@v2.1.0 - with: - version: 7.0.0 - run_install: false - name: Build and push uses: docker/build-push-action@v2 @@ -46,3 +32,5 @@ jobs: platforms: linux/amd64,linux/arm64 push: true tags: coollabsio/coolify-test:latest + cache-from: type=registry,ref=coollabsio/coolify-test:buildcache + cache-to: type=registry,ref=coollabsio/coolify-test:buildcache,mode=max From 4f662dbf215a7c025e6ccf5c902bdd58f86420f8 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 13:36:46 +0200 Subject: [PATCH 022/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index ae6680669..e7a334b3d 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -29,7 +29,7 @@ jobs: uses: docker/build-push-action@v2 with: context: . - platforms: linux/amd64,linux/arm64 + platforms: linux/amd64 push: true tags: coollabsio/coolify-test:latest cache-from: type=registry,ref=coollabsio/coolify-test:buildcache From c07d6aa702f306c2df4bba637c906b1b566e0dd2 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 13:44:48 +0200 Subject: [PATCH 023/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index e7a334b3d..b8e1b010f 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -6,7 +6,7 @@ on: - 'gh-actions' jobs: - build: + make-it-coolifyed: runs-on: ubuntu-latest steps: - From 1211f3c9fdc23e511d0823b150817e1ea8889813 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 13:59:59 +0200 Subject: [PATCH 024/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index b8e1b010f..4c59cf715 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -24,6 +24,10 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Read package.json version + uses: dutscher/read-package-json-endpoint-actions@v1.3.37 + id: packagejson - name: Build and push uses: docker/build-push-action@v2 @@ -31,6 +35,6 @@ jobs: context: . platforms: linux/amd64 push: true - tags: coollabsio/coolify-test:latest + tags: coollabsio/coolify-test:latest,coollabsio/coolify-test:${{ steps.packagejson.version }} cache-from: type=registry,ref=coollabsio/coolify-test:buildcache cache-to: type=registry,ref=coollabsio/coolify-test:buildcache,mode=max From 9d53bc09260e65196600a90c8e3bee5b4ab181ed Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 14:03:00 +0200 Subject: [PATCH 025/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index 4c59cf715..263072877 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -35,6 +35,6 @@ jobs: context: . platforms: linux/amd64 push: true - tags: coollabsio/coolify-test:latest,coollabsio/coolify-test:${{ steps.packagejson.version }} + tags: coollabsio/coolify-test:latest,coollabsio/coolify-test:${{ steps.packagejson.outputs.version }} cache-from: type=registry,ref=coollabsio/coolify-test:buildcache cache-to: type=registry,ref=coollabsio/coolify-test:buildcache,mode=max From 259aeeb67a84d60a89ab11d2a3150904b54514ee Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 14:06:06 +0200 Subject: [PATCH 026/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index 263072877..6ff5cdb81 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -25,9 +25,8 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Read package.json version - uses: dutscher/read-package-json-endpoint-actions@v1.3.37 - id: packagejson + name: Get current package version + uses: martinbeentjes/npm-get-version-action@v1.2.3 - name: Build and push uses: docker/build-push-action@v2 @@ -35,6 +34,6 @@ jobs: context: . platforms: linux/amd64 push: true - tags: coollabsio/coolify-test:latest,coollabsio/coolify-test:${{ steps.packagejson.outputs.version }} + tags: coollabsio/coolify-test:latest,coollabsio/coolify-test:${{ steps.package-version.outputs.current-version }} cache-from: type=registry,ref=coollabsio/coolify-test:buildcache cache-to: type=registry,ref=coollabsio/coolify-test:buildcache,mode=max From 3937cfec534a4e04867b0ec9925056d4915bbe43 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 14:08:24 +0200 Subject: [PATCH 027/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index 6ff5cdb81..147b9cd5c 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -27,6 +27,7 @@ jobs: - name: Get current package version uses: martinbeentjes/npm-get-version-action@v1.2.3 + id: package-version - name: Build and push uses: docker/build-push-action@v2 @@ -34,6 +35,6 @@ jobs: context: . platforms: linux/amd64 push: true - tags: coollabsio/coolify-test:latest,coollabsio/coolify-test:${{ steps.package-version.outputs.current-version }} + tags: coollabsio/coolify-test:latest,coollabsio/coolify-test:${{steps.package-version.outputs.current-version}} cache-from: type=registry,ref=coollabsio/coolify-test:buildcache cache-to: type=registry,ref=coollabsio/coolify-test:buildcache,mode=max From 2cce1f84592db6dfc43b6d932e456df4be1f6929 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 14:11:46 +0200 Subject: [PATCH 028/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index 147b9cd5c..656b5667e 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -33,7 +33,7 @@ jobs: uses: docker/build-push-action@v2 with: context: . - platforms: linux/amd64 + platforms: linux/amd64,linux/arm64 push: true tags: coollabsio/coolify-test:latest,coollabsio/coolify-test:${{steps.package-version.outputs.current-version}} cache-from: type=registry,ref=coollabsio/coolify-test:buildcache From 4246d86694df981706211786091679b8f4f6dcfa Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 14:30:35 +0200 Subject: [PATCH 029/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index 656b5667e..aa575bf04 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -1,9 +1,8 @@ name: release-coolify on: - push: - branches: - - 'gh-actions' + release: + types: published jobs: make-it-coolifyed: From 1ec03693d39265695eafbf80aca60f08561ae06d Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 14:31:03 +0200 Subject: [PATCH 030/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index aa575bf04..ac49d22c3 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -34,6 +34,6 @@ jobs: context: . platforms: linux/amd64,linux/arm64 push: true - tags: coollabsio/coolify-test:latest,coollabsio/coolify-test:${{steps.package-version.outputs.current-version}} + tags: coollabsio/coolify:latest,coollabsio/coolify:${{steps.package-version.outputs.current-version}} cache-from: type=registry,ref=coollabsio/coolify-test:buildcache cache-to: type=registry,ref=coollabsio/coolify-test:buildcache,mode=max From 02a1f50776a5a7f8da7b4710e562de6269a33f25 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 14:40:00 +0200 Subject: [PATCH 031/118] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index d73fc94df..5660915df 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ https://demo.coolify.io/ (If it is unresponsive, that means someone overloaded the server. 🙃) +## Feedback +If you have a new service / build pack you would like to add, raise an idea [here](https://feedback.coolify.io/) to get feedback from the community! + ## How to install Installation is automated with the following command: From 2e8fd6f0c7dfebe69f318250d91b3d9ffa2909ac Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 4 May 2022 15:45:44 +0200 Subject: [PATCH 032/118] fix: exposedPorts --- src/lib/buildPacks/gatsby.ts | 4 +-- src/lib/buildPacks/laravel.ts | 4 +-- src/lib/buildPacks/php.ts | 4 +-- src/lib/buildPacks/react.ts | 4 +-- src/lib/buildPacks/static.ts | 5 +-- src/lib/buildPacks/svelte.ts | 4 +-- src/lib/buildPacks/vuejs.ts | 4 +-- src/routes/applications/[id]/check.json.ts | 5 ++- src/routes/applications/[id]/index.svelte | 39 ++++++++-------------- 9 files changed, 32 insertions(+), 41 deletions(-) diff --git a/src/lib/buildPacks/gatsby.ts b/src/lib/buildPacks/gatsby.ts index cdf95f1dd..a10f84c43 100644 --- a/src/lib/buildPacks/gatsby.ts +++ b/src/lib/buildPacks/gatsby.ts @@ -2,7 +2,7 @@ import { buildCacheImageWithNode, buildImage } from '$lib/docker'; import { promises as fs } from 'fs'; const createDockerfile = async (data, imageforBuild): Promise => { - const { applicationId, tag, workdir, publishDirectory, baseImage, buildId } = data; + const { applicationId, tag, workdir, publishDirectory, baseImage, buildId, port } = data; const Dockerfile: Array = []; Dockerfile.push(`FROM ${imageforBuild}`); @@ -12,7 +12,7 @@ const createDockerfile = async (data, imageforBuild): Promise => { if (baseImage.includes('nginx')) { Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`); } - Dockerfile.push(`EXPOSE 80`); + Dockerfile.push(`EXPOSE ${port}`); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); }; diff --git a/src/lib/buildPacks/laravel.ts b/src/lib/buildPacks/laravel.ts index a83363dc0..4912a772f 100644 --- a/src/lib/buildPacks/laravel.ts +++ b/src/lib/buildPacks/laravel.ts @@ -2,7 +2,7 @@ import { buildCacheImageForLaravel, buildImage } from '$lib/docker'; import { promises as fs } from 'fs'; const createDockerfile = async (data, image): Promise => { - const { workdir, applicationId, tag, buildId } = data; + const { workdir, applicationId, tag, buildId, port } = data; const Dockerfile: Array = []; Dockerfile.push(`FROM ${image}`); @@ -24,7 +24,7 @@ const createDockerfile = async (data, image): Promise => { `COPY --chown=application:application --from=${applicationId}:${tag}-cache /app/mix-manifest.json /app/public/mix-manifest.json` ); Dockerfile.push(`COPY --chown=application:application . ./`); - Dockerfile.push(`EXPOSE 80`); + Dockerfile.push(`EXPOSE ${port}`); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); }; diff --git a/src/lib/buildPacks/php.ts b/src/lib/buildPacks/php.ts index b3c9651ce..d04e86712 100644 --- a/src/lib/buildPacks/php.ts +++ b/src/lib/buildPacks/php.ts @@ -2,7 +2,7 @@ import { buildImage } from '$lib/docker'; import { promises as fs } from 'fs'; const createDockerfile = async (data, image, htaccessFound): Promise => { - const { workdir, baseDirectory, buildId } = data; + const { workdir, baseDirectory, buildId, port } = data; const Dockerfile: Array = []; let composerFound = false; try { @@ -22,7 +22,7 @@ const createDockerfile = async (data, image, htaccessFound): Promise => { } Dockerfile.push(`COPY /entrypoint.sh /opt/docker/provision/entrypoint.d/30-entrypoint.sh`); - Dockerfile.push(`EXPOSE 80`); + Dockerfile.push(`EXPOSE ${port}`); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); }; diff --git a/src/lib/buildPacks/react.ts b/src/lib/buildPacks/react.ts index 3b55bfa23..5217e8f96 100644 --- a/src/lib/buildPacks/react.ts +++ b/src/lib/buildPacks/react.ts @@ -2,7 +2,7 @@ import { buildCacheImageWithNode, buildImage } from '$lib/docker'; import { promises as fs } from 'fs'; const createDockerfile = async (data, image): Promise => { - const { applicationId, tag, workdir, publishDirectory, baseImage, buildId } = data; + const { applicationId, tag, workdir, publishDirectory, baseImage, buildId, port } = data; const Dockerfile: Array = []; Dockerfile.push(`FROM ${image}`); @@ -12,7 +12,7 @@ const createDockerfile = async (data, image): Promise => { if (baseImage.includes('nginx')) { Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`); } - Dockerfile.push(`EXPOSE 80`); + Dockerfile.push(`EXPOSE ${port}`); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); }; diff --git a/src/lib/buildPacks/static.ts b/src/lib/buildPacks/static.ts index 8f3c2c7d4..79647ae93 100644 --- a/src/lib/buildPacks/static.ts +++ b/src/lib/buildPacks/static.ts @@ -12,7 +12,8 @@ const createDockerfile = async (data, image): Promise => { secrets, pullmergeRequestId, baseImage, - buildId + buildId, + port } = data; const Dockerfile: Array = []; @@ -42,7 +43,7 @@ const createDockerfile = async (data, image): Promise => { if (baseImage.includes('nginx')) { Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`); } - Dockerfile.push(`EXPOSE 80`); + Dockerfile.push(`EXPOSE ${port}`); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); }; diff --git a/src/lib/buildPacks/svelte.ts b/src/lib/buildPacks/svelte.ts index 5604e7ed6..bede0e806 100644 --- a/src/lib/buildPacks/svelte.ts +++ b/src/lib/buildPacks/svelte.ts @@ -2,7 +2,7 @@ import { buildCacheImageWithNode, buildImage } from '$lib/docker'; import { promises as fs } from 'fs'; const createDockerfile = async (data, image): Promise => { - const { applicationId, tag, workdir, publishDirectory, baseImage, buildId } = data; + const { applicationId, tag, workdir, publishDirectory, baseImage, buildId, port } = data; const Dockerfile: Array = []; Dockerfile.push(`FROM ${image}`); @@ -12,7 +12,7 @@ const createDockerfile = async (data, image): Promise => { if (baseImage.includes('nginx')) { Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`); } - Dockerfile.push(`EXPOSE 80`); + Dockerfile.push(`EXPOSE ${port}`); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); }; diff --git a/src/lib/buildPacks/vuejs.ts b/src/lib/buildPacks/vuejs.ts index 5604e7ed6..bede0e806 100644 --- a/src/lib/buildPacks/vuejs.ts +++ b/src/lib/buildPacks/vuejs.ts @@ -2,7 +2,7 @@ import { buildCacheImageWithNode, buildImage } from '$lib/docker'; import { promises as fs } from 'fs'; const createDockerfile = async (data, image): Promise => { - const { applicationId, tag, workdir, publishDirectory, baseImage, buildId } = data; + const { applicationId, tag, workdir, publishDirectory, baseImage, buildId, port } = data; const Dockerfile: Array = []; Dockerfile.push(`FROM ${image}`); @@ -12,7 +12,7 @@ const createDockerfile = async (data, image): Promise => { if (baseImage.includes('nginx')) { Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`); } - Dockerfile.push(`EXPOSE 80`); + Dockerfile.push(`EXPOSE ${port}`); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); }; diff --git a/src/routes/applications/[id]/check.json.ts b/src/routes/applications/[id]/check.json.ts index f432b5dba..8c4b12af1 100644 --- a/src/routes/applications/[id]/check.json.ts +++ b/src/routes/applications/[id]/check.json.ts @@ -50,10 +50,13 @@ export const post: RequestHandler = async (event) => { exposePort = Number(exposePort); if (exposePort < 1024 || exposePort > 65535) { - throw { message: `Expose Port needs to be between 1024 and 65535` }; + throw { message: `Expose Port needs to be between 1024 and 65535.` }; } const publicPort = await getPort({ port: exposePort }); + if (publicPort !== exposePort) { + throw { message: `Port ${exposePort} is already in use.` }; + } } return { diff --git a/src/routes/applications/[id]/index.svelte b/src/routes/applications/[id]/index.svelte index c1afa6b14..71cfa3dc3 100644 --- a/src/routes/applications/[id]/index.svelte +++ b/src/routes/applications/[id]/index.svelte @@ -62,7 +62,6 @@ let previews = application.settings.previews; let dualCerts = application.settings.dualCerts; let autodeploy = application.settings.autodeploy; - let showExposePort = application.exposePort !== null; let wsgis = [ { @@ -455,35 +454,23 @@ /> {/if} - {#if !staticDeployments.includes(application.buildPack)} + {#if application.buildPack !== 'docker'}
- { - showExposePort = !showExposePort; - application.exposePort = undefined; - }} - title={$t('application.expose_a_port')} - description="Expose a port to the host system" + + +
Useful if you would like to use your own reverse proxy or tunnel and also in development mode. Otherwise leave empty.'} />
- - {#if showExposePort} -
- - -
- {/if} {/if} {#if !notNodeDeployments.includes(application.buildPack)} -
+
@@ -521,7 +508,7 @@
{/if} {#if application.buildPack === 'docker'} -
+
From aa2f328640ace0748e72193801c5a4ce0d5965e8 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 5 May 2022 13:20:59 +0200 Subject: [PATCH 033/118] fix: logos for dbs --- .../components/svg/databases/MariaDB.svelte | 76 ++++--------------- .../components/svg/databases/MongoDB.svelte | 32 ++------ 2 files changed, 23 insertions(+), 85 deletions(-) diff --git a/src/lib/components/svg/databases/MariaDB.svelte b/src/lib/components/svg/databases/MariaDB.svelte index 86e7871d1..1de83ef15 100644 --- a/src/lib/components/svg/databases/MariaDB.svelte +++ b/src/lib/components/svg/databases/MariaDB.svelte @@ -3,66 +3,22 @@ - - - - - - - - - - - - - - - - - + + + + diff --git a/src/lib/components/svg/databases/MongoDB.svelte b/src/lib/components/svg/databases/MongoDB.svelte index b99ffe4da..ea0d2859d 100644 --- a/src/lib/components/svg/databases/MongoDB.svelte +++ b/src/lib/components/svg/databases/MongoDB.svelte @@ -3,31 +3,13 @@ - + d="M203.77731,148.85754c-10.8147-12.762-20.13269-25.8139-22.02478-28.49224a.426.426,0,0,0-.70032.00006c-1.89172,2.6784-11.20758,15.73022-22.02191,28.49218-92.69141,118.085,14.62982,197.75507,14.62982,197.75507l.87.60461c.8136,12.32624,2.83508,30.041,2.83508,30.041H185.442s2.01282-17.63849,2.83-29.96106l.87549-.68451S296.46774,266.94257,203.77731,148.85754ZM181.404,344.88123h-.001s-4.811-4.10383-6.10962-6.16l-.01172-.22131,5.81946-128.56055a.30281.30281,0,0,1,.605,0l5.81946,128.56036-.01135.22065C186.21652,340.77625,181.404,344.88123,181.404,344.88123Z" + fill="#00684a" + /> From 0da4a1024a17bf5b5085c32b1d63b99614329860 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 5 May 2022 13:22:42 +0200 Subject: [PATCH 034/118] Add feedback link --- .github/ISSUE_TEMPLATE/--feature-request.yaml | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/--feature-request.yaml b/.github/ISSUE_TEMPLATE/--feature-request.yaml index b6ba5125f..9e217ff23 100644 --- a/.github/ISSUE_TEMPLATE/--feature-request.yaml +++ b/.github/ISSUE_TEMPLATE/--feature-request.yaml @@ -1,31 +1,31 @@ name: 🛠️ Feature request description: Suggest an idea to improve coolify -title: "[Feature]: " +title: '[Feature]: ' labels: [Enhancement] assignees: -- andrasbacsai -- vasani-arpit + - andrasbacsai + - vasani-arpit body: -- type: markdown - attributes: - value: | - Thanks for taking the time to request a feature for coolify! -- type: checkboxes - attributes: - label: Is there an existing issue for this? - description: Please search to see if an issue related to this feature request already exists. - options: - - label: I have searched the existing issues + - type: markdown + attributes: + value: | + Thanks for taking the time to request a feature for coolify! Please also add your request here to get feedback from the community: https://feedback.coolify.io/! + - type: checkboxes + attributes: + label: Is there an existing issue for this? + description: Please search to see if an issue related to this feature request already exists. + options: + - label: I have searched the existing issues + required: true + - type: textarea + attributes: + label: Summary + description: One paragraph description of the feature. + validations: + required: true + - type: textarea + attributes: + label: Why should this be worked on? + description: A concise description of the problems or use cases for this feature request. + validations: required: true -- type: textarea - attributes: - label: Summary - description: One paragraph description of the feature. - validations: - required: true -- type: textarea - attributes: - label: Why should this be worked on? - description: A concise description of the problems or use cases for this feature request. - validations: - required: true From 4046c472ed55b4c87526ba6e4313ae04cb03307e Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 5 May 2022 13:29:46 +0200 Subject: [PATCH 035/118] chore: version++ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ece20c8eb..29b7566ef 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "coolify", "description": "An open-source & self-hostable Heroku / Netlify alternative.", - "version": "2.6.3", + "version": "2.7.0", "license": "AGPL-3.0", "scripts": { "dev": "docker-compose -f docker-compose-dev.yaml up -d && cross-env NODE_ENV=development & svelte-kit dev --host 0.0.0.0", From eccd7c96d75fd3253b5392726c0c34038141a8fd Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 5 May 2022 13:31:36 +0200 Subject: [PATCH 036/118] fix: Do not run SSL renew in development --- src/lib/letsencrypt/index.ts | 38 +++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/lib/letsencrypt/index.ts b/src/lib/letsencrypt/index.ts index 7b64b8a9e..0f2a2b1d6 100644 --- a/src/lib/letsencrypt/index.ts +++ b/src/lib/letsencrypt/index.ts @@ -292,26 +292,28 @@ export async function generateSSLCerts(): Promise { } export async function renewSSLCerts(): Promise { - const host = 'unix:///var/run/docker.sock'; - await asyncExecShell(`docker pull alpine:latest`); - const certbotImage = - process.arch === 'x64' ? 'certbot/certbot' : 'certbot/certbot:arm64v8-latest'; + if (!dev) { + const host = 'unix:///var/run/docker.sock'; + await asyncExecShell(`docker pull alpine:latest`); + const certbotImage = + process.arch === 'x64' ? 'certbot/certbot' : 'certbot/certbot:arm64v8-latest'; - const { stdout: certificates } = await asyncExecShell( - `DOCKER_HOST=${host} docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest sh -c "ls -1 /etc/letsencrypt/live/ | grep -v README"` - ); + const { stdout: certificates } = await asyncExecShell( + `DOCKER_HOST=${host} docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest sh -c "ls -1 /etc/letsencrypt/live/ | grep -v README"` + ); - for (const certificate of certificates.trim().split('\n')) { - try { - await asyncExecShell( - `DOCKER_HOST=${host} docker run --rm --name certbot-renewal -p 9080:9080 -v "coolify-letsencrypt:/etc/letsencrypt" ${certbotImage} --cert-name ${certificate} --logs-dir /etc/letsencrypt/logs renew --standalone --preferred-challenges http --http-01-address 0.0.0.0 --http-01-port 9080` - ); - await asyncExecShell( - `DOCKER_HOST=${host} docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest sh -c "test -d /etc/letsencrypt/live/${certificate}/ && cat /etc/letsencrypt/live/${certificate}/fullchain.pem /etc/letsencrypt/live/${certificate}/privkey.pem > /app/ssl/${certificate}.pem"` - ); - } catch (error) { - console.log(error); + for (const certificate of certificates.trim().split('\n')) { + try { + await asyncExecShell( + `DOCKER_HOST=${host} docker run --rm --name certbot-renewal -p 9080:9080 -v "coolify-letsencrypt:/etc/letsencrypt" ${certbotImage} --cert-name ${certificate} --logs-dir /etc/letsencrypt/logs renew --standalone --preferred-challenges http --http-01-address 0.0.0.0 --http-01-port 9080` + ); + await asyncExecShell( + `DOCKER_HOST=${host} docker run --rm -v "coolify-letsencrypt:/etc/letsencrypt" -v "coolify-ssl-certs:/app/ssl" alpine:latest sh -c "test -d /etc/letsencrypt/live/${certificate}/ && cat /etc/letsencrypt/live/${certificate}/fullchain.pem /etc/letsencrypt/live/${certificate}/privkey.pem > /app/ssl/${certificate}.pem"` + ); + } catch (error) { + console.log(error); + } } + await reloadHaproxy('unix:///var/run/docker.sock'); } - await reloadHaproxy('unix:///var/run/docker.sock'); } From f56d4dbbb3a001c4ad753c947473e2c157b80f3f Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Thu, 5 May 2022 15:18:13 +0200 Subject: [PATCH 037/118] fix: Check domain for coolify before saving --- package.json | 1 + pnpm-lock.yaml | 103 +++++++++++---------------- src/routes/settings/check.json.ts | 113 ++++++++++++++++++++++++++++-- src/routes/settings/index.json.ts | 4 +- src/routes/settings/index.svelte | 19 +++-- 5 files changed, 167 insertions(+), 73 deletions(-) diff --git a/package.json b/package.json index 29b7566ef..5c93290e9 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ "generate-password": "1.7.0", "get-port": "6.1.2", "got": "12.0.3", + "is-ip": "^4.0.0", "js-cookie": "3.0.1", "js-yaml": "4.1.0", "jsonwebtoken": "8.5.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 46dca967e..10f21d2f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: 5.3 +lockfileVersion: 5.4 specifiers: '@iarna/toml': 2.2.5 @@ -31,6 +31,7 @@ specifiers: get-port: 6.1.2 got: 12.0.3 husky: 7.0.4 + is-ip: ^4.0.0 js-cookie: 3.0.1 js-yaml: 4.1.0 jsonwebtoken: 8.5.1 @@ -71,6 +72,7 @@ dependencies: generate-password: 1.7.0 get-port: 6.1.2 got: 12.0.3 + is-ip: 4.0.0 js-cookie: 3.0.1 js-yaml: 4.1.0 jsonwebtoken: 8.5.1 @@ -88,29 +90,29 @@ devDependencies: '@types/js-yaml': 4.0.5 '@types/node': 17.0.25 '@types/node-forge': 1.0.1 - '@typescript-eslint/eslint-plugin': 4.31.1_8ede7edd7694646e12d33c52460f622c - '@typescript-eslint/parser': 4.31.1_eslint@7.32.0+typescript@4.6.3 + '@typescript-eslint/eslint-plugin': 4.31.1_r3ph5xlwsrsg4ewthrjemd3cfq + '@typescript-eslint/parser': 4.31.1_hrkuebk64jiu2ut2d2sm4oylnu '@zerodevx/svelte-toast': 0.7.1 autoprefixer: 10.4.4_postcss@8.4.12 cross-env: 7.0.3 cross-var: 1.1.0 eslint: 7.32.0 eslint-config-prettier: 8.5.0_eslint@7.32.0 - eslint-plugin-svelte3: 3.4.1_eslint@7.32.0+svelte@3.47.0 + eslint-plugin-svelte3: 3.4.1_4oxeyilw5mxcaksmcxtpjddhfe husky: 7.0.4 lint-staged: 12.4.0 postcss: 8.4.12 prettier: 2.6.2 - prettier-plugin-svelte: 2.7.0_prettier@2.6.2+svelte@3.47.0 + prettier-plugin-svelte: 2.7.0_sqtt6dzjlskmywoml5ykunxlce prettier-plugin-tailwindcss: 0.1.10_prettier@2.6.2 prisma: 3.11.1 svelte: 3.47.0 - svelte-check: 2.7.0_postcss@8.4.12+svelte@3.47.0 - svelte-preprocess: 4.10.6_41810887ae6c6d59323116f47e33fa38 + svelte-check: 2.7.0_cp6olp7pwsfaq5mjijwt65d6uy + svelte-preprocess: 4.10.6_igaqrb5onrwvsmrrc32h4m72ha svelte-select: 4.4.7 sveltekit-i18n: 2.1.2_svelte@3.47.0 tailwindcss: 3.0.24_ts-node@10.7.0 - ts-node: 10.7.0_de7c86b0cde507c63a0402da5b982bd3 + ts-node: 10.7.0_3z6inmgn4ud4moqealnfxgbl2m tslib: 2.3.1 typescript: 4.6.3 @@ -494,26 +496,6 @@ 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: { @@ -591,26 +573,7 @@ packages: '@types/node': 17.0.25 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: + /@typescript-eslint/eslint-plugin/4.31.1_r3ph5xlwsrsg4ewthrjemd3cfq: resolution: { integrity: sha512-UDqhWmd5i0TvPLmbK5xY3UZB0zEGseF+DHPghZ37Sb83Qd3p8ujhvAtkU4OF46Ka5Pm5kWvFIx0cCTBFKo0alA== @@ -624,8 +587,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/experimental-utils': 4.31.1_eslint@7.32.0+typescript@4.6.3 - '@typescript-eslint/parser': 4.31.1_eslint@7.32.0+typescript@4.6.3 + '@typescript-eslint/experimental-utils': 4.31.1_hrkuebk64jiu2ut2d2sm4oylnu + '@typescript-eslint/parser': 4.31.1_hrkuebk64jiu2ut2d2sm4oylnu '@typescript-eslint/scope-manager': 4.31.1 debug: 4.3.3 eslint: 7.32.0 @@ -638,7 +601,7 @@ packages: - supports-color dev: true - /@typescript-eslint/experimental-utils/4.31.1_eslint@7.32.0+typescript@4.6.3: + /@typescript-eslint/experimental-utils/4.31.1_hrkuebk64jiu2ut2d2sm4oylnu: resolution: { integrity: sha512-NtoPsqmcSsWty0mcL5nTZXMf7Ei0Xr2MT8jWjXMVgRK0/1qeQ2jZzLFUh4QtyJ4+/lPUyMw5cSfeeME+Zrtp9Q== @@ -659,7 +622,7 @@ packages: - typescript dev: true - /@typescript-eslint/parser/4.31.1_eslint@7.32.0+typescript@4.6.3: + /@typescript-eslint/parser/4.31.1_hrkuebk64jiu2ut2d2sm4oylnu: resolution: { integrity: sha512-dnVZDB6FhpIby6yVbHkwTKkn2ypjVIfAR9nh+kYsA/ZL0JlTsd22BiDjouotisY3Irmd3OW1qlk9EI5R8GrvRQ== @@ -2652,7 +2615,7 @@ packages: eslint: 7.32.0 dev: true - /eslint-plugin-svelte3/3.4.1_eslint@7.32.0+svelte@3.47.0: + /eslint-plugin-svelte3/3.4.1_4oxeyilw5mxcaksmcxtpjddhfe: resolution: { integrity: sha512-7p59WG8qV8L6wLdl4d/c3mdjkgVglQCdv5XOTk/iNPBKXuuV+Q0eFP5Wa6iJd/G2M1qR3BkLPEzaANOqKAZczw== @@ -3322,6 +3285,14 @@ packages: - supports-color dev: false + /ip-regex/5.0.0: + resolution: + { + integrity: sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw== + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + dev: false + /is-binary-path/2.1.0: resolution: { @@ -3380,6 +3351,16 @@ packages: is-extglob: 2.1.1 dev: true + /is-ip/4.0.0: + resolution: + { + integrity: sha512-4B4XA2HEIm/PY+OSpeMBXr8pGWBYbXuHgjMAqrwbLO3CPTCAd9ArEJzBUKGZtk9viY6+aSfadGnWyjY3ydYZkw== + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + dependencies: + ip-regex: 5.0.0 + dev: false + /is-number/7.0.0: resolution: { @@ -4142,7 +4123,7 @@ packages: postcss: 8.4.12 dev: true - /postcss-load-config/3.1.4_postcss@8.4.12+ts-node@10.7.0: + /postcss-load-config/3.1.4_ysmyu6g5dtd6yanj6zrab4uqoy: resolution: { integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg== @@ -4159,7 +4140,7 @@ packages: dependencies: lilconfig: 2.0.5 postcss: 8.4.12 - ts-node: 10.7.0_de7c86b0cde507c63a0402da5b982bd3 + ts-node: 10.7.0_3z6inmgn4ud4moqealnfxgbl2m yaml: 1.10.2 dev: true @@ -4214,7 +4195,7 @@ packages: engines: { node: '>= 0.8.0' } dev: true - /prettier-plugin-svelte/2.7.0_prettier@2.6.2+svelte@3.47.0: + /prettier-plugin-svelte/2.7.0_sqtt6dzjlskmywoml5ykunxlce: resolution: { integrity: sha512-fQhhZICprZot2IqEyoiUYLTRdumULGRvw0o4dzl5jt0jfzVWdGqeYW27QTWAeXhoupEZJULmNoH3ueJwUWFLIA== @@ -4897,7 +4878,7 @@ packages: engines: { node: '>= 0.4' } dev: true - /svelte-check/2.7.0_postcss@8.4.12+svelte@3.47.0: + /svelte-check/2.7.0_cp6olp7pwsfaq5mjijwt65d6uy: resolution: { integrity: sha512-GrvG24j0+i8AOm0k0KyJ6Dqc+TAR2yzB7rtS4nljHStunVxCTr/1KYlv4EsOeoqtHLzeWMOd5D2O6nDdP/yw4A== @@ -4913,7 +4894,7 @@ packages: sade: 1.7.4 source-map: 0.7.3 svelte: 3.47.0 - svelte-preprocess: 4.10.6_41810887ae6c6d59323116f47e33fa38 + svelte-preprocess: 4.10.6_igaqrb5onrwvsmrrc32h4m72ha typescript: 4.6.3 transitivePeerDependencies: - '@babel/core' @@ -4946,7 +4927,7 @@ packages: } dev: false - /svelte-preprocess/4.10.6_41810887ae6c6d59323116f47e33fa38: + /svelte-preprocess/4.10.6_igaqrb5onrwvsmrrc32h4m72ha: resolution: { integrity: sha512-I2SV1w/AveMvgIQlUF/ZOO3PYVnhxfcpNyGt8pxpUVhPfyfL/CZBkkw/KPfuFix5FJ9TnnNYMhACK3DtSaYVVQ== @@ -5078,7 +5059,7 @@ packages: picocolors: 1.0.0 postcss: 8.4.12 postcss-js: 4.0.0_postcss@8.4.12 - postcss-load-config: 3.1.4_postcss@8.4.12+ts-node@10.7.0 + postcss-load-config: 3.1.4_ysmyu6g5dtd6yanj6zrab4uqoy postcss-nested: 5.0.6_postcss@8.4.12 postcss-selector-parser: 6.0.10 postcss-value-parser: 4.2.0 @@ -5152,7 +5133,7 @@ packages: engines: { node: '>=0.10.0' } dev: true - /ts-node/10.7.0_de7c86b0cde507c63a0402da5b982bd3: + /ts-node/10.7.0_3z6inmgn4ud4moqealnfxgbl2m: resolution: { integrity: sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A== diff --git a/src/routes/settings/check.json.ts b/src/routes/settings/check.json.ts index bec577001..66cbe7dbf 100644 --- a/src/routes/settings/check.json.ts +++ b/src/routes/settings/check.json.ts @@ -1,25 +1,124 @@ -import { asyncExecShell, getEngine, getUserDetails } from '$lib/common'; +import { dev } from '$app/env'; +import { asyncExecShell, getDomain, getEngine, getUserDetails } from '$lib/common'; import * as db from '$lib/database'; import { ErrorHandler } from '$lib/database'; import { t } from '$lib/translations'; +import { promises as dns } from 'dns'; import type { RequestHandler } from '@sveltejs/kit'; +import { isIP } from 'is-ip'; export const post: RequestHandler = async (event) => { const { status, body } = await getUserDetails(event); if (status === 401) return { status, body }; const { id } = event.params; - let { fqdn } = await event.request.json(); + let { fqdn, forceSave, dualCerts, isDNSCheckEnabled } = await event.request.json(); if (fqdn) fqdn = fqdn.toLowerCase(); try { + const domain = getDomain(fqdn); + const domainDualCert = domain.includes('www.') ? domain.replace('www.', '') : `www.${domain}`; const found = await db.isDomainConfigured({ id, fqdn }); - return { - status: found ? 500 : 200, - body: { - error: - found && t.get('application.domain_already_in_use', { domain: fqdn.replace('www.', '') }) + if (found) { + throw { + message: t.get('application.domain_already_in_use', { + domain: getDomain(fqdn).replace('www.', '') + }) + }; + } + if (isDNSCheckEnabled) { + if (!forceSave) { + dns.setServers(['1.1.1.1', '8.8.8.8']); + if (dualCerts) { + try { + const ipDomain = await dns.resolve4(domain); + const ipDomainDualCert = await dns.resolve4(domainDualCert); + console.log({ ipDomain, ipDomainDualCert }); + if ( + ipDomain.length === ipDomainDualCert.length && + ipDomain.every((v) => ipDomainDualCert.indexOf(v) >= 0) + ) { + let resolves = []; + if (isIP(event.url.hostname)) { + resolves = [event.url.hostname]; + } else { + resolves = await dns.resolve4(event.url.hostname); + } + console.log({ resolves }); + if (resolves.includes(ipDomain) || resolves.includes(ipDomainDualCert)) { + console.log('OK'); + } else { + throw false; + } + } else { + throw false; + } + } catch (error) { + console.log(error); + throw { + message: t.get('application.dns_not_set_error', { domain }) + }; + } + } else { + let resolves = []; + try { + const ipDomain = await dns.resolve4(domain); + console.log({ ipDomain }); + if (isIP(event.url.hostname)) { + resolves = [event.url.hostname]; + } else { + resolves = await dns.resolve4(event.url.hostname); + } + console.log({ resolves }); + if (resolves.includes(ipDomain)) { + console.log('OK'); + } else { + throw false; + } + } catch (error) { + console.log(error); + throw { + message: t.get('application.dns_not_set_error', { domain }) + }; + } + } + // let localReverseDomains = []; + // let newIps = []; + // let newIpsWWW = []; + // let localIps = []; + // try { + // localReverseDomains = await dns.reverse(event.url.hostname) + // } catch (error) { } + // try { + // localIps = await dns.resolve4(event.url.hostname); + // } catch (error) { } + // try { + // newIps = await dns.resolve4(domain); + // if (dualCerts) { + // newIpsWWW = await dns.resolve4(`${isWWW ? nonWWW : domain}`) + // } + // console.log(newIps) + // } catch (error) { } + // console.log({ localIps, newIps, localReverseDomains, dualCerts, isWWW, nonWWW }) + // if (localReverseDomains?.length > 0) { + // if ((newIps?.length === 0 || !newIps.includes(event.url.hostname)) || (dualCerts && newIpsWWW?.length === 0 && !newIpsWWW.includes(`${isWWW ? nonWWW : domain}`))) { + // throw { + // message: t.get('application.dns_not_set_error', { domain }) + // }; + // } + // } + // if (localIps?.length > 0) { + // if (newIps?.length === 0 || !localIps.includes(newIps[0])) { + // throw { + // message: t.get('application.dns_not_set_error', { domain }) + // }; + // } + // } } + } + + return { + status: 200 }; } catch (error) { return ErrorHandler(error); diff --git a/src/routes/settings/index.json.ts b/src/routes/settings/index.json.ts index 5546d782f..21f4907f2 100644 --- a/src/routes/settings/index.json.ts +++ b/src/routes/settings/index.json.ts @@ -1,3 +1,4 @@ +import { dev } from '$app/env'; import { getUserDetails } from '$lib/common'; import * as db from '$lib/database'; import { listSettings, ErrorHandler } from '$lib/database'; @@ -71,7 +72,8 @@ export const post: RequestHandler = async (event) => { minPort, maxPort, isAutoUpdateEnabled, - isDNSCheckEnabled + isDNSCheckEnabled, + forceSave } = await event.request.json(); try { const { id } = await db.listSettings(); diff --git a/src/routes/settings/index.svelte b/src/routes/settings/index.svelte index 20e1c788d..1a4f25801 100644 --- a/src/routes/settings/index.svelte +++ b/src/routes/settings/index.svelte @@ -47,6 +47,7 @@ let minPort = settings.minPort; let maxPort = settings.maxPort; + let forceSave = false; let fqdn = settings.fqdn; let isFqdnSet = !!settings.fqdn; let loading = { @@ -96,7 +97,7 @@ try { loading.save = true; if (fqdn !== settings.fqdn) { - await post(`/settings/check.json`, { fqdn }); + await post(`/settings/check.json`, { fqdn, forceSave, dualCerts, isDNSCheckEnabled }); await post(`/settings.json`, { fqdn }); return window.location.reload(); } @@ -106,6 +107,9 @@ settings.maxPort = maxPort; } } catch ({ error }) { + if (error?.startsWith($t('application.dns_not_set_partial_error'))) { + forceSave = true; + } return errorNotification(error); } finally { loading.save = false; @@ -131,11 +135,18 @@
{$t('index.global_settings')}
{loading.save + ? $t('forms.saving') + : forceSave + ? $t('forms.confirm_continue') + : $t('forms.save')} + {#if isFqdnSet} + {#if dualCerts} + + {/if} +
+ {/if} +
{ + const { status, body } = await getUserDetails(event); + if (status === 401) return { status, body }; + const domain = event.url.searchParams.get('domain'); + if (!domain) { + return { + status: 500, + body: { + message: t.get('application.domain_required') + } + }; + } + try { + await isDNSValid(event, domain); + return { + status: 200 + }; + } catch (error) { + return ErrorHandler(error); + } +}; export const post: RequestHandler = async (event) => { const { status, body } = await getUserDetails(event); @@ -14,11 +34,9 @@ export const post: RequestHandler = async (event) => { let { fqdn, forceSave, dualCerts, isDNSCheckEnabled } = await event.request.json(); if (fqdn) fqdn = fqdn.toLowerCase(); - try { - const domain = getDomain(fqdn); - const domainDualCert = domain.includes('www.') ? domain.replace('www.', '') : `www.${domain}`; const found = await db.isDomainConfigured({ id, fqdn }); + console.log(found); if (found) { throw { message: t.get('application.domain_already_in_use', { @@ -26,111 +44,9 @@ export const post: RequestHandler = async (event) => { }) }; } - if (isDNSCheckEnabled) { - if (!forceSave) { - dns.setServers(['1.1.1.1', '8.8.8.8']); - if (dualCerts) { - try { - const ipDomain = await dns.resolve4(domain); - const ipDomainDualCert = await dns.resolve4(domainDualCert); - console.log({ ipDomain, ipDomainDualCert }); - // TODO: Check if ipDomain and ipDomainDualCert are the same, but not like this - if ( - ipDomain.length === ipDomainDualCert.length && - ipDomain.every((v) => ipDomainDualCert.indexOf(v) >= 0) - ) { - let resolves = []; - if (isIP(event.url.hostname)) { - resolves = [event.url.hostname]; - } else { - resolves = await dns.resolve4(event.url.hostname); - } - console.log({ resolves }); - for (const ip of ipDomain) { - if (resolves.includes(ip)) { - return { - status: 200 - }; - } - } - for (const ip of ipDomainDualCert) { - if (resolves.includes(ip)) { - return { - status: 200 - }; - } - } - throw false; - } else { - throw false; - } - } catch (error) { - console.log(error); - throw { - message: t.get('application.dns_not_set_error', { domain }) - }; - } - } else { - let resolves = []; - try { - const ipDomain = await dns.resolve4(domain); - console.log({ ipDomain }); - if (isIP(event.url.hostname)) { - resolves = [event.url.hostname]; - } else { - resolves = await dns.resolve4(event.url.hostname); - } - console.log({ resolves }); - for (const ip of ipDomain) { - if (resolves.includes(ip)) { - return { - status: 200 - }; - } - } - throw false; - } catch (error) { - console.log(error); - throw { - message: t.get('application.dns_not_set_error', { domain }) - }; - } - } - // let localReverseDomains = []; - // let newIps = []; - // let newIpsWWW = []; - // let localIps = []; - // try { - // localReverseDomains = await dns.reverse(event.url.hostname) - // } catch (error) { } - // try { - // localIps = await dns.resolve4(event.url.hostname); - // } catch (error) { } - // try { - // newIps = await dns.resolve4(domain); - // if (dualCerts) { - // newIpsWWW = await dns.resolve4(`${isWWW ? nonWWW : domain}`) - // } - // console.log(newIps) - // } catch (error) { } - // console.log({ localIps, newIps, localReverseDomains, dualCerts, isWWW, nonWWW }) - // if (localReverseDomains?.length > 0) { - // if ((newIps?.length === 0 || !newIps.includes(event.url.hostname)) || (dualCerts && newIpsWWW?.length === 0 && !newIpsWWW.includes(`${isWWW ? nonWWW : domain}`))) { - // throw { - // message: t.get('application.dns_not_set_error', { domain }) - // }; - // } - // } - // if (localIps?.length > 0) { - // if (newIps?.length === 0 || !localIps.includes(newIps[0])) { - // throw { - // message: t.get('application.dns_not_set_error', { domain }) - // }; - // } - // } - } + if (isDNSCheckEnabled && !forceSave) { + return await checkDomainsIsValidInDNS({ event, fqdn, dualCerts }); } - return { status: 200 }; diff --git a/src/routes/settings/index.svelte b/src/routes/settings/index.svelte index 1a4f25801..7d3f7aad3 100644 --- a/src/routes/settings/index.svelte +++ b/src/routes/settings/index.svelte @@ -31,7 +31,7 @@ import Setting from '$lib/components/Setting.svelte'; import Explainer from '$lib/components/Explainer.svelte'; import { errorNotification } from '$lib/form'; - import { del, post } from '$lib/api'; + import { del, get, post } from '$lib/api'; import CopyPasswordField from '$lib/components/CopyPasswordField.svelte'; import { browser } from '$app/env'; import { getDomain } from '$lib/components/common'; @@ -49,6 +49,7 @@ let forceSave = false; let fqdn = settings.fqdn; + let nonWWWDomain = fqdn && getDomain(fqdn).replace(/^www\./, ''); let isFqdnSet = !!settings.fqdn; let loading = { save: false, @@ -96,6 +97,7 @@ async function handleSubmit() { try { loading.save = true; + nonWWWDomain = fqdn && getDomain(fqdn).replace(/^www\./, ''); if (fqdn !== settings.fqdn) { await post(`/settings/check.json`, { fqdn, forceSave, dualCerts, isDNSCheckEnabled }); await post(`/settings.json`, { fqdn }); @@ -106,6 +108,7 @@ settings.minPort = minPort; settings.maxPort = maxPort; } + forceSave = false; } catch ({ error }) { if (error?.startsWith($t('application.dns_not_set_partial_error'))) { forceSave = true; @@ -123,6 +126,14 @@ return errorNotification(error); } } + async function isDNSValid(domain) { + try { + await get(`/settings/check.json?domain=${domain}`); + toast.push('Domain is valid in DNS.'); + } catch ({ error }) { + return errorNotification(error); + } + }
@@ -176,6 +187,23 @@ pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$" placeholder="{$t('forms.eg')}: https://coolify.io" /> + + {#if forceSave} +
+ + {#if dualCerts} + + {/if} +
+ {/if}
From 8e53ae348479fc1bedbd2e537f5cf2e9ce057a3d Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 May 2022 11:42:24 +0200 Subject: [PATCH 044/118] fix: Check DNS in prod only --- src/routes/applications/[id]/check.json.ts | 2 +- src/routes/settings/check.json.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/applications/[id]/check.json.ts b/src/routes/applications/[id]/check.json.ts index 0960014fc..021cb5975 100644 --- a/src/routes/applications/[id]/check.json.ts +++ b/src/routes/applications/[id]/check.json.ts @@ -61,7 +61,7 @@ export const post: RequestHandler = async (event) => { } } - if (isDNSCheckEnabled && !forceSave) { + if (isDNSCheckEnabled && !dev && !forceSave) { return await checkDomainsIsValidInDNS({ event, fqdn, dualCerts }); } diff --git a/src/routes/settings/check.json.ts b/src/routes/settings/check.json.ts index 88eaa0293..22c6c53d8 100644 --- a/src/routes/settings/check.json.ts +++ b/src/routes/settings/check.json.ts @@ -44,7 +44,7 @@ export const post: RequestHandler = async (event) => { }) }; } - if (isDNSCheckEnabled && !forceSave) { + if (isDNSCheckEnabled && !dev && !forceSave) { return await checkDomainsIsValidInDNS({ event, fqdn, dualCerts }); } return { From 9e009bebaa5e870a814024c6777260a784409b1c Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 May 2022 11:53:53 +0200 Subject: [PATCH 045/118] fix --- src/lib/common.ts | 5 ++--- src/lib/locales/en.json | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/lib/common.ts b/src/lib/common.ts index 78da1338f..f9c77f3d3 100644 --- a/src/lib/common.ts +++ b/src/lib/common.ts @@ -193,8 +193,7 @@ export async function isDNSValid(event: any, domain: string): Promise { } } catch (error) { throw { - message: - "Could not resolve domain or it's not pointing to the server IP address.

Please check your domain name and try again." + message: t.get('application.dns_not_set_error', { domain }) }; } @@ -230,7 +229,7 @@ export async function checkDomainsIsValidInDNS({ event, fqdn, dualCerts }): Prom } } catch (error) { throw { - message: t.get('application.dns_not_set_error', { domain: domain }) + message: t.get('application.dns_not_set_error', { domain }) }; } diff --git a/src/lib/locales/en.json b/src/lib/locales/en.json index f6c4ff1e6..c455523af 100644 --- a/src/lib/locales/en.json +++ b/src/lib/locales/en.json @@ -182,7 +182,7 @@ "domain_required": "Domain is required.", "settings_saved": "Settings saved.", "dns_not_set_partial_error": "DNS not set", - "domain_not_valid": "Domain is not valid.", + "domain_not_valid": "Could not resolve domain or it's not pointing to the server IP address.

Please check your DNS configuration and try again.", "git_source": "Git Source", "git_repository": "Git Repository", "build_pack": "Build Pack", @@ -314,7 +314,7 @@ "credential_stat_explainer": "Credentials for
stats page.", "auto_update_enabled": "Auto update enabled?", "auto_update_enabled_explainer": "Enable automatic updates for Coolify. It will be done automatically behind the scenes, if there is no build process running.", - "generate_www_non_www_ssl": "It will generate certificates for both www and non-www.
You need to have both DNS entries set in advance.

Service needs to be restarted.", + "generate_www_non_www_ssl": "It will generate certificates for both www and non-www.
You need to have both DNS entries set in advance.", "is_dns_check_enabled": "DNS check enabled?", "is_dns_check_enabled_explainer": "You can disable DNS check before creating SSL certificates.

Turning it off is useful when Coolify is behind a reverse proxy or tunnel." }, From af0652f6b240f35b9ed53b61e2bad452bbcd1501 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 May 2022 14:07:43 +0200 Subject: [PATCH 046/118] fix: DNS check --- src/routes/applications/[id]/index.svelte | 62 ++++++++++++++++----- src/routes/settings/check.json.ts | 2 +- src/routes/settings/index.svelte | 67 ++++++++++++++++++----- 3 files changed, 104 insertions(+), 27 deletions(-) diff --git a/src/routes/applications/[id]/index.svelte b/src/routes/applications/[id]/index.svelte index 02a158fc5..6d8807123 100644 --- a/src/routes/applications/[id]/index.svelte +++ b/src/routes/applications/[id]/index.svelte @@ -64,6 +64,8 @@ let autodeploy = application.settings.autodeploy; let nonWWWDomain = application.fqdn && getDomain(application.fqdn).replace(/^www\./, ''); + let isNonWWWDomainOK = false; + let isWWWDomainOK = false; let wsgis = [ { @@ -143,6 +145,17 @@ } catch ({ error }) { if (error?.startsWith($t('application.dns_not_set_partial_error'))) { forceSave = true; + if (dualCerts) { + isNonWWWDomainOK = await isDNSValid(getDomain(nonWWWDomain), false); + isWWWDomainOK = await isDNSValid(getDomain(`www.${nonWWWDomain}`), true); + } else { + const isWWW = getDomain(application.fqdn).includes('www.'); + if (isWWW) { + isWWWDomainOK = await isDNSValid(getDomain(`www.${nonWWWDomain}`), true); + } else { + isNonWWWDomainOK = await isDNSValid(getDomain(nonWWWDomain), false); + } + } } return errorNotification(error); } finally { @@ -160,12 +173,17 @@ application.baseBuildImage = event.detail.value; await handleSubmit(); } - async function isDNSValid(domain) { + + async function isDNSValid(domain, isWWW) { try { await get(`/applications/${id}/check.json?domain=${domain}`); - toast.push('Domain is valid in DNS.'); + toast.push('DNS configuration is valid.'); + isWWW ? (isWWWDomainOK = true) : (isNonWWWDomainOK = true); + return true; } catch ({ error }) { - return errorNotification(error); + errorNotification(error); + isWWW ? (isWWWDomainOK = false) : (isNonWWWDomainOK = false); + return false; } } @@ -412,18 +430,36 @@ placeholder="eg: https://coollabs.io" /> {#if forceSave} -
- - {#if dualCerts} +
+ {#if isNonWWWDomainOK} isDNSValid(getDomain(nonWWWDomain), false)} + >DNS settings for {nonWWWDomain} is OK, click to recheck. + {:else} + + {/if} + {#if dualCerts} + {#if isWWWDomainOK} + + {:else} + + {/if} {/if}
{/if} diff --git a/src/routes/settings/check.json.ts b/src/routes/settings/check.json.ts index 22c6c53d8..88eaa0293 100644 --- a/src/routes/settings/check.json.ts +++ b/src/routes/settings/check.json.ts @@ -44,7 +44,7 @@ export const post: RequestHandler = async (event) => { }) }; } - if (isDNSCheckEnabled && !dev && !forceSave) { + if (isDNSCheckEnabled && !forceSave) { return await checkDomainsIsValidInDNS({ event, fqdn, dualCerts }); } return { diff --git a/src/routes/settings/index.svelte b/src/routes/settings/index.svelte index 7d3f7aad3..c601db4ed 100644 --- a/src/routes/settings/index.svelte +++ b/src/routes/settings/index.svelte @@ -50,6 +50,8 @@ let forceSave = false; let fqdn = settings.fqdn; let nonWWWDomain = fqdn && getDomain(fqdn).replace(/^www\./, ''); + let isNonWWWDomainOK = false; + let isWWWDomainOK = false; let isFqdnSet = !!settings.fqdn; let loading = { save: false, @@ -71,6 +73,7 @@ } async function changeSettings(name) { try { + resetView(); if (name === 'isRegistrationEnabled') { isRegistrationEnabled = !isRegistrationEnabled; } @@ -98,6 +101,7 @@ try { loading.save = true; nonWWWDomain = fqdn && getDomain(fqdn).replace(/^www\./, ''); + if (fqdn !== settings.fqdn) { await post(`/settings/check.json`, { fqdn, forceSave, dualCerts, isDNSCheckEnabled }); await post(`/settings.json`, { fqdn }); @@ -112,6 +116,17 @@ } catch ({ error }) { if (error?.startsWith($t('application.dns_not_set_partial_error'))) { forceSave = true; + if (dualCerts) { + isNonWWWDomainOK = await isDNSValid(getDomain(nonWWWDomain), false); + isWWWDomainOK = await isDNSValid(getDomain(`www.${nonWWWDomain}`), true); + } else { + const isWWW = getDomain(settings.fqdn).includes('www.'); + if (isWWW) { + isWWWDomainOK = await isDNSValid(getDomain(`www.${nonWWWDomain}`), true); + } else { + isNonWWWDomainOK = await isDNSValid(getDomain(nonWWWDomain), false); + } + } } return errorNotification(error); } finally { @@ -126,14 +141,21 @@ return errorNotification(error); } } - async function isDNSValid(domain) { + async function isDNSValid(domain, isWWW) { try { await get(`/settings/check.json?domain=${domain}`); - toast.push('Domain is valid in DNS.'); + toast.push('DNS configuration is valid.'); + isWWW ? (isWWWDomainOK = true) : (isNonWWWDomainOK = true); + return true; } catch ({ error }) { - return errorNotification(error); + errorNotification(error); + isWWW ? (isWWWDomainOK = false) : (isNonWWWDomainOK = false); + return false; } } + function resetView() { + forceSave = false; + }
@@ -182,6 +204,7 @@ bind:value={fqdn} readonly={!$session.isAdmin || isFqdnSet} disabled={!$session.isAdmin || isFqdnSet} + on:input={resetView} name="fqdn" id="fqdn" pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$" @@ -189,18 +212,36 @@ /> {#if forceSave} -
- - {#if dualCerts} +
+ {#if isNonWWWDomainOK} isDNSValid(getDomain(nonWWWDomain), false)} + >DNS settings for {nonWWWDomain} is OK, click to recheck. + {:else} + + {/if} + {#if dualCerts} + {#if isWWWDomainOK} + + {:else} + + {/if} {/if}
{/if} From 7cc760eecfdfedbd0bed6b0513870c6668707f1f Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 May 2022 14:43:28 +0200 Subject: [PATCH 047/118] fix: Disable sentry for now --- src/lib/common.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/lib/common.ts b/src/lib/common.ts index f9c77f3d3..61009d42f 100644 --- a/src/lib/common.ts +++ b/src/lib/common.ts @@ -20,21 +20,21 @@ import { t } from './translations'; try { if (!dev) { - Sentry.init({ - dsn: process.env['COOLIFY_SENTRY_DSN'], - tracesSampleRate: 0, - environment: 'production', - debug: true, - release: currentVersion, - initialScope: { - tags: { - appId: process.env['COOLIFY_APP_ID'], - 'os.arch': getOsArch(), - 'os.platform': os.platform(), - 'os.release': os.release() - } - } - }); + // Sentry.init({ + // dsn: process.env['COOLIFY_SENTRY_DSN'], + // tracesSampleRate: 0, + // environment: 'production', + // debug: true, + // release: currentVersion, + // initialScope: { + // tags: { + // appId: process.env['COOLIFY_APP_ID'], + // 'os.arch': getOsArch(), + // 'os.platform': os.platform(), + // 'os.release': os.release() + // } + // } + // }); } } catch (err) { console.log('Could not initialize Sentry, no worries.'); From fa5f439858af748f69d68347cf7d65613a5b8afd Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 May 2022 14:45:50 +0200 Subject: [PATCH 048/118] fix: Cancel --- src/routes/applications/[id]/cancel.json.ts | 108 +++++++++--------- .../[id]/logs/build/_BuildLog.svelte | 33 +++--- 2 files changed, 76 insertions(+), 65 deletions(-) diff --git a/src/routes/applications/[id]/cancel.json.ts b/src/routes/applications/[id]/cancel.json.ts index edaa22c95..e09c954f7 100644 --- a/src/routes/applications/[id]/cancel.json.ts +++ b/src/routes/applications/[id]/cancel.json.ts @@ -3,6 +3,61 @@ import { buildQueue } from '$lib/queues'; import type { RequestHandler } from '@sveltejs/kit'; import * as db from '$lib/database'; +async function cleanupDB(buildId: string) { + const data = await db.prisma.build.findUnique({ where: { id: buildId } }); + if (data?.status === 'queued' || data?.status === 'running') { + await db.prisma.build.update({ where: { id: buildId }, data: { status: 'failed' } }); + } +} + +async function stopBuild(buildId, applicationId) { + let count = 0; + await new Promise(async (resolve, reject) => { + const job = await buildQueue.getJob(buildId); + if (!job) { + await cleanupDB(buildId); + return resolve(); + } + const { + destinationDocker: { engine } + } = job?.data; + const host = getEngine(engine); + let interval = setInterval(async () => { + try { + const data = await db.prisma.build.findUnique({ where: { id: buildId } }); + if (data?.status === 'failed') { + clearInterval(interval); + return resolve(); + } + if (count > 100) { + clearInterval(interval); + return resolve(); + } + + const { stdout: buildContainers } = await asyncExecShell( + `DOCKER_HOST=${host} docker container ls --filter "label=coolify.buildId=${buildId}" --format '{{json .}}'` + ); + if (buildContainers) { + const containersArray = buildContainers.trim().split('\n'); + for (const container of containersArray) { + const containerObj = JSON.parse(container); + const id = containerObj.ID; + if (!containerObj.Names.startsWith(`${applicationId}`)) { + await removeDestinationDocker({ id, engine }); + clearInterval(interval); + await saveBuildLog({ + line: 'Canceled by user!', + buildId: job.data.build_id, + applicationId: job.data.id + }); + } + } + } + count++; + } catch (error) {} + }, 100); + }); +} export const post: RequestHandler = async (event) => { const { buildId, applicationId } = await event.request.json(); if (!buildId) { @@ -14,57 +69,8 @@ export const post: RequestHandler = async (event) => { }; } try { - let count = 0; - await new Promise(async (resolve, reject) => { - const job = await buildQueue.getJob(buildId); - if (!job) { - return resolve(); - } - const { - destinationDocker: { engine } - } = job?.data; - const host = getEngine(engine); - let interval = setInterval(async () => { - try { - const data = await db.prisma.build.findUnique({ where: { id: buildId } }); - if (data?.status === 'failed') { - clearInterval(interval); - return resolve(); - } - if (count > 60) { - clearInterval(interval); - reject(new Error('Could not cancel build.')); - } - - const { stdout: buildContainers } = await asyncExecShell( - `DOCKER_HOST=${host} docker container ls --filter "label=coolify.buildId=${buildId}" --format '{{json .}}'` - ); - if (buildContainers) { - const containersArray = buildContainers.trim().split('\n'); - for (const container of containersArray) { - const containerObj = JSON.parse(container); - const id = containerObj.ID; - if (!containerObj.Names.startsWith(`${applicationId}`)) { - await removeDestinationDocker({ id, engine }); - clearInterval(interval); - await saveBuildLog({ - line: 'Canceled by user!', - buildId: job.data.build_id, - applicationId: job.data.id - }); - } - } - } - count++; - } catch (error) {} - }, 1000); - - resolve(); - }); - const data = await db.prisma.build.findUnique({ where: { id: buildId } }); - if (data?.status === 'queued' || data?.status === 'running') { - await db.prisma.build.update({ where: { id: buildId }, data: { status: 'failed' } }); - } + await stopBuild(buildId, applicationId); + await cleanupDB(buildId); return { status: 200, body: { diff --git a/src/routes/applications/[id]/logs/build/_BuildLog.svelte b/src/routes/applications/[id]/logs/build/_BuildLog.svelte index 378e58c2c..b95e295f1 100644 --- a/src/routes/applications/[id]/logs/build/_BuildLog.svelte +++ b/src/routes/applications/[id]/logs/build/_BuildLog.svelte @@ -129,23 +129,28 @@ {#if currentStatus === 'running'} {/if}
From b5b0b6524da40aea46d82793eb55dba94650bde7 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 May 2022 15:10:28 +0200 Subject: [PATCH 049/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index ac49d22c3..b0b7028d6 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -35,5 +35,5 @@ jobs: platforms: linux/amd64,linux/arm64 push: true tags: coollabsio/coolify:latest,coollabsio/coolify:${{steps.package-version.outputs.current-version}} - cache-from: type=registry,ref=coollabsio/coolify-test:buildcache - cache-to: type=registry,ref=coollabsio/coolify-test:buildcache,mode=max + cache-from: type=registry,ref=coollabsio/coolify:buildcache + cache-to: type=registry,ref=coollabsio/coolify:buildcache,mode=max From 0be402af824a37e4ffe3de7a2ba658aa7b5818d8 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 May 2022 15:18:38 +0200 Subject: [PATCH 050/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index b0b7028d6..5446eac09 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -11,6 +11,8 @@ jobs: - name: Checkout uses: actions/checkout@v2 + with: + path: main - name: Set up QEMU uses: docker/setup-qemu-action@v1 From c34d643f9551bee2c480d095e8cc08db4f44a06b Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 May 2022 15:22:22 +0200 Subject: [PATCH 051/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index 5446eac09..2355641ee 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -1,8 +1,9 @@ name: release-coolify on: - release: - types: published + push: + branches: + - 'main' jobs: make-it-coolifyed: From 21256746c3cd6969c9c13dbf4d944d35c2ddd00d Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 May 2022 15:23:18 +0200 Subject: [PATCH 052/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index 2355641ee..665924ea7 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -3,7 +3,7 @@ name: release-coolify on: push: branches: - - 'main' + - main jobs: make-it-coolifyed: @@ -12,8 +12,6 @@ jobs: - name: Checkout uses: actions/checkout@v2 - with: - path: main - name: Set up QEMU uses: docker/setup-qemu-action@v1 From 6a6426fe6bd732b200c8aad773a40deaaebe4eec Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 May 2022 15:40:07 +0200 Subject: [PATCH 053/118] fix: Sentry --- src/hooks.ts | 2 +- src/lib/database/common.ts | 126 ++++++++++---------- src/lib/queues/builder.ts | 2 +- src/routes/applications/[id]/cancel.json.ts | 3 +- 4 files changed, 66 insertions(+), 67 deletions(-) diff --git a/src/hooks.ts b/src/hooks.ts index 50624b22f..639bab353 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -114,5 +114,5 @@ export const getSession: GetSession = function ({ locals }) { }; export async function handleError({ error, event }) { - if (!dev) sentry.captureException(error, event); + // if (!dev) sentry.captureException(error, event); } diff --git a/src/lib/database/common.ts b/src/lib/database/common.ts index e83308878..c6293e76f 100644 --- a/src/lib/database/common.ts +++ b/src/lib/database/common.ts @@ -58,7 +58,7 @@ export function ErrorHandler(e: { truncatedError.message = 'git clone failed'; } if (!e.message?.includes('Coolify Proxy is not running')) { - sentry.captureException(truncatedError); + // sentry.captureException(truncatedError); } const payload = { status: truncatedError.status || 500, @@ -127,73 +127,73 @@ export function getServiceImages(type: string): string[] { export function generateDatabaseConfiguration(database: Database & { settings: DatabaseSettings }): | { - volume: string; - image: string; - ulimits: Record; - privatePort: number; - environmentVariables: { - MYSQL_DATABASE: string; - MYSQL_PASSWORD: string; - MYSQL_ROOT_USER: string; - MYSQL_USER: string; - MYSQL_ROOT_PASSWORD: string; - }; - } + volume: string; + image: string; + ulimits: Record; + privatePort: number; + environmentVariables: { + MYSQL_DATABASE: string; + MYSQL_PASSWORD: string; + MYSQL_ROOT_USER: string; + MYSQL_USER: string; + MYSQL_ROOT_PASSWORD: string; + }; + } | { - volume: string; - image: string; - ulimits: Record; - privatePort: number; - environmentVariables: { - MONGODB_ROOT_USER: string; - MONGODB_ROOT_PASSWORD: string; - }; - } + volume: string; + image: string; + ulimits: Record; + privatePort: number; + environmentVariables: { + MONGODB_ROOT_USER: string; + MONGODB_ROOT_PASSWORD: string; + }; + } | { - volume: string; - image: string; - ulimits: Record; - privatePort: number; - environmentVariables: { - MARIADB_ROOT_USER: string; - MARIADB_ROOT_PASSWORD: string; - MARIADB_USER: string; - MARIADB_PASSWORD: string; - MARIADB_DATABASE: string; - }; - } + volume: string; + image: string; + ulimits: Record; + privatePort: number; + environmentVariables: { + MARIADB_ROOT_USER: string; + MARIADB_ROOT_PASSWORD: string; + MARIADB_USER: string; + MARIADB_PASSWORD: string; + MARIADB_DATABASE: string; + }; + } | { - volume: string; - image: string; - ulimits: Record; - privatePort: number; - environmentVariables: { - POSTGRESQL_POSTGRES_PASSWORD: string; - POSTGRESQL_USERNAME: string; - POSTGRESQL_PASSWORD: string; - POSTGRESQL_DATABASE: string; - }; - } + volume: string; + image: string; + ulimits: Record; + privatePort: number; + environmentVariables: { + POSTGRESQL_POSTGRES_PASSWORD: string; + POSTGRESQL_USERNAME: string; + POSTGRESQL_PASSWORD: string; + POSTGRESQL_DATABASE: string; + }; + } | { - volume: string; - image: string; - ulimits: Record; - privatePort: number; - environmentVariables: { - REDIS_AOF_ENABLED: string; - REDIS_PASSWORD: string; - }; - } + volume: string; + image: string; + ulimits: Record; + privatePort: number; + environmentVariables: { + REDIS_AOF_ENABLED: string; + REDIS_PASSWORD: string; + }; + } | { - volume: string; - image: string; - ulimits: Record; - privatePort: number; - environmentVariables: { - COUCHDB_PASSWORD: string; - COUCHDB_USER: string; - }; - } { + volume: string; + image: string; + ulimits: Record; + privatePort: number; + environmentVariables: { + COUCHDB_PASSWORD: string; + COUCHDB_USER: string; + }; + } { const { id, dbUser, diff --git a/src/lib/queues/builder.ts b/src/lib/queues/builder.ts index 7c7740945..c69ffb678 100644 --- a/src/lib/queues/builder.ts +++ b/src/lib/queues/builder.ts @@ -328,7 +328,7 @@ export default async function (job: Job): Promise 100) { clearInterval(interval); - return resolve(); + return reject(new Error('Build canceled')); } const { stdout: buildContainers } = await asyncExecShell( @@ -70,7 +70,6 @@ export const post: RequestHandler = async (event) => { } try { await stopBuild(buildId, applicationId); - await cleanupDB(buildId); return { status: 200, body: { From 9c02af6b52a70c1515a96660d83d6bc48c0b6265 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 6 May 2022 15:41:42 +0200 Subject: [PATCH 054/118] Update github-actions.yml --- .github/workflows/github-actions.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index 665924ea7..b0b7028d6 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -1,9 +1,8 @@ name: release-coolify on: - push: - branches: - - main + release: + types: published jobs: make-it-coolifyed: From f3f4bb5105c220eb9b4745012a54d2e855d28e72 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Sat, 7 May 2022 10:41:31 +0200 Subject: [PATCH 055/118] fix: No image for Docker buildpack --- pnpm-lock.yaml | 44 +++++++++++------------ src/routes/applications/[id]/index.svelte | 36 ++++++++++--------- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10f21d2f8..657cd725a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: 5.4 +lockfileVersion: 5.3 specifiers: '@iarna/toml': 2.2.5 @@ -90,29 +90,29 @@ devDependencies: '@types/js-yaml': 4.0.5 '@types/node': 17.0.25 '@types/node-forge': 1.0.1 - '@typescript-eslint/eslint-plugin': 4.31.1_r3ph5xlwsrsg4ewthrjemd3cfq - '@typescript-eslint/parser': 4.31.1_hrkuebk64jiu2ut2d2sm4oylnu + '@typescript-eslint/eslint-plugin': 4.31.1_8ede7edd7694646e12d33c52460f622c + '@typescript-eslint/parser': 4.31.1_eslint@7.32.0+typescript@4.6.3 '@zerodevx/svelte-toast': 0.7.1 autoprefixer: 10.4.4_postcss@8.4.12 cross-env: 7.0.3 cross-var: 1.1.0 eslint: 7.32.0 eslint-config-prettier: 8.5.0_eslint@7.32.0 - eslint-plugin-svelte3: 3.4.1_4oxeyilw5mxcaksmcxtpjddhfe + eslint-plugin-svelte3: 3.4.1_eslint@7.32.0+svelte@3.47.0 husky: 7.0.4 lint-staged: 12.4.0 postcss: 8.4.12 prettier: 2.6.2 - prettier-plugin-svelte: 2.7.0_sqtt6dzjlskmywoml5ykunxlce + prettier-plugin-svelte: 2.7.0_prettier@2.6.2+svelte@3.47.0 prettier-plugin-tailwindcss: 0.1.10_prettier@2.6.2 prisma: 3.11.1 svelte: 3.47.0 - svelte-check: 2.7.0_cp6olp7pwsfaq5mjijwt65d6uy - svelte-preprocess: 4.10.6_igaqrb5onrwvsmrrc32h4m72ha + svelte-check: 2.7.0_postcss@8.4.12+svelte@3.47.0 + svelte-preprocess: 4.10.6_41810887ae6c6d59323116f47e33fa38 svelte-select: 4.4.7 sveltekit-i18n: 2.1.2_svelte@3.47.0 tailwindcss: 3.0.24_ts-node@10.7.0 - ts-node: 10.7.0_3z6inmgn4ud4moqealnfxgbl2m + ts-node: 10.7.0_de7c86b0cde507c63a0402da5b982bd3 tslib: 2.3.1 typescript: 4.6.3 @@ -573,7 +573,7 @@ packages: '@types/node': 17.0.25 dev: true - /@typescript-eslint/eslint-plugin/4.31.1_r3ph5xlwsrsg4ewthrjemd3cfq: + /@typescript-eslint/eslint-plugin/4.31.1_8ede7edd7694646e12d33c52460f622c: resolution: { integrity: sha512-UDqhWmd5i0TvPLmbK5xY3UZB0zEGseF+DHPghZ37Sb83Qd3p8ujhvAtkU4OF46Ka5Pm5kWvFIx0cCTBFKo0alA== @@ -587,8 +587,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/experimental-utils': 4.31.1_hrkuebk64jiu2ut2d2sm4oylnu - '@typescript-eslint/parser': 4.31.1_hrkuebk64jiu2ut2d2sm4oylnu + '@typescript-eslint/experimental-utils': 4.31.1_eslint@7.32.0+typescript@4.6.3 + '@typescript-eslint/parser': 4.31.1_eslint@7.32.0+typescript@4.6.3 '@typescript-eslint/scope-manager': 4.31.1 debug: 4.3.3 eslint: 7.32.0 @@ -601,7 +601,7 @@ packages: - supports-color dev: true - /@typescript-eslint/experimental-utils/4.31.1_hrkuebk64jiu2ut2d2sm4oylnu: + /@typescript-eslint/experimental-utils/4.31.1_eslint@7.32.0+typescript@4.6.3: resolution: { integrity: sha512-NtoPsqmcSsWty0mcL5nTZXMf7Ei0Xr2MT8jWjXMVgRK0/1qeQ2jZzLFUh4QtyJ4+/lPUyMw5cSfeeME+Zrtp9Q== @@ -622,7 +622,7 @@ packages: - typescript dev: true - /@typescript-eslint/parser/4.31.1_hrkuebk64jiu2ut2d2sm4oylnu: + /@typescript-eslint/parser/4.31.1_eslint@7.32.0+typescript@4.6.3: resolution: { integrity: sha512-dnVZDB6FhpIby6yVbHkwTKkn2ypjVIfAR9nh+kYsA/ZL0JlTsd22BiDjouotisY3Irmd3OW1qlk9EI5R8GrvRQ== @@ -2615,7 +2615,7 @@ packages: eslint: 7.32.0 dev: true - /eslint-plugin-svelte3/3.4.1_4oxeyilw5mxcaksmcxtpjddhfe: + /eslint-plugin-svelte3/3.4.1_eslint@7.32.0+svelte@3.47.0: resolution: { integrity: sha512-7p59WG8qV8L6wLdl4d/c3mdjkgVglQCdv5XOTk/iNPBKXuuV+Q0eFP5Wa6iJd/G2M1qR3BkLPEzaANOqKAZczw== @@ -4123,7 +4123,7 @@ packages: postcss: 8.4.12 dev: true - /postcss-load-config/3.1.4_ysmyu6g5dtd6yanj6zrab4uqoy: + /postcss-load-config/3.1.4_postcss@8.4.12+ts-node@10.7.0: resolution: { integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg== @@ -4140,7 +4140,7 @@ packages: dependencies: lilconfig: 2.0.5 postcss: 8.4.12 - ts-node: 10.7.0_3z6inmgn4ud4moqealnfxgbl2m + ts-node: 10.7.0_de7c86b0cde507c63a0402da5b982bd3 yaml: 1.10.2 dev: true @@ -4195,7 +4195,7 @@ packages: engines: { node: '>= 0.8.0' } dev: true - /prettier-plugin-svelte/2.7.0_sqtt6dzjlskmywoml5ykunxlce: + /prettier-plugin-svelte/2.7.0_prettier@2.6.2+svelte@3.47.0: resolution: { integrity: sha512-fQhhZICprZot2IqEyoiUYLTRdumULGRvw0o4dzl5jt0jfzVWdGqeYW27QTWAeXhoupEZJULmNoH3ueJwUWFLIA== @@ -4878,7 +4878,7 @@ packages: engines: { node: '>= 0.4' } dev: true - /svelte-check/2.7.0_cp6olp7pwsfaq5mjijwt65d6uy: + /svelte-check/2.7.0_postcss@8.4.12+svelte@3.47.0: resolution: { integrity: sha512-GrvG24j0+i8AOm0k0KyJ6Dqc+TAR2yzB7rtS4nljHStunVxCTr/1KYlv4EsOeoqtHLzeWMOd5D2O6nDdP/yw4A== @@ -4894,7 +4894,7 @@ packages: sade: 1.7.4 source-map: 0.7.3 svelte: 3.47.0 - svelte-preprocess: 4.10.6_igaqrb5onrwvsmrrc32h4m72ha + svelte-preprocess: 4.10.6_41810887ae6c6d59323116f47e33fa38 typescript: 4.6.3 transitivePeerDependencies: - '@babel/core' @@ -4927,7 +4927,7 @@ packages: } dev: false - /svelte-preprocess/4.10.6_igaqrb5onrwvsmrrc32h4m72ha: + /svelte-preprocess/4.10.6_41810887ae6c6d59323116f47e33fa38: resolution: { integrity: sha512-I2SV1w/AveMvgIQlUF/ZOO3PYVnhxfcpNyGt8pxpUVhPfyfL/CZBkkw/KPfuFix5FJ9TnnNYMhACK3DtSaYVVQ== @@ -5059,7 +5059,7 @@ packages: picocolors: 1.0.0 postcss: 8.4.12 postcss-js: 4.0.0_postcss@8.4.12 - postcss-load-config: 3.1.4_ysmyu6g5dtd6yanj6zrab4uqoy + postcss-load-config: 3.1.4_postcss@8.4.12+ts-node@10.7.0 postcss-nested: 5.0.6_postcss@8.4.12 postcss-selector-parser: 6.0.10 postcss-value-parser: 4.2.0 @@ -5133,7 +5133,7 @@ packages: engines: { node: '>=0.10.0' } dev: true - /ts-node/10.7.0_3z6inmgn4ud4moqealnfxgbl2m: + /ts-node/10.7.0_de7c86b0cde507c63a0402da5b982bd3: resolution: { integrity: sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A== diff --git a/src/routes/applications/[id]/index.svelte b/src/routes/applications/[id]/index.svelte index 6d8807123..ea07637bd 100644 --- a/src/routes/applications/[id]/index.svelte +++ b/src/routes/applications/[id]/index.svelte @@ -358,24 +358,26 @@ />
-
- -
- +
+
- -
+ {/if} {#if application.buildCommand || application.buildPack === 'rust' || application.buildPack === 'laravel'}