diff --git a/apps/api/src/jobs/cleanupStorage.ts b/apps/api/src/jobs/cleanupStorage.ts index 7c788c790..97683ac2d 100644 --- a/apps/api/src/jobs/cleanupStorage.ts +++ b/apps/api/src/jobs/cleanupStorage.ts @@ -1,6 +1,5 @@ import { parentPort } from 'node:worker_threads'; import { asyncExecShell, cleanupDockerStorage, executeDockerCmd, isDev, prisma, version } from '../lib/common'; -import { getEngine } from '../lib/docker'; (async () => { if (parentPort) { diff --git a/apps/api/src/jobs/deployApplication.ts b/apps/api/src/jobs/deployApplication.ts index 5936dcc91..e31ccf149 100644 --- a/apps/api/src/jobs/deployApplication.ts +++ b/apps/api/src/jobs/deployApplication.ts @@ -5,7 +5,6 @@ import yaml from 'js-yaml'; import { copyBaseConfigurationFiles, makeLabelForStandaloneApplication, saveBuildLog, setDefaultConfiguration } from '../lib/buildPacks/common'; import { createDirectories, decrypt, executeDockerCmd, getDomain, prisma } from '../lib/common'; -import Dockerode from 'dockerode'; import * as importers from '../lib/importers'; import * as buildpacks from '../lib/buildPacks'; diff --git a/apps/api/src/lib/common.ts b/apps/api/src/lib/common.ts index 2a51dbe46..91722b654 100644 --- a/apps/api/src/lib/common.ts +++ b/apps/api/src/lib/common.ts @@ -13,7 +13,7 @@ import cuid from 'cuid'; import os from 'os'; import sshConfig from 'ssh-config' -import { checkContainer, getEngine, removeContainer } from './docker'; +import { checkContainer, removeContainer } from './docker'; import { day } from './dayjs'; import * as serviceFields from './serviceFields' @@ -326,7 +326,7 @@ export async function isDomainConfigured({ dockerId: string; }): Promise { - console.log({checkOwn, dockerId}) + console.log({ checkOwn, dockerId }) const domain = getDomain(fqdn); const nakedDomain = domain.replace('www.', ''); const foundApp = await prisma.application.findFirst({ @@ -387,7 +387,7 @@ export async function getContainerUsage(dockerId: string, container: string): Pr export async function checkDomainsIsValidInDNS({ hostname, fqdn, dualCerts }): Promise { const { isIP } = await import('is-ip'); const domain = getDomain(fqdn); - console.log({hostname, fqdn, dualCerts }) + console.log({ hostname, fqdn, dualCerts }) const domainDualCert = domain.includes('www.') ? domain.replace('www.', '') : `www.${domain}`; dns.setServers(['1.1.1.1', '8.8.8.8']); let resolves = []; @@ -506,25 +506,24 @@ export async function createRemoteEngineConfiguration(id: string) { } export async function executeDockerCmd({ dockerId, command }: { dockerId: string, command: string }) { let { remoteEngine, remoteIpAddress, remoteUser, engine } = await prisma.destinationDocker.findUnique({ where: { id: dockerId } }) - if (remoteEngine) engine = `ssh://${remoteUser}@${remoteIpAddress}` - const host = getEngine(engine) - if (engine.startsWith('ssh://')) { + if (remoteEngine) { + engine = `ssh://${remoteUser}@${remoteIpAddress}` await createRemoteEngineConfiguration(dockerId) + } else { + engine = 'unix:///var/run/docker.sock' } return await asyncExecShell( - `DOCKER_BUILDKIT=1 DOCKER_HOST="${host}" ${command}` + `DOCKER_BUILDKIT=1 DOCKER_HOST="${engine}" ${command}` ); } export async function startTraefikProxy(id: string): Promise { const { engine, network, remoteEngine, remoteIpAddress } = await prisma.destinationDocker.findUnique({ where: { id } }) - const found = await checkContainer({ dockerId: id, container: 'coolify-proxy', remove: true }); const { id: settingsId, ipv4, ipv6 } = await listSettings(); if (!found) { const { stdout: Config } = await executeDockerCmd({ dockerId: id, command: `docker network inspect ${network} --format '{{json .IPAM.Config }}'` }) const ip = JSON.parse(Config)[0].Gateway; - const { publicIp } = await import('public-ip') let traefikUrl = mainTraefikEndpoint if (remoteEngine) { let ip = null @@ -619,21 +618,6 @@ export async function stopTraefikProxy( } } -export async function configureNetworkCoolifyProxy(engine: string): Promise { - const host = getEngine(engine); - const destinations = await prisma.destinationDocker.findMany({ where: { engine } }); - const { stdout: networks } = await asyncExecShell( - `DOCKER_HOST="${host}" docker ps -a --filter name=coolify-haproxy --format '{{json .Networks}}'` - ); - const configuredNetworks = networks.replace(/"/g, '').replace('\n', '').split(','); - for (const destination of destinations) { - if (!configuredNetworks.includes(destination.network)) { - await asyncExecShell( - `DOCKER_HOST="${host}" docker network connect ${destination.network} coolify-haproxy` - ); - } - } -} export async function listSettings(): Promise { const settings = await prisma.setting.findFirst({}); if (settings.proxyPassword) settings.proxyPassword = decrypt(settings.proxyPassword); @@ -1096,7 +1080,7 @@ export async function startTraefikTCPProxy( const { network, id: dockerId, remoteEngine } = destinationDocker; const container = `${id}-${publicPort}`; const found = await checkContainer({ dockerId, container, remove: true }); - const { ipv4, ipv6 } = await listSettings(); + const { ipv4, ipv6 } = await listSettings(); let dependentId = id; if (type === 'wordpressftp') dependentId = `${id}-ftp`; @@ -1526,7 +1510,6 @@ export async function stopBuild(buildId, applicationId) { await new Promise(async (resolve, reject) => { const { destinationDockerId, status } = await prisma.build.findFirst({ where: { id: buildId } }); const { engine, id: dockerId } = await prisma.destinationDocker.findFirst({ where: { id: destinationDockerId } }); - const host = getEngine(engine); let interval = setInterval(async () => { try { if (status === 'failed') { @@ -1537,10 +1520,7 @@ export async function stopBuild(buildId, applicationId) { clearInterval(interval); return reject(new Error('Build canceled')); } - - const { stdout: buildContainers } = await asyncExecShell( - `DOCKER_HOST = ${host} docker container ls--filter "label=coolify.buildId=${buildId}" --format '{{json .}}'` - ); + const { stdout: buildContainers } = await executeDockerCmd({ dockerId, command: `docker container ls--filter "label=coolify.buildId=${buildId}" --format '{{json .}}'` }) if (buildContainers) { const containersArray = buildContainers.trim().split('\n'); for (const container of containersArray) { diff --git a/apps/api/src/lib/docker.ts b/apps/api/src/lib/docker.ts index 0458ee342..f80526cd3 100644 --- a/apps/api/src/lib/docker.ts +++ b/apps/api/src/lib/docker.ts @@ -1,17 +1,4 @@ import { executeDockerCmd } from './common'; -import Dockerode from 'dockerode'; -export function getEngine(engine: string): string { - return engine === '/var/run/docker.sock' ? 'unix:///var/run/docker.sock' : engine; -} -export function dockerInstance({ destinationDocker }): { engine: Dockerode; network: string } { - return { - engine: new Dockerode({ - socketPath: destinationDocker.engine - }), - network: destinationDocker.network - }; -} - export async function checkContainer({ dockerId, container, remove = false }: { dockerId: string, container: string, remove?: boolean }): Promise { let containerFound = false; try { diff --git a/apps/api/src/routes/api/v1/applications/handlers.ts b/apps/api/src/routes/api/v1/applications/handlers.ts index 42b771601..fa9378c90 100644 --- a/apps/api/src/routes/api/v1/applications/handlers.ts +++ b/apps/api/src/routes/api/v1/applications/handlers.ts @@ -6,7 +6,7 @@ import { FastifyReply } from 'fastify'; import { day } from '../../../../lib/dayjs'; import { setDefaultBaseImage, setDefaultConfiguration } from '../../../../lib/buildPacks/common'; import { checkDomainsIsValidInDNS, checkDoubleBranch, decrypt, encrypt, errorHandler, executeDockerCmd, generateSshKeyPair, getContainerUsage, getDomain, getFreeExposedPort, isDev, isDomainConfigured, prisma, stopBuild, uniqueName } from '../../../../lib/common'; -import { checkContainer, dockerInstance, isContainerExited, removeContainer } from '../../../../lib/docker'; +import { checkContainer, isContainerExited, removeContainer } from '../../../../lib/docker'; import { scheduler } from '../../../../lib/scheduler'; import type { FastifyRequest } from 'fastify'; @@ -731,16 +731,19 @@ export async function getPreviews(request: FastifyRequest) { secret.value = decrypt(secret.value); return secret; }); + const applicationSecrets = secrets.filter((secret) => !secret.isPRMRSecret); const PRMRSecrets = secrets.filter((secret) => secret.isPRMRSecret); - const destinationDocker = await prisma.destinationDocker.findFirst({ - where: { application: { some: { id } }, teams: { some: { id: teamId } } } - }); - const docker = dockerInstance({ destinationDocker }); - const listContainers = await docker.engine.listContainers({ - filters: { network: [destinationDocker.network], name: [id] } - }); - const containers = listContainers.filter((container) => { + const application = await prisma.application.findUnique({ where: { id }, include: { destinationDocker: true } }) + const { stdout } = await executeDockerCmd({ dockerId: application.destinationDocker.id, command: `docker container ls --filter 'name=${id}-' --format "{{json .}}"` }) + if (!stdout) { + return { + containers: [], + applicationSecrets: [], + PRMRSecrets: [] + } + } + const containers = JSON.parse(stdout).filter((container) => { return ( container.Labels['coolify.configuration'] && container.Labels['coolify.type'] === 'standalone-application' diff --git a/apps/api/src/routes/api/v1/destinations/handlers.ts b/apps/api/src/routes/api/v1/destinations/handlers.ts index 047dad6f5..c46a2fdbd 100644 --- a/apps/api/src/routes/api/v1/destinations/handlers.ts +++ b/apps/api/src/routes/api/v1/destinations/handlers.ts @@ -5,7 +5,7 @@ import fs from 'fs/promises' import os from 'os'; import { asyncExecShell, decrypt, errorHandler, executeDockerCmd, listSettings, prisma, startTraefikProxy, stopTraefikProxy } from '../../../../lib/common'; -import { checkContainer, dockerInstance, getEngine } from '../../../../lib/docker'; +import { checkContainer } from '../../../../lib/docker'; import type { OnlyId } from '../../../../types'; import type { CheckDestination, ListDestinations, NewDestination, Proxy, SaveDestinationSettings } from './types'; @@ -79,19 +79,17 @@ export async function newDestination(request: FastifyRequest, re let { name, network, engine, isCoolifyProxyUsed, remoteIpAddress, remoteUser, remotePort } = request.body console.log({ name, network, engine, isCoolifyProxyUsed, remoteIpAddress, remoteUser, remotePort }) if (id === 'new') { + console.log(engine) if (engine) { - const host = getEngine(engine); - const docker = dockerInstance({ destinationDocker: { engine, network } }); - const found = await docker.engine.listNetworks({ filters: { name: [`^${network}$`] } }); - if (found.length === 0) { - await asyncExecShell(`DOCKER_HOST=${host} docker network create --attachable ${network}`); + const { stdout } = await asyncExecShell(`DOCKER_HOST=unix:///var/run/docker.sock docker network ls --filter 'name=^${network}$' --format '{{json .}}'`); + if (stdout === '') { + await asyncExecShell(`DOCKER_HOST=unix:///var/run/docker.sock docker network create --attachable ${network}`); } await prisma.destinationDocker.create({ data: { name, teams: { connect: { id: teamId } }, engine, network, isCoolifyProxyUsed } }); const destinations = await prisma.destinationDocker.findMany({ where: { engine } }); const destination = destinations.find((destination) => destination.network === network); - if (destinations.length > 0) { const proxyConfigured = destinations.find( (destination) => destination.network !== network && destination.isCoolifyProxyUsed === true @@ -102,10 +100,7 @@ export async function newDestination(request: FastifyRequest, re await prisma.destinationDocker.updateMany({ where: { engine }, data: { isCoolifyProxyUsed } }); } if (isCoolifyProxyUsed) { - const settings = await prisma.setting.findFirst(); - if (settings?.isTraefikUsed) { - await startTraefikProxy(id); - } + await startTraefikProxy(destination.id); } return reply.code(201).send({ id: destination.id }); } else { @@ -120,9 +115,8 @@ export async function newDestination(request: FastifyRequest, re } } catch ({ status, message }) { + console.log({ status, message }) return errorHandler({ status, message }) - } finally { - await fs.rm('./id_rsa') } } export async function deleteDestination(request: FastifyRequest) { @@ -218,7 +212,7 @@ export async function verifyRemoteDockerEngine(request: FastifyRequest, reply: F const homedir = os.homedir(); const { sshKey: { privateKey }, remoteIpAddress, remotePort, remoteUser, network } = await prisma.destinationDocker.findFirst({ where: { id }, include: { sshKey: true } }) - + await fs.writeFile(`/tmp/id_rsa_verification_${id}`, decrypt(privateKey) + '\n', { encoding: 'utf8', mode: 400 }) const host = `ssh://${remoteUser}@${remoteIpAddress}` diff --git a/apps/api/src/routes/api/v1/services/handlers.ts b/apps/api/src/routes/api/v1/services/handlers.ts index 1096e6681..cb2b2abb7 100644 --- a/apps/api/src/routes/api/v1/services/handlers.ts +++ b/apps/api/src/routes/api/v1/services/handlers.ts @@ -4,7 +4,7 @@ import yaml from 'js-yaml'; import bcrypt from 'bcryptjs'; import { prisma, uniqueName, asyncExecShell, getServiceImage, configureServiceType, getServiceFromDB, getContainerUsage, removeService, isDomainConfigured, saveUpdateableFields, fixType, decrypt, encrypt, getServiceMainPort, createDirectories, ComposeFile, makeLabelForServices, getFreePublicPort, getDomain, errorHandler, generatePassword, isDev, stopTcpHttpProxy, supportedServiceTypesAndVersions, executeDockerCmd, listSettings, getFreeExposedPort, checkDomainsIsValidInDNS } from '../../../../lib/common'; import { day } from '../../../../lib/dayjs'; -import { checkContainer, dockerInstance, isContainerExited, removeContainer } from '../../../../lib/docker'; +import { checkContainer, isContainerExited, removeContainer } from '../../../../lib/docker'; import cuid from 'cuid'; import type { OnlyId } from '../../../../types'; @@ -350,7 +350,7 @@ export async function checkServiceDomain(request: FastifyRequest a.name === type); if (found) { const port = found.ports.main; @@ -546,7 +541,7 @@ export async function remoteTraefikConfiguration(request: FastifyRequest) { settings: { previews, dualCerts } } = application; if (destinationDockerId) { - const { engine, network } = destinationDocker; + const { id: dockerId, network } = destinationDocker; const isRunning = true; if (fqdn) { const domain = getDomain(fqdn); @@ -567,10 +562,7 @@ export async function remoteTraefikConfiguration(request: FastifyRequest) { }); } if (previews) { - const host = getEngine(engine); - const { stdout } = await asyncExecShell( - `DOCKER_HOST=${host} docker container ls --filter="status=running" --filter="network=${network}" --filter="name=${id}-" --format="{{json .Names}}"` - ); + const { stdout } = await executeDockerCmd({ dockerId, command: `docker container ls --filter="status=running" --filter="network=${network}" --filter="name=${id}-" --format="{{json .Names}}"` }) const containers = stdout .trim() .split('\n') @@ -614,7 +606,6 @@ export async function remoteTraefikConfiguration(request: FastifyRequest) { plausibleAnalytics } = service; if (destinationDockerId) { - const { engine } = destinationDocker; const found = supportedServiceTypesAndVersions.find((a) => a.name === type); if (found) { const port = found.ports.main;