feat: working on remote docker engine

This commit is contained in:
Andras Bacsai 2022-07-20 13:35:26 +00:00
parent 9a0a145374
commit 7795c524f0
17 changed files with 510 additions and 520 deletions

View File

@ -1,24 +1,24 @@
import { parentPort } from 'node:worker_threads'; import { parentPort } from 'node:worker_threads';
import { prisma, startTraefikTCPProxy, generateDatabaseConfiguration, startTraefikProxy, asyncExecShell } from '../lib/common'; import { prisma, startTraefikTCPProxy, generateDatabaseConfiguration, startTraefikProxy, asyncExecShell, executeDockerCmd } from '../lib/common';
import { checkContainer, getEngine } from '../lib/docker'; import { checkContainer, getEngine } from '../lib/docker';
(async () => { (async () => {
if (parentPort) { if (parentPort) {
// Coolify Proxy // Coolify Proxy local
const engine = '/var/run/docker.sock'; const engine = '/var/run/docker.sock';
const localDocker = await prisma.destinationDocker.findFirst({ const localDocker = await prisma.destinationDocker.findFirst({
where: { engine, network: 'coolify' } where: { engine, network: 'coolify' }
}); });
if (localDocker && localDocker.isCoolifyProxyUsed) { if (localDocker && localDocker.isCoolifyProxyUsed) {
// Remove HAProxy // Remove HAProxy
const found = await checkContainer(engine, 'coolify-haproxy'); const found = await checkContainer({ dockerId: localDocker.id, container: 'coolify-haproxy' });
const host = getEngine(engine);
if (found) { if (found) {
await asyncExecShell( await executeDockerCmd({
`DOCKER_HOST="${host}" docker stop -t 0 coolify-haproxy && docker rm coolify-haproxy` dockerId: localDocker.id,
); command: `docker stop -t 0 coolify-haproxy && docker rm coolify-haproxy`
})
} }
await startTraefikProxy(engine); await startTraefikProxy(localDocker.id);
} }
@ -32,12 +32,14 @@ import { checkContainer, getEngine } from '../lib/docker';
if (destinationDockerId && destinationDocker.isCoolifyProxyUsed) { if (destinationDockerId && destinationDocker.isCoolifyProxyUsed) {
const { privatePort } = generateDatabaseConfiguration(database); const { privatePort } = generateDatabaseConfiguration(database);
// Remove HAProxy // Remove HAProxy
const found = await checkContainer(engine, `haproxy-for-${publicPort}`); const found = await checkContainer({
const host = getEngine(engine); dockerId: localDocker.id, container: `haproxy-for-${publicPort}`
});
if (found) { if (found) {
await asyncExecShell( await executeDockerCmd({
`DOCKER_HOST="${host}" docker stop -t 0 haproxy-for-${publicPort} && docker rm haproxy-for-${publicPort}` dockerId: localDocker.id,
); command: `docker stop -t 0 haproxy-for-${publicPort} && docker rm haproxy-for-${publicPort}`
})
} }
await startTraefikTCPProxy(destinationDocker, id, publicPort, privatePort); await startTraefikTCPProxy(destinationDocker, id, publicPort, privatePort);
@ -52,12 +54,12 @@ import { checkContainer, getEngine } from '../lib/docker';
const { destinationDockerId, destinationDocker, id } = service; const { destinationDockerId, destinationDocker, id } = service;
if (destinationDockerId && destinationDocker.isCoolifyProxyUsed) { if (destinationDockerId && destinationDocker.isCoolifyProxyUsed) {
// Remove HAProxy // Remove HAProxy
const found = await checkContainer(engine, `haproxy-for-${ftpPublicPort}`); const found = await checkContainer({ dockerId: localDocker.id, container: `haproxy-for-${ftpPublicPort}` });
const host = getEngine(engine);
if (found) { if (found) {
await asyncExecShell( await executeDockerCmd({
`DOCKER_HOST="${host}" docker stop -t 0 haproxy-for-${ftpPublicPort} && docker rm haproxy-for-${ftpPublicPort} ` dockerId: localDocker.id,
); command: `docker stop -t 0 haproxy -for-${ftpPublicPort} && docker rm haproxy-for-${ftpPublicPort}`
})
} }
await startTraefikTCPProxy(destinationDocker, id, ftpPublicPort, 22, 'wordpressftp'); await startTraefikTCPProxy(destinationDocker, id, ftpPublicPort, 22, 'wordpressftp');
} }
@ -73,12 +75,12 @@ import { checkContainer, getEngine } from '../lib/docker';
const { destinationDockerId, destinationDocker, id } = service; const { destinationDockerId, destinationDocker, id } = service;
if (destinationDockerId && destinationDocker.isCoolifyProxyUsed) { if (destinationDockerId && destinationDocker.isCoolifyProxyUsed) {
// Remove HAProxy // Remove HAProxy
const found = await checkContainer(engine, `${id}-${publicPort}`); const found = await checkContainer({ dockerId: localDocker.id, container: `${id}-${publicPort}` });
const host = getEngine(engine);
if (found) { if (found) {
await asyncExecShell( await executeDockerCmd({
`DOCKER_HOST="${host}" docker stop -t 0 ${id}-${publicPort} && docker rm ${id}-${publicPort}` dockerId: localDocker.id,
); command: `docker stop -t 0 ${id}-${publicPort} && docker rm ${id}-${publicPort} `
})
} }
await startTraefikTCPProxy(destinationDocker, id, publicPort, 9000); await startTraefikTCPProxy(destinationDocker, id, publicPort, 9000);
} }

View File

@ -4,7 +4,7 @@ import fs from 'fs/promises';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
import { copyBaseConfigurationFiles, makeLabelForStandaloneApplication, saveBuildLog, setDefaultConfiguration } from '../lib/buildPacks/common'; import { copyBaseConfigurationFiles, makeLabelForStandaloneApplication, saveBuildLog, setDefaultConfiguration } from '../lib/buildPacks/common';
import { asyncExecShell, createDirectories, decrypt, getDomain, prisma } from '../lib/common'; import { createDirectories, decrypt, executeDockerCmd, getDomain, prisma } from '../lib/common';
import { dockerInstance, getEngine } from '../lib/docker'; import { dockerInstance, getEngine } from '../lib/docker';
import * as importers from '../lib/importers'; import * as importers from '../lib/importers';
import * as buildpacks from '../lib/buildPacks'; import * as buildpacks from '../lib/buildPacks';
@ -238,8 +238,8 @@ import * as buildpacks from '../lib/buildPacks';
await saveBuildLog({ line: 'Build image already available - no rebuild required.', buildId, applicationId }); await saveBuildLog({ line: 'Build image already available - no rebuild required.', buildId, applicationId });
} }
try { try {
await asyncExecShell(`DOCKER_HOST=${host} docker stop -t 0 ${imageId}`); await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker stop -t 0 ${imageId}` })
await asyncExecShell(`DOCKER_HOST=${host} docker rm ${imageId}`); await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker rm ${imageId}` })
} catch (error) { } catch (error) {
// //
} }
@ -325,9 +325,7 @@ import * as buildpacks from '../lib/buildPacks';
volumes: Object.assign({}, ...composeVolumes) volumes: Object.assign({}, ...composeVolumes)
}; };
await fs.writeFile(`${workdir}/docker-compose.yml`, yaml.dump(composeFile)); await fs.writeFile(`${workdir}/docker-compose.yml`, yaml.dump(composeFile));
await asyncExecShell( await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose --project-directory ${workdir} up -d` })
`DOCKER_HOST=${host} docker compose --project-directory ${workdir} up -d`
);
await saveBuildLog({ line: 'Deployment successful!', buildId, applicationId }); await saveBuildLog({ line: 'Deployment successful!', buildId, applicationId });
} catch (error) { } catch (error) {
await saveBuildLog({ line: error, buildId, applicationId }); await saveBuildLog({ line: error, buildId, applicationId });

View File

@ -10,6 +10,8 @@ import crypto from 'crypto';
import { promises as dns } from 'dns'; import { promises as dns } from 'dns';
import { PrismaClient } from '@prisma/client'; import { PrismaClient } from '@prisma/client';
import cuid from 'cuid'; import cuid from 'cuid';
import os from 'os';
import sshConfig from 'ssh-config'
import { checkContainer, getEngine, removeContainer } from './docker'; import { checkContainer, getEngine, removeContainer } from './docker';
import { day } from './dayjs'; import { day } from './dayjs';
@ -113,164 +115,164 @@ export const encrypt = (text: string) => {
}; };
export const supportedServiceTypesAndVersions = [ export const supportedServiceTypesAndVersions = [
{ {
name: 'plausibleanalytics', name: 'plausibleanalytics',
fancyName: 'Plausible Analytics', fancyName: 'Plausible Analytics',
baseImage: 'plausible/analytics', baseImage: 'plausible/analytics',
images: ['bitnami/postgresql:13.2.0', 'yandex/clickhouse-server:21.3.2.5'], images: ['bitnami/postgresql:13.2.0', 'yandex/clickhouse-server:21.3.2.5'],
versions: ['latest', 'stable'], versions: ['latest', 'stable'],
recommendedVersion: 'stable', recommendedVersion: 'stable',
ports: { ports: {
main: 8000 main: 8000
} }
}, },
{ {
name: 'nocodb', name: 'nocodb',
fancyName: 'NocoDB', fancyName: 'NocoDB',
baseImage: 'nocodb/nocodb', baseImage: 'nocodb/nocodb',
versions: ['latest'], versions: ['latest'],
recommendedVersion: 'latest', recommendedVersion: 'latest',
ports: { ports: {
main: 8080 main: 8080
} }
}, },
{ {
name: 'minio', name: 'minio',
fancyName: 'MinIO', fancyName: 'MinIO',
baseImage: 'minio/minio', baseImage: 'minio/minio',
versions: ['latest'], versions: ['latest'],
recommendedVersion: 'latest', recommendedVersion: 'latest',
ports: { ports: {
main: 9001 main: 9001
} }
}, },
{ {
name: 'vscodeserver', name: 'vscodeserver',
fancyName: 'VSCode Server', fancyName: 'VSCode Server',
baseImage: 'codercom/code-server', baseImage: 'codercom/code-server',
versions: ['latest'], versions: ['latest'],
recommendedVersion: 'latest', recommendedVersion: 'latest',
ports: { ports: {
main: 8080 main: 8080
} }
}, },
{ {
name: 'wordpress', name: 'wordpress',
fancyName: 'Wordpress', fancyName: 'Wordpress',
baseImage: 'wordpress', baseImage: 'wordpress',
images: ['bitnami/mysql:5.7'], images: ['bitnami/mysql:5.7'],
versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'], versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'],
recommendedVersion: 'latest', recommendedVersion: 'latest',
ports: { ports: {
main: 80 main: 80
} }
}, },
{ {
name: 'vaultwarden', name: 'vaultwarden',
fancyName: 'Vaultwarden', fancyName: 'Vaultwarden',
baseImage: 'vaultwarden/server', baseImage: 'vaultwarden/server',
versions: ['latest'], versions: ['latest'],
recommendedVersion: 'latest', recommendedVersion: 'latest',
ports: { ports: {
main: 80 main: 80
} }
}, },
{ {
name: 'languagetool', name: 'languagetool',
fancyName: 'LanguageTool', fancyName: 'LanguageTool',
baseImage: 'silviof/docker-languagetool', baseImage: 'silviof/docker-languagetool',
versions: ['latest'], versions: ['latest'],
recommendedVersion: 'latest', recommendedVersion: 'latest',
ports: { ports: {
main: 8010 main: 8010
} }
}, },
{ {
name: 'n8n', name: 'n8n',
fancyName: 'n8n', fancyName: 'n8n',
baseImage: 'n8nio/n8n', baseImage: 'n8nio/n8n',
versions: ['latest'], versions: ['latest'],
recommendedVersion: 'latest', recommendedVersion: 'latest',
ports: { ports: {
main: 5678 main: 5678
} }
}, },
{ {
name: 'uptimekuma', name: 'uptimekuma',
fancyName: 'Uptime Kuma', fancyName: 'Uptime Kuma',
baseImage: 'louislam/uptime-kuma', baseImage: 'louislam/uptime-kuma',
versions: ['latest'], versions: ['latest'],
recommendedVersion: 'latest', recommendedVersion: 'latest',
ports: { ports: {
main: 3001 main: 3001
} }
}, },
{ {
name: 'ghost', name: 'ghost',
fancyName: 'Ghost', fancyName: 'Ghost',
baseImage: 'bitnami/ghost', baseImage: 'bitnami/ghost',
images: ['bitnami/mariadb'], images: ['bitnami/mariadb'],
versions: ['latest'], versions: ['latest'],
recommendedVersion: 'latest', recommendedVersion: 'latest',
ports: { ports: {
main: 2368 main: 2368
} }
}, },
{ {
name: 'meilisearch', name: 'meilisearch',
fancyName: 'Meilisearch', fancyName: 'Meilisearch',
baseImage: 'getmeili/meilisearch', baseImage: 'getmeili/meilisearch',
images: [], images: [],
versions: ['latest'], versions: ['latest'],
recommendedVersion: 'latest', recommendedVersion: 'latest',
ports: { ports: {
main: 7700 main: 7700
} }
}, },
{ {
name: 'umami', name: 'umami',
fancyName: 'Umami', fancyName: 'Umami',
baseImage: 'ghcr.io/mikecao/umami', baseImage: 'ghcr.io/mikecao/umami',
images: ['postgres:12-alpine'], images: ['postgres:12-alpine'],
versions: ['postgresql-latest'], versions: ['postgresql-latest'],
recommendedVersion: 'postgresql-latest', recommendedVersion: 'postgresql-latest',
ports: { ports: {
main: 3000 main: 3000
} }
}, },
{ {
name: 'hasura', name: 'hasura',
fancyName: 'Hasura', fancyName: 'Hasura',
baseImage: 'hasura/graphql-engine', baseImage: 'hasura/graphql-engine',
images: ['postgres:12-alpine'], images: ['postgres:12-alpine'],
versions: ['latest', 'v2.5.1'], versions: ['latest', 'v2.5.1'],
recommendedVersion: 'v2.5.1', recommendedVersion: 'v2.5.1',
ports: { ports: {
main: 8080 main: 8080
} }
}, },
{ {
name: 'fider', name: 'fider',
fancyName: 'Fider', fancyName: 'Fider',
baseImage: 'getfider/fider', baseImage: 'getfider/fider',
images: ['postgres:12-alpine'], images: ['postgres:12-alpine'],
versions: ['stable'], versions: ['stable'],
recommendedVersion: 'stable', recommendedVersion: 'stable',
ports: { ports: {
main: 3000 main: 3000
} }
}, },
// { // {
// name: 'moodle', // name: 'moodle',
// fancyName: 'Moodle', // fancyName: 'Moodle',
// baseImage: 'bitnami/moodle', // baseImage: 'bitnami/moodle',
// images: [], // images: [],
// versions: ['latest', 'v4.0.2'], // versions: ['latest', 'v4.0.2'],
// recommendedVersion: 'latest', // recommendedVersion: 'latest',
// ports: { // ports: {
// main: 8080 // main: 8080
// } // }
// } // }
]; ];
export async function checkDoubleBranch(branch: string, projectId: number): Promise<boolean> { export async function checkDoubleBranch(branch: string, projectId: number): Promise<boolean> {
@ -359,12 +361,9 @@ export async function isDomainConfigured({
return !!(foundApp || foundService || coolifyFqdn); return !!(foundApp || foundService || coolifyFqdn);
} }
export async function getContainerUsage(engine: string, container: string): Promise<any> { export async function getContainerUsage(dockerId: string, container: string): Promise<any> {
const host = getEngine(engine);
try { try {
const { stdout } = await asyncExecShell( const { stdout } = await executeDockerCmd({ dockerId, command: `docker container stats ${container} --no-stream --no-trunc --format "{{json .}}"` })
`DOCKER_HOST="${host}" docker container stats ${container} --no-stream --no-trunc --format "{{json .}}"`
);
return JSON.parse(stdout); return JSON.parse(stdout);
} catch (err) { } catch (err) {
return { return {
@ -469,20 +468,55 @@ export const supportedDatabaseTypesAndVersions = [
}, },
{ name: 'couchdb', fancyName: 'CouchDB', baseImage: 'bitnami/couchdb', versions: ['3.2.1'] } { name: 'couchdb', fancyName: 'CouchDB', baseImage: 'bitnami/couchdb', versions: ['3.2.1'] }
]; ];
export async function createRemoteEngineConfiguration(id: string) {
export async function startTraefikProxy(engine: string): Promise<void> { const homedir = os.homedir();
const host = getEngine(engine); const sshKeyFile = `/tmp/id_rsa-${id}`
const found = await checkContainer(engine, 'coolify-proxy', true); const { sshKey: { privateKey }, remoteIpAddress, remotePort, remoteUser } = await prisma.destinationDocker.findFirst({ where: { id }, include: { sshKey: true } })
const { proxyPassword, proxyUser, id } = await listSettings(); await fs.writeFile(sshKeyFile, decrypt(privateKey) + '\n', { encoding: 'utf8', mode: 400 })
const config = sshConfig.parse('')
const found = config.find({ Host: remoteIpAddress })
if (!found) { if (!found) {
const { stdout: Config } = await asyncExecShell( config.append({
`DOCKER_HOST="${host}" docker network inspect bridge --format '{{json .IPAM.Config }}'` Host: remoteIpAddress,
); Port: remotePort.toString(),
User: remoteUser,
IdentityFile: sshKeyFile,
StrictHostKeyChecking: 'no'
})
}
try {
await fs.stat(`${homedir}/.ssh/`)
} catch (error) {
await fs.mkdir(`${homedir}/.ssh/`)
}
return await fs.writeFile(`${homedir}/.ssh/config`, sshConfig.stringify(config))
}
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://')) {
await createRemoteEngineConfiguration(dockerId)
}
return await asyncExecShell(
`DOCKER_HOST="${host}" ${command}`
);
}
export async function startTraefikProxy(id: string): Promise<void> {
const { engine, network, remoteEngine } = await prisma.destinationDocker.findUnique({ where: { id } })
const found = await checkContainer({ dockerId: id, container: 'coolify-proxy', remove: true });
const { id: settingsId } = 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 ip = JSON.parse(Config)[0].Gateway;
await asyncExecShell( await executeDockerCmd({
`DOCKER_HOST="${host}" docker run --restart always \ dockerId: id,
command: `docker run --restart always \
--add-host 'host.docker.internal:host-gateway' \ --add-host 'host.docker.internal:host-gateway' \
--add-host 'host.docker.internal:${ip}' \ ${ip ? `--add-host 'host.docker.internal:${ip}'` : ''} \
-v coolify-traefik-letsencrypt:/etc/traefik/acme \ -v coolify-traefik-letsencrypt:/etc/traefik/acme \
-v /var/run/docker.sock:/var/run/docker.sock \ -v /var/run/docker.sock:/var/run/docker.sock \
--network coolify-infra \ --network coolify-infra \
@ -502,75 +536,56 @@ export async function startTraefikProxy(engine: string): Promise<void> {
--certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/acme.json \ --certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/acme.json \
--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web \ --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web \
--log.level=error` --log.level=error`
); })
await prisma.setting.update({ where: { id }, data: { proxyHash: null } }); await prisma.setting.update({ where: { id: settingsId }, data: { proxyHash: null } });
await prisma.destinationDocker.updateMany({ await prisma.destinationDocker.update({
where: { engine }, where: { id },
data: { isCoolifyProxyUsed: true } data: { isCoolifyProxyUsed: true }
}); });
} }
await configureNetworkTraefikProxy(engine); if (!remoteEngine) await configureNetworkTraefikProxy(engine);
} }
export async function configureNetworkTraefikProxy(engine: string): Promise<void> { export async function configureNetworkTraefikProxy(engine: string): Promise<void> {
const host = getEngine(engine);
const destinations = await prisma.destinationDocker.findMany({ where: { engine } }); const destinations = await prisma.destinationDocker.findMany({ where: { engine } });
const { stdout: networks } = await asyncExecShell(
`DOCKER_HOST="${host}" docker ps -a --filter name=coolify-proxy --format '{{json .Networks}}'` const { stdout: networks } = await executeDockerCmd({
); dockerId: '',
command:
`docker ps -a --filter name=coolify-proxy --format '{{json .Networks}}'`
});
const configuredNetworks = networks.replace(/"/g, '').replace('\n', '').split(','); const configuredNetworks = networks.replace(/"/g, '').replace('\n', '').split(',');
for (const destination of destinations) { for (const destination of destinations) {
if (!configuredNetworks.includes(destination.network)) { if (!configuredNetworks.includes(destination.network)) {
await asyncExecShell( await executeDockerCmd({ dockerId: destination.id, command: `docker network connect ${destination.network} coolify-proxy` })
`DOCKER_HOST="${host}" docker network connect ${destination.network} coolify-proxy`
);
} }
} }
} }
export async function stopTraefikProxy( export async function stopTraefikProxy(
engine: string id: string
): Promise<{ stdout: string; stderr: string } | Error> { ): Promise<{ stdout: string; stderr: string } | Error> {
const host = getEngine(engine); const found = await checkContainer({ dockerId: id, container: 'coolify-proxy' });
const found = await checkContainer(engine, 'coolify-proxy'); await prisma.destinationDocker.update({
await prisma.destinationDocker.updateMany({ where: { id },
where: { engine },
data: { isCoolifyProxyUsed: false } data: { isCoolifyProxyUsed: false }
}); });
const { id } = await prisma.setting.findFirst({}); const { id: settingsId } = await prisma.setting.findFirst({});
await prisma.setting.update({ where: { id }, data: { proxyHash: null } }); await prisma.setting.update({ where: { id: settingsId }, data: { proxyHash: null } });
try { try {
if (found) { if (found) {
await asyncExecShell( await executeDockerCmd({
`DOCKER_HOST="${host}" docker stop -t 0 coolify-proxy && docker rm coolify-proxy` dockerId: id,
); command:
`docker stop -t 0 coolify-proxy && docker rm coolify-proxy`
});
} }
} catch (error) { } catch (error) {
return error; return error;
} }
} }
export async function startCoolifyProxy(engine: string): Promise<void> {
const host = getEngine(engine);
const found = await checkContainer(engine, 'coolify-haproxy', true);
const { proxyPassword, proxyUser, id } = await listSettings();
if (!found) {
const { stdout: Config } = await asyncExecShell(
`DOCKER_HOST="${host}" docker network inspect bridge --format '{{json .IPAM.Config }}'`
);
const ip = JSON.parse(Config)[0].Gateway;
await asyncExecShell(
`DOCKER_HOST="${host}" docker run -e HAPROXY_USERNAME=${proxyUser} -e HAPROXY_PASSWORD=${proxyPassword} --restart always --add-host 'host.docker.internal:host-gateway' --add-host 'host.docker.internal:${ip}' -v coolify-ssl-certs:/usr/local/etc/haproxy/ssl --network coolify-infra -p "80:80" -p "443:443" -p "8404:8404" -p "5555:5555" -p "5000:5000" --name coolify-haproxy -d coollabsio/${defaultProxyImage}`
);
await prisma.setting.update({ where: { id }, data: { proxyHash: null } });
await prisma.destinationDocker.updateMany({
where: { engine },
data: { isCoolifyProxyUsed: true }
});
}
await configureNetworkCoolifyProxy(engine);
}
export async function configureNetworkCoolifyProxy(engine: string): Promise<void> { export async function configureNetworkCoolifyProxy(engine: string): Promise<void> {
const host = getEngine(engine); const host = getEngine(engine);
const destinations = await prisma.destinationDocker.findMany({ where: { engine } }); const destinations = await prisma.destinationDocker.findMany({ where: { engine } });
@ -593,29 +608,6 @@ export async function listSettings(): Promise<any> {
} }
// export async function stopCoolifyProxy(
// engine: string
// ): Promise<{ stdout: string; stderr: string } | Error> {
// const host = getEngine(engine);
// const found = await checkContainer(engine, 'coolify-haproxy');
// await prisma.destinationDocker.updateMany({
// where: { engine },
// data: { isCoolifyProxyUsed: false }
// });
// const { id } = await prisma.setting.findFirst({});
// await prisma.setting.update({ where: { id }, data: { proxyHash: null } });
// try {
// if (found) {
// await asyncExecShell(
// `DOCKER_HOST="${host}" docker stop -t 0 coolify-haproxy && docker rm coolify-haproxy`
// );
// }
// } catch (error) {
// return error;
// }
// }
export function generatePassword(length = 24, symbols = false): string { export function generatePassword(length = 24, symbols = false): string {
return generator.generate({ return generator.generate({
length, length,
@ -900,38 +892,6 @@ export const createDirectories = async ({
}; };
}; };
export async function startTcpProxy(
destinationDocker: any,
id: string,
publicPort: number,
privatePort: number
): Promise<{ stdout: string; stderr: string } | Error> {
const { network, engine } = destinationDocker;
const host = getEngine(engine);
const containerName = `haproxy-for-${publicPort}`;
const found = await checkContainer(engine, containerName, true);
const foundDependentContainer = await checkContainer(engine, id, true);
try {
if (foundDependentContainer && !found) {
const { stdout: Config } = await asyncExecShell(
`DOCKER_HOST="${host}" docker network inspect bridge --format '{{json .IPAM.Config }}'`
);
const ip = JSON.parse(Config)[0].Gateway;
return await asyncExecShell(
`DOCKER_HOST=${host} docker run --restart always -e PORT=${publicPort} -e APP=${id} -e PRIVATE_PORT=${privatePort} --add-host 'host.docker.internal:host-gateway' --add-host 'host.docker.internal:${ip}' --network ${network} -p ${publicPort}:${publicPort} --name ${containerName} -d coollabsio/${defaultProxyImageTcp}`
);
}
if (!foundDependentContainer && found) {
return await asyncExecShell(
`DOCKER_HOST=${host} docker stop -t 0 ${containerName} && docker rm ${containerName}`
);
}
} catch (error) {
return error;
}
}
export async function stopDatabaseContainer( export async function stopDatabaseContainer(
database: any database: any
@ -940,17 +900,15 @@ export async function stopDatabaseContainer(
const { const {
id, id,
destinationDockerId, destinationDockerId,
destinationDocker: { engine } destinationDocker: { engine, id: dockerId }
} = database; } = database;
if (destinationDockerId) { if (destinationDockerId) {
try { try {
const host = getEngine(engine); const { stdout } = await executeDockerCmd({ dockerId, command: `docker inspect --format '{{json .State}}' ${id}` })
const { stdout } = await asyncExecShell(
`DOCKER_HOST=${host} docker inspect --format '{{json .State}}' ${id}`
);
if (stdout) { if (stdout) {
everStarted = true; everStarted = true;
await removeContainer({ id, engine }); await removeContainer({ id, dockerId });
} }
} catch (error) { } catch (error) {
// //
@ -966,21 +924,18 @@ export async function stopTcpHttpProxy(
publicPort: number, publicPort: number,
forceName: string = null forceName: string = null
): Promise<{ stdout: string; stderr: string } | Error> { ): Promise<{ stdout: string; stderr: string } | Error> {
const { engine } = destinationDocker; const { id: dockerId } = destinationDocker;
const host = getEngine(engine); let container = `${id}-${publicPort}`;
const settings = await listSettings(); if (forceName) container = forceName;
let containerName = `${id}-${publicPort}`; const found = await checkContainer({ dockerId, container });
if (!settings.isTraefikUsed) {
containerName = `haproxy-for-${publicPort}`;
}
if (forceName) containerName = forceName;
const found = await checkContainer(engine, containerName);
try { try {
if (found) { if (found) {
return await asyncExecShell( return await executeDockerCmd({
`DOCKER_HOST=${host} docker stop -t 0 ${containerName} && docker rm ${containerName}` dockerId,
); command:
`docker stop -t 0 ${container} && docker rm ${container}`
});
} }
} catch (error) { } catch (error) {
return error; return error;
@ -1073,34 +1028,35 @@ export async function startTraefikTCPProxy(
privatePort: number, privatePort: number,
type?: string type?: string
): Promise<{ stdout: string; stderr: string } | Error> { ): Promise<{ stdout: string; stderr: string } | Error> {
const { network, engine } = destinationDocker; const { network, id: dockerId } = destinationDocker;
const host = getEngine(engine); const container = `${id}-${publicPort}`;
const containerName = `${id}-${publicPort}`; const found = await checkContainer({ dockerId, container, remove: true });
const found = await checkContainer(engine, containerName, true);
let dependentId = id; let dependentId = id;
if (type === 'wordpressftp') dependentId = `${id}-ftp`; if (type === 'wordpressftp') dependentId = `${id}-ftp`;
const foundDependentContainer = await checkContainer(engine, dependentId, true); const foundDependentContainer = await checkContainer({ dockerId, container: dependentId, remove: true });
try { try {
if (foundDependentContainer && !found) { if (foundDependentContainer && !found) {
const { stdout: Config } = await asyncExecShell( const { stdout: Config } = await executeDockerCmd({
`DOCKER_HOST="${host}" docker network inspect bridge --format '{{json .IPAM.Config }}'` dockerId,
); command: `docker network inspect ${network} --format '{{json .IPAM.Config }}'`
})
const ip = JSON.parse(Config)[0].Gateway; const ip = JSON.parse(Config)[0].Gateway;
const tcpProxy = { const tcpProxy = {
version: '3.5', version: '3.5',
services: { services: {
[`${id}-${publicPort}`]: { [`${id}-${publicPort}`]: {
container_name: containerName, container_name: container,
image: 'traefik:v2.6', image: 'traefik:v2.6',
command: [ command: [
`--entrypoints.tcp.address=:${publicPort}`, `--entrypoints.tcp.address =: ${publicPort}`,
`--entryPoints.tcp.forwardedHeaders.insecure=true`, `--entryPoints.tcp.forwardedHeaders.insecure = true`,
`--providers.http.endpoint=${otherTraefikEndpoint}?id=${id}&privatePort=${privatePort}&publicPort=${publicPort}&type=tcp&address=${dependentId}`, `--providers.http.endpoint = ${otherTraefikEndpoint} ? id = ${id} & privatePort=${privatePort} & publicPort=${publicPort} & type=tcp & address=${dependentId}`,
'--providers.http.pollTimeout=2s', '--providers.http.pollTimeout=2s',
'--log.level=error' '--log.level=error'
], ],
ports: [`${publicPort}:${publicPort}`], ports: [`${publicPort}: ${publicPort}`],
extra_hosts: ['host.docker.internal:host-gateway', `host.docker.internal:${ip}`], extra_hosts: ['host.docker.internal:host-gateway', `host.docker.internal: ${ip}`],
volumes: ['/var/run/docker.sock:/var/run/docker.sock'], volumes: ['/var/run/docker.sock:/var/run/docker.sock'],
networks: ['coolify-infra', network] networks: ['coolify-infra', network]
} }
@ -1117,15 +1073,17 @@ export async function startTraefikTCPProxy(
} }
}; };
await fs.writeFile(`/tmp/docker-compose-${id}.yaml`, yaml.dump(tcpProxy)); await fs.writeFile(`/tmp/docker-compose-${id}.yaml`, yaml.dump(tcpProxy));
await asyncExecShell( await executeDockerCmd({
`DOCKER_HOST=${host} docker compose -f /tmp/docker-compose-${id}.yaml up -d` dockerId,
); command: `docker compose -f /tmp/docker-compose-${id}.yaml up -d`
})
await fs.rm(`/tmp/docker-compose-${id}.yaml`); await fs.rm(`/tmp/docker-compose-${id}.yaml`);
} }
if (!foundDependentContainer && found) { if (!foundDependentContainer && found) {
return await asyncExecShell( await executeDockerCmd({
`DOCKER_HOST=${host} docker stop -t 0 ${containerName} && docker rm ${containerName}` dockerId,
); command: `docker stop -t 0 ${container} && docker rm ${container}`
})
} }
} catch (error) { } catch (error) {
console.log(error); console.log(error);
@ -1350,7 +1308,7 @@ export async function configureServiceType({
} else if (type === 'moodle') { } else if (type === 'moodle') {
const defaultUsername = cuid(); const defaultUsername = cuid();
const defaultPassword = encrypt(generatePassword()); const defaultPassword = encrypt(generatePassword());
const defaultEmail = `${cuid()}@example.com`; const defaultEmail = `${cuid()} @example.com`;
const mariadbUser = cuid(); const mariadbUser = cuid();
const mariadbPassword = encrypt(generatePassword()); const mariadbPassword = encrypt(generatePassword());
const mariadbDatabase = 'moodle_db'; const mariadbDatabase = 'moodle_db';
@ -1461,9 +1419,9 @@ export const getServiceMainPort = (service: string) => {
export function makeLabelForServices(type) { export function makeLabelForServices(type) {
return [ return [
'coolify.managed=true', 'coolify.managed=true',
`coolify.version=${version}`, `coolify.version = ${version} `,
`coolify.type=service`, `coolify.type = service`,
`coolify.service.type=${type}` `coolify.service.type = ${type} `
]; ];
} }
export function errorHandler({ status = 500, message = 'Unknown error.' }: { status: number, message: string | any }) { export function errorHandler({ status = 500, message = 'Unknown error.' }: { status: number, message: string | any }) {
@ -1489,7 +1447,7 @@ export async function stopBuild(buildId, applicationId) {
let count = 0; let count = 0;
await new Promise<void>(async (resolve, reject) => { await new Promise<void>(async (resolve, reject) => {
const { destinationDockerId, status } = await prisma.build.findFirst({ where: { id: buildId } }); const { destinationDockerId, status } = await prisma.build.findFirst({ where: { id: buildId } });
const { engine } = await prisma.destinationDocker.findFirst({ where: { id: destinationDockerId } }); const { engine, id: dockerId } = await prisma.destinationDocker.findFirst({ where: { id: destinationDockerId } });
const host = getEngine(engine); const host = getEngine(engine);
let interval = setInterval(async () => { let interval = setInterval(async () => {
try { try {
@ -1503,15 +1461,15 @@ export async function stopBuild(buildId, applicationId) {
} }
const { stdout: buildContainers } = await asyncExecShell( const { stdout: buildContainers } = await asyncExecShell(
`DOCKER_HOST=${host} docker container ls --filter "label=coolify.buildId=${buildId}" --format '{{json .}}'` `DOCKER_HOST = ${host} docker container ls--filter "label=coolify.buildId=${buildId}" --format '{{json .}}'`
); );
if (buildContainers) { if (buildContainers) {
const containersArray = buildContainers.trim().split('\n'); const containersArray = buildContainers.trim().split('\n');
for (const container of containersArray) { for (const container of containersArray) {
const containerObj = JSON.parse(container); const containerObj = JSON.parse(container);
const id = containerObj.ID; const id = containerObj.ID;
if (!containerObj.Names.startsWith(`${applicationId}`)) { if (!containerObj.Names.startsWith(`${applicationId} `)) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId });
await cleanupDB(buildId); await cleanupDB(buildId);
clearInterval(interval); clearInterval(interval);
return resolve(); return resolve();

View File

@ -1,4 +1,4 @@
import { asyncExecShell } from './common'; import { asyncExecShell, executeDockerCmd } from './common';
import Dockerode from 'dockerode'; import Dockerode from 'dockerode';
export function getEngine(engine: string): string { export function getEngine(engine: string): string {
return engine === '/var/run/docker.sock' ? 'unix:///var/run/docker.sock' : engine; return engine === '/var/run/docker.sock' ? 'unix:///var/run/docker.sock' : engine;
@ -12,22 +12,31 @@ export function dockerInstance({ destinationDocker }): { engine: Dockerode; netw
}; };
} }
export async function checkContainer(engine: string, container: string, remove = false): Promise<boolean> { export async function checkContainer({ dockerId, container, remove = false }: { dockerId: string, container: string, remove?: boolean }): Promise<boolean> {
const host = getEngine(engine);
let containerFound = false; let containerFound = false;
try { try {
const { stdout } = await asyncExecShell( const { stdout } = await executeDockerCmd({
`DOCKER_HOST="${host}" docker inspect --format '{{json .State}}' ${container}` dockerId,
); command:
`docker inspect --format '{{json .State}}' ${container}`
});
const parsedStdout = JSON.parse(stdout); const parsedStdout = JSON.parse(stdout);
const status = parsedStdout.Status; const status = parsedStdout.Status;
const isRunning = status === 'running'; const isRunning = status === 'running';
if (status === 'created') { if (status === 'created') {
await asyncExecShell(`DOCKER_HOST="${host}" docker rm ${container}`); await executeDockerCmd({
dockerId,
command:
`docker rm ${container}`
});
} }
if (remove && status === 'exited') { if (remove && status === 'exited') {
await asyncExecShell(`DOCKER_HOST="${host}" docker rm ${container}`); await executeDockerCmd({
dockerId,
command:
`docker rm ${container}`
});
} }
if (isRunning) { if (isRunning) {
containerFound = true; containerFound = true;
@ -57,19 +66,17 @@ export async function isContainerExited(engine: string, containerName: string):
export async function removeContainer({ export async function removeContainer({
id, id,
engine dockerId
}: { }: {
id: string; id: string;
engine: string; dockerId: string;
}): Promise<void> { }): Promise<void> {
const host = getEngine(engine);
try { try {
const { stdout } = await asyncExecShell( const { stdout } =await executeDockerCmd({ dockerId, command: `docker inspect --format '{{json .State}}' ${id}`})
`DOCKER_HOST=${host} docker inspect --format '{{json .State}}' ${id}`
);
if (JSON.parse(stdout).Running) { if (JSON.parse(stdout).Running) {
await asyncExecShell(`DOCKER_HOST=${host} docker stop -t 0 ${id}`); await executeDockerCmd({ dockerId, command: `docker stop -t 0 ${id}`})
await asyncExecShell(`DOCKER_HOST=${host} docker rm ${id}`); await executeDockerCmd({ dockerId, command: `docker rm ${id}`})
} }
} catch (error) { } catch (error) {
console.log(error); console.log(error);

View File

@ -72,7 +72,7 @@ export async function getApplication(request: FastifyRequest<OnlyId>) {
let isExited = false; let isExited = false;
const application: any = await getApplicationFromDB(id, teamId); const application: any = await getApplicationFromDB(id, teamId);
if (application?.destinationDockerId && application.destinationDocker?.engine) { if (application?.destinationDockerId && application.destinationDocker?.engine) {
isRunning = await checkContainer(application.destinationDocker.engine, id); isRunning = await checkContainer({ dockerId: application.destinationDocker.id, container: id });
isExited = await isContainerExited(application.destinationDocker.engine, id); isExited = await isContainerExited(application.destinationDocker.engine, id);
} }
return { return {
@ -285,10 +285,10 @@ export async function stopApplication(request: FastifyRequest<OnlyId>, reply: Fa
const { teamId } = request.user const { teamId } = request.user
const application: any = await getApplicationFromDB(id, teamId); const application: any = await getApplicationFromDB(id, teamId);
if (application?.destinationDockerId && application.destinationDocker?.engine) { if (application?.destinationDockerId && application.destinationDocker?.engine) {
const { engine } = application.destinationDocker; const { engine, id: dockerId } = application.destinationDocker;
const found = await checkContainer(engine, id); const found = await checkContainer({ dockerId, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: application.destinationDocker.id });
} }
} }
return reply.code(201).send(); return reply.code(201).send();
@ -314,7 +314,7 @@ export async function deleteApplication(request: FastifyRequest<DeleteApplicatio
for (const container of containersArray) { for (const container of containersArray) {
const containerObj = JSON.parse(container); const containerObj = JSON.parse(container);
const id = containerObj.ID; const id = containerObj.ID;
await removeContainer({ id, engine: application.destinationDocker.engine }); await removeContainer({ id, dockerId: application.destinationDocker.id });
} }
} }
} }
@ -375,7 +375,7 @@ export async function getUsage(request) {
const application: any = await getApplicationFromDB(id, teamId); const application: any = await getApplicationFromDB(id, teamId);
if (application.destinationDockerId) { if (application.destinationDockerId) {
[usage] = await Promise.all([getContainerUsage(application.destinationDocker.engine, id)]); [usage] = await Promise.all([getContainerUsage(application.destinationDocker.id, id)]);
} }
return { return {
usage usage

View File

@ -3,7 +3,7 @@ import type { FastifyRequest } from 'fastify';
import { FastifyReply } from 'fastify'; import { FastifyReply } from 'fastify';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
import fs from 'fs/promises'; import fs from 'fs/promises';
import { asyncExecShell, ComposeFile, createDirectories, decrypt, encrypt, errorHandler, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePort, listSettings, makeLabelForStandaloneDatabase, prisma, startTcpProxy, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common'; import { asyncExecShell, ComposeFile, createDirectories, decrypt, encrypt, errorHandler, executeDockerCmd, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePort, listSettings, makeLabelForStandaloneDatabase, prisma, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common';
import { dockerInstance, getEngine } from '../../../../lib/docker'; import { dockerInstance, getEngine } from '../../../../lib/docker';
import { day } from '../../../../lib/dayjs'; import { day } from '../../../../lib/dayjs';
import { GetDatabaseLogs, OnlyId, SaveDatabase, SaveDatabaseDestination, SaveDatabaseSettings, SaveVersion } from '../../../../types'; import { GetDatabaseLogs, OnlyId, SaveDatabase, SaveDatabaseDestination, SaveDatabaseSettings, SaveVersion } from '../../../../types';
@ -56,6 +56,36 @@ export async function newDatabase(request: FastifyRequest, reply: FastifyReply)
return errorHandler({ status, message }) return errorHandler({ status, message })
} }
} }
export async function getDatabaseStatus(request: FastifyRequest<OnlyId>) {
try {
const { id } = request.params;
const teamId = request.user.teamId;
let isRunning = false;
const database = await prisma.database.findFirst({
where: { id, teams: { some: { id: teamId === '0' ? undefined : teamId } } },
include: { destinationDocker: true, settings: true }
});
const { destinationDockerId, destinationDocker } = database;
if (destinationDockerId) {
try {
const { stdout } = await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker inspect --format '{{json .State}}' ${id}` })
if (JSON.parse(stdout).Running) {
isRunning = true;
}
} catch (error) {
//
}
}
return {
isRunning
}
} catch ({ status, message }) {
return errorHandler({ status, message })
}
}
export async function getDatabase(request: FastifyRequest<OnlyId>) { export async function getDatabase(request: FastifyRequest<OnlyId>) {
try { try {
const { id } = request.params; const { id } = request.params;
@ -69,29 +99,11 @@ export async function getDatabase(request: FastifyRequest<OnlyId>) {
} }
if (database.dbUserPassword) database.dbUserPassword = decrypt(database.dbUserPassword); if (database.dbUserPassword) database.dbUserPassword = decrypt(database.dbUserPassword);
if (database.rootUserPassword) database.rootUserPassword = decrypt(database.rootUserPassword); if (database.rootUserPassword) database.rootUserPassword = decrypt(database.rootUserPassword);
const { destinationDockerId, destinationDocker } = database;
let isRunning = false;
if (destinationDockerId) {
const host = getEngine(destinationDocker.engine);
try {
const { stdout } = await asyncExecShell(
`DOCKER_HOST=${host} docker inspect --format '{{json .State}}' ${id}`
);
if (JSON.parse(stdout).Running) {
isRunning = true;
}
} catch (error) {
//
}
}
const configuration = generateDatabaseConfiguration(database); const configuration = generateDatabaseConfiguration(database);
const settings = await listSettings(); const settings = await listSettings();
return { return {
privatePort: configuration?.privatePort, privatePort: configuration?.privatePort,
database, database,
isRunning,
versions: await getDatabaseVersions(database.type), versions: await getDatabaseVersions(database.type),
settings settings
}; };
@ -164,16 +176,15 @@ export async function saveDatabaseDestination(request: FastifyRequest<SaveDataba
const { const {
destinationDockerId, destinationDockerId,
destinationDocker: { engine }, destinationDocker: { engine, id: dockerId },
version, version,
type type
} = await prisma.database.findUnique({ where: { id }, include: { destinationDocker: true } }); } = await prisma.database.findUnique({ where: { id }, include: { destinationDocker: true } });
if (destinationDockerId) { if (destinationDockerId) {
const host = getEngine(engine);
if (type && version) { if (type && version) {
const baseImage = getDatabaseImage(type); const baseImage = getDatabaseImage(type);
asyncExecShell(`DOCKER_HOST=${host} docker pull ${baseImage}:${version}`); executeDockerCmd({ dockerId, command: `docker pull ${baseImage}:${version}` })
} }
} }
return reply.code(201).send({}) return reply.code(201).send({})
@ -194,7 +205,7 @@ export async function getDatabaseUsage(request: FastifyRequest<OnlyId>) {
if (database.dbUserPassword) database.dbUserPassword = decrypt(database.dbUserPassword); if (database.dbUserPassword) database.dbUserPassword = decrypt(database.dbUserPassword);
if (database.rootUserPassword) database.rootUserPassword = decrypt(database.rootUserPassword); if (database.rootUserPassword) database.rootUserPassword = decrypt(database.rootUserPassword);
if (database.destinationDockerId) { if (database.destinationDockerId) {
[usage] = await Promise.all([getContainerUsage(database.destinationDocker.engine, id)]); [usage] = await Promise.all([getContainerUsage(database.destinationDocker.id, id)]);
} }
return { return {
usage usage
@ -267,13 +278,13 @@ export async function startDatabase(request: FastifyRequest<OnlyId>) {
const composeFileDestination = `${workdir}/docker-compose.yaml`; const composeFileDestination = `${workdir}/docker-compose.yaml`;
await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); await fs.writeFile(composeFileDestination, yaml.dump(composeFile));
try { try {
await asyncExecShell(`DOCKER_HOST=${host} docker volume create ${volumeName}`); await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker volume create ${volumeName}` })
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
try { try {
await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up -d` })
if (isPublic) await startTcpProxy(destinationDocker, id, publicPort, privatePort); if (isPublic) await startTraefikTCPProxy(destinationDocker, id, publicPort, privatePort);
return {}; return {};
} catch (error) { } catch (error) {
throw { throw {
@ -453,11 +464,7 @@ export async function saveDatabaseSettings(request: FastifyRequest<SaveDatabaseS
if (destinationDockerId) { if (destinationDockerId) {
if (isPublic) { if (isPublic) {
await prisma.database.update({ where: { id }, data: { publicPort } }); await prisma.database.update({ where: { id }, data: { publicPort } });
if (settings.isTraefikUsed) { await startTraefikTCPProxy(destinationDocker, id, publicPort, privatePort);
await startTraefikTCPProxy(destinationDocker, id, publicPort, privatePort);
} else {
await startTcpProxy(destinationDocker, id, publicPort, privatePort);
}
} else { } else {
await prisma.database.update({ where: { id }, data: { publicPort: null } }); await prisma.database.update({ where: { id }, data: { publicPort: null } });
await stopTcpHttpProxy(id, destinationDocker, oldPublicPort); await stopTcpHttpProxy(id, destinationDocker, oldPublicPort);

View File

@ -1,5 +1,5 @@
import { FastifyPluginAsync } from 'fastify'; import { FastifyPluginAsync } from 'fastify';
import { deleteDatabase, getDatabase, getDatabaseLogs, getDatabaseTypes, getDatabaseUsage, getVersions, listDatabases, newDatabase, saveDatabase, saveDatabaseDestination, saveDatabaseSettings, saveDatabaseType, saveVersion, startDatabase, stopDatabase } from './handlers'; import { deleteDatabase, getDatabase, getDatabaseLogs, getDatabaseStatus, getDatabaseTypes, getDatabaseUsage, getVersions, listDatabases, newDatabase, saveDatabase, saveDatabaseDestination, saveDatabaseSettings, saveDatabaseType, saveVersion, startDatabase, stopDatabase } from './handlers';
import type { GetDatabaseLogs, OnlyId, SaveDatabase, SaveDatabaseDestination, SaveDatabaseSettings, SaveVersion } from '../../../../types'; import type { GetDatabaseLogs, OnlyId, SaveDatabase, SaveDatabaseDestination, SaveDatabaseSettings, SaveVersion } from '../../../../types';
import type { SaveDatabaseType } from './types'; import type { SaveDatabaseType } from './types';
@ -12,6 +12,7 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
fastify.post('/new', async (request, reply) => await newDatabase(request, reply)); fastify.post('/new', async (request, reply) => await newDatabase(request, reply));
fastify.get<OnlyId>('/:id', async (request) => await getDatabase(request)); fastify.get<OnlyId>('/:id', async (request) => await getDatabase(request));
fastify.get<OnlyId>('/:id/status', async (request) => await getDatabaseStatus(request));
fastify.post<SaveDatabase>('/:id', async (request, reply) => await saveDatabase(request, reply)); fastify.post<SaveDatabase>('/:id', async (request, reply) => await saveDatabase(request, reply));
fastify.delete<OnlyId>('/:id', async (request) => await deleteDatabase(request)); fastify.delete<OnlyId>('/:id', async (request) => await deleteDatabase(request));

View File

@ -2,7 +2,7 @@ import type { FastifyRequest } from 'fastify';
import { FastifyReply } from 'fastify'; import { FastifyReply } from 'fastify';
import sshConfig from 'ssh-config' import sshConfig from 'ssh-config'
import fs from 'fs/promises' import fs from 'fs/promises'
import { asyncExecShell, decrypt, errorHandler, listSettings, prisma, startCoolifyProxy, startTraefikProxy, stopTraefikProxy } from '../../../../lib/common'; import { asyncExecShell, decrypt, errorHandler, listSettings, prisma, startTraefikProxy, stopTraefikProxy } from '../../../../lib/common';
import { checkContainer, dockerInstance, getEngine } from '../../../../lib/docker'; import { checkContainer, dockerInstance, getEngine } from '../../../../lib/docker';
import type { OnlyId } from '../../../../types'; import type { OnlyId } from '../../../../types';
@ -55,23 +55,8 @@ export async function getDestination(request: FastifyRequest<OnlyId>) {
const settings = await listSettings(); const settings = await listSettings();
let payload = { let payload = {
destination, destination,
settings, settings
state: false
}; };
if (destination?.remoteEngine) {
// const { stdout } = await asyncExecShell(
// `ssh -p ${destination.port} ${destination.user}@${destination.ipAddress} "docker ps -a"`
// );
// console.log(stdout)
// const engine = await generateRemoteEngine(destination);
// // await saveSshKey(destination);
// payload.state = await checkContainer(engine, 'coolify-haproxy');
} else {
const containerName = 'coolify-proxy';
payload.state =
destination?.engine && (await checkContainer(destination.engine, containerName));
}
return { return {
...payload ...payload
}; };
@ -83,7 +68,7 @@ export async function getDestination(request: FastifyRequest<OnlyId>) {
export async function newDestination(request: FastifyRequest<NewDestination>, reply: FastifyReply) { export async function newDestination(request: FastifyRequest<NewDestination>, reply: FastifyReply) {
try { try {
const { id } = request.params const { id } = request.params
let { name, network, engine, isCoolifyProxyUsed, ipAddress, user, port, sshPrivateKey } = request.body let { name, network, engine, isCoolifyProxyUsed, remoteIpAddress, remoteUser, remotePort } = request.body
const teamId = request.user.teamId; const teamId = request.user.teamId;
if (id === 'new') { if (id === 'new') {
if (engine) { if (engine) {
@ -111,16 +96,14 @@ export async function newDestination(request: FastifyRequest<NewDestination>, re
if (isCoolifyProxyUsed) { if (isCoolifyProxyUsed) {
const settings = await prisma.setting.findFirst(); const settings = await prisma.setting.findFirst();
if (settings?.isTraefikUsed) { if (settings?.isTraefikUsed) {
await startTraefikProxy(engine); await startTraefikProxy(id);
} else {
await startCoolifyProxy(engine);
} }
} }
return reply.code(201).send({ id: destination.id }); return reply.code(201).send({ id: destination.id });
} }
if (ipAddress) { if (remoteIpAddress) {
await prisma.destinationDocker.create({ await prisma.destinationDocker.create({
data: { name, teams: { connect: { id: teamId } }, engine, network, isCoolifyProxyUsed, remoteEngine: true, remoteIpAddress: ipAddress, remoteUser: user, remotePort: port } data: { name, teams: { connect: { id: teamId } }, engine, network, isCoolifyProxyUsed, remoteEngine: true, remoteIpAddress, remoteUser, remotePort }
}); });
return reply.code(201).send() return reply.code(201).send()
@ -180,35 +163,39 @@ export async function saveDestinationSettings(request: FastifyRequest<SaveDestin
} }
} }
export async function startProxy(request: FastifyRequest<Proxy>) { export async function startProxy(request: FastifyRequest<Proxy>) {
const { engine } = request.body; const { id } = request.params
try { try {
await startTraefikProxy(engine); await startTraefikProxy(id);
return {} return {}
} catch ({ status, message }) { } catch ({ status, message }) {
await stopTraefikProxy(engine); await stopTraefikProxy(id);
return errorHandler({ status, message }) return errorHandler({ status, message })
} }
} }
export async function stopProxy(request: FastifyRequest<Proxy>) { export async function stopProxy(request: FastifyRequest<Proxy>) {
const { engine } = request.body; const { id } = request.params
try { try {
await stopTraefikProxy(engine); await stopTraefikProxy(id);
return {} return {}
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message })
} }
} }
export async function restartProxy(request: FastifyRequest<Proxy>) { export async function restartProxy(request: FastifyRequest<Proxy>) {
const { engine } = request.body; const { id } = request.params
try { try {
await stopTraefikProxy(engine); await stopTraefikProxy(id);
await startTraefikProxy(engine); await startTraefikProxy(id);
await prisma.destinationDocker.updateMany({ await prisma.destinationDocker.update({
where: { engine }, where: { id },
data: { isCoolifyProxyUsed: true } data: { isCoolifyProxyUsed: true }
}); });
return {} return {}
} catch ({ status, message }) { } catch ({ status, message }) {
await prisma.destinationDocker.update({
where: { id },
data: { isCoolifyProxyUsed: false }
});
return errorHandler({ status, message }) return errorHandler({ status, message })
} }
} }
@ -217,7 +204,6 @@ export async function assignSSHKey(request: FastifyRequest) {
try { try {
const { id: sshKeyId } = request.body; const { id: sshKeyId } = request.body;
const { id } = request.params; const { id } = request.params;
console.log({ id, sshKeyId })
await prisma.destinationDocker.update({ where: { id }, data: { sshKey: { connect: { id: sshKeyId } } } }) await prisma.destinationDocker.update({ where: { id }, data: { sshKey: { connect: { id: sshKeyId } } } })
return {} return {}
} catch ({ status, message }) { } catch ({ status, message }) {
@ -254,3 +240,16 @@ export async function verifyRemoteDockerEngine(request: FastifyRequest, reply: F
return errorHandler({ status, message }) return errorHandler({ status, message })
} }
} }
export async function getDestinationStatus(request: FastifyRequest<OnlyId>) {
try {
const { id } = request.params
const destination = await prisma.destinationDocker.findUnique({ where: { id } })
const containerName = 'coolify-proxy';
return {
isRunning: await checkContainer({ dockerId: destination.id, container: containerName })
}
} catch ({ status, message }) {
return errorHandler({ status, message })
}
}

View File

@ -1,5 +1,5 @@
import { FastifyPluginAsync } from 'fastify'; import { FastifyPluginAsync } from 'fastify';
import { assignSSHKey, checkDestination, deleteDestination, getDestination, listDestinations, newDestination, restartProxy, saveDestinationSettings, startProxy, stopProxy, verifyRemoteDockerEngine } from './handlers'; import { assignSSHKey, checkDestination, deleteDestination, getDestination, getDestinationStatus, listDestinations, newDestination, restartProxy, saveDestinationSettings, startProxy, stopProxy, verifyRemoteDockerEngine } from './handlers';
import type { OnlyId } from '../../../../types'; import type { OnlyId } from '../../../../types';
import type { CheckDestination, NewDestination, Proxy, SaveDestinationSettings } from './types'; import type { CheckDestination, NewDestination, Proxy, SaveDestinationSettings } from './types';
@ -14,6 +14,7 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
fastify.get<OnlyId>('/:id', async (request) => await getDestination(request)); fastify.get<OnlyId>('/:id', async (request) => await getDestination(request));
fastify.post<NewDestination>('/:id', async (request, reply) => await newDestination(request, reply)); fastify.post<NewDestination>('/:id', async (request, reply) => await newDestination(request, reply));
fastify.delete<OnlyId>('/:id', async (request) => await deleteDestination(request)); fastify.delete<OnlyId>('/:id', async (request) => await deleteDestination(request));
fastify.get<OnlyId>('/:id/status', async (request) => await getDestinationStatus(request));
fastify.post<SaveDestinationSettings>('/:id/settings', async (request) => await saveDestinationSettings(request)); fastify.post<SaveDestinationSettings>('/:id/settings', async (request) => await saveDestinationSettings(request));
fastify.post<Proxy>('/:id/start', async (request,) => await startProxy(request)); fastify.post<Proxy>('/:id/start', async (request,) => await startProxy(request));

View File

@ -20,7 +20,5 @@ export interface SaveDestinationSettings extends OnlyId {
} }
} }
export interface Proxy extends OnlyId { export interface Proxy extends OnlyId {
Body: {
engine: string
}
} }

View File

@ -282,7 +282,7 @@ export async function getServiceUsage(request: FastifyRequest<OnlyId>) {
const service = await getServiceFromDB({ id, teamId }); const service = await getServiceFromDB({ id, teamId });
if (service.destinationDockerId) { if (service.destinationDockerId) {
[usage] = await Promise.all([getContainerUsage(service.destinationDocker.engine, id)]); [usage] = await Promise.all([getContainerUsage(service.destinationDocker.id, id)]);
} }
return { return {
usage usage
@ -877,17 +877,17 @@ async function stopPlausibleAnalyticsService(request: FastifyRequest<ServiceStar
if (destinationDockerId) { if (destinationDockerId) {
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
let found = await checkContainer(engine, id); let found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
found = await checkContainer(engine, `${id}-postgresql`); found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-postgresql` });
if (found) { if (found) {
await removeContainer({ id: `${id}-postgresql`, engine }); await removeContainer({ id: `${id}-postgresql`, dockerId: destinationDocker.id });
} }
found = await checkContainer(engine, `${id}-clickhouse`); found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-clickhouse` });
if (found) { if (found) {
await removeContainer({ id: `${id}-clickhouse`, engine }); await removeContainer({ id: `${id}-clickhouse`, dockerId: destinationDocker.id });
} }
} }
@ -971,9 +971,9 @@ async function stopNocodbService(request: FastifyRequest<ServiceStartStop>) {
const { destinationDockerId, destinationDocker, fqdn } = service; const { destinationDockerId, destinationDocker, fqdn } = service;
if (destinationDockerId) { if (destinationDockerId) {
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
const found = await checkContainer(engine, id); const found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
} }
return {} return {}
@ -1075,9 +1075,9 @@ async function stopMinioService(request: FastifyRequest<ServiceStartStop>) {
await prisma.minio.update({ where: { serviceId: id }, data: { publicPort: null } }) await prisma.minio.update({ where: { serviceId: id }, data: { publicPort: null } })
if (destinationDockerId) { if (destinationDockerId) {
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
const found = await checkContainer(engine, id); const found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
} }
return {} return {}
@ -1199,9 +1199,9 @@ async function stopVscodeService(request: FastifyRequest<ServiceStartStop>) {
const { destinationDockerId, destinationDocker, fqdn } = service; const { destinationDockerId, destinationDocker, fqdn } = service;
if (destinationDockerId) { if (destinationDockerId) {
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
const found = await checkContainer(engine, id); const found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
} }
return {} return {}
@ -1348,26 +1348,26 @@ async function stopWordpressService(request: FastifyRequest<ServiceStartStop>) {
if (destinationDockerId) { if (destinationDockerId) {
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
try { try {
const found = await checkContainer(engine, id); const found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
try { try {
const found = await checkContainer(engine, `${id}-mysql`); const found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-mysql` });
if (found) { if (found) {
await removeContainer({ id: `${id}-mysql`, engine }); await removeContainer({ id: `${id}-mysql`, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
try { try {
if (ftpEnabled) { if (ftpEnabled) {
const found = await checkContainer(engine, `${id}-ftp`); const found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-ftp` });
if (found) { if (found) {
await removeContainer({ id: `${id}-ftp`, engine }); await removeContainer({ id: `${id}-ftp`, dockerId: destinationDocker.id });
} }
await prisma.wordpress.update({ await prisma.wordpress.update({
where: { serviceId: id }, where: { serviceId: id },
@ -1461,9 +1461,9 @@ async function stopVaultwardenService(request: FastifyRequest<ServiceStartStop>)
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
try { try {
const found = await checkContainer(engine, id); const found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -1553,9 +1553,9 @@ async function stopLanguageToolService(request: FastifyRequest<ServiceStartStop>
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
try { try {
const found = await checkContainer(engine, id); const found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -1645,9 +1645,9 @@ async function stopN8nService(request: FastifyRequest<ServiceStartStop>) {
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
try { try {
const found = await checkContainer(engine, id); const found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -1736,9 +1736,9 @@ async function stopUptimekumaService(request: FastifyRequest<ServiceStartStop>)
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
try { try {
const found = await checkContainer(engine, id); const found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -1888,13 +1888,13 @@ async function stopGhostService(request: FastifyRequest<ServiceStartStop>) {
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
try { try {
let found = await checkContainer(engine, id); let found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
found = await checkContainer(engine, `${id}-mariadb`); found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-mariadb` });
if (found) { if (found) {
await removeContainer({ id: `${id}-mariadb`, engine }); await removeContainer({ id: `${id}-mariadb`, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -1989,9 +1989,9 @@ async function stopMeilisearchService(request: FastifyRequest<ServiceStartStop>)
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
try { try {
const found = await checkContainer(engine, id); const found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -2208,17 +2208,17 @@ async function stopUmamiService(request: FastifyRequest<ServiceStartStop>) {
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
try { try {
const found = await checkContainer(engine, id); const found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
try { try {
const found = await checkContainer(engine, `${id}-postgresql`); const found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-postgresql` });
if (found) { if (found) {
await removeContainer({ id: `${id}-postgresql`, engine }); await removeContainer({ id: `${id}-postgresql`, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -2344,17 +2344,17 @@ async function stopHasuraService(request: FastifyRequest<ServiceStartStop>) {
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
try { try {
const found = await checkContainer(engine, id); const found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
try { try {
const found = await checkContainer(engine, `${id}-postgresql`); const found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-postgresql` });
if (found) { if (found) {
await removeContainer({ id: `${id}-postgresql`, engine }); await removeContainer({ id: `${id}-postgresql`, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -2507,17 +2507,17 @@ async function stopFiderService(request: FastifyRequest<ServiceStartStop>) {
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
try { try {
const found = await checkContainer(engine, id); const found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
try { try {
const found = await checkContainer(engine, `${id}-postgresql`); const found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-postgresql` });
if (found) { if (found) {
await removeContainer({ id: `${id}-postgresql`, engine }); await removeContainer({ id: `${id}-postgresql`, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -2670,17 +2670,17 @@ async function stopMoodleService(request: FastifyRequest<ServiceStartStop>) {
const engine = destinationDocker.engine; const engine = destinationDocker.engine;
try { try {
const found = await checkContainer(engine, id); const found = await checkContainer({ dockerId: destinationDocker.id, container: id });
if (found) { if (found) {
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
try { try {
const found = await checkContainer(engine, `${id}-mariadb`); const found = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-mariadb` });
if (found) { if (found) {
await removeContainer({ id: `${id}-mariadb`, engine }); await removeContainer({ id: `${id}-mariadb`, dockerId: destinationDocker.id });
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -2789,7 +2789,7 @@ export async function activateWordpressFtp(request: FastifyRequest<ActivateWordp
}); });
try { try {
const isRunning = await checkContainer(engine, `${id}-ftp`); const isRunning = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-ftp` });
if (isRunning) { if (isRunning) {
await asyncExecShell( await asyncExecShell(
`DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp` `DOCKER_HOST=${host} docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`

View File

@ -162,8 +162,10 @@ export async function gitHubEvents(request: FastifyRequest<GitHubEvents>): Promi
if (applicationFound.settings.previews) { if (applicationFound.settings.previews) {
if (applicationFound.destinationDockerId) { if (applicationFound.destinationDockerId) {
const isRunning = await checkContainer( const isRunning = await checkContainer(
applicationFound.destinationDocker.engine, {
applicationFound.id dockerId: applicationFound.destinationDocker.engine,
container: applicationFound.id
}
); );
if (!isRunning) { if (!isRunning) {
throw { status: 500, message: 'Application not running.' } throw { status: 500, message: 'Application not running.' }
@ -205,7 +207,7 @@ export async function gitHubEvents(request: FastifyRequest<GitHubEvents>): Promi
if (applicationFound.destinationDockerId) { if (applicationFound.destinationDockerId) {
const id = `${applicationFound.id}-${pullmergeRequestId}`; const id = `${applicationFound.id}-${pullmergeRequestId}`;
const engine = applicationFound.destinationDocker.engine; const engine = applicationFound.destinationDocker.engine;
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: applicationFound.destinationDocker.id });
} }
return { return {
message: 'Removed preview. Thank you!' message: 'Removed preview. Thank you!'

View File

@ -117,8 +117,10 @@ export async function gitLabEvents(request: FastifyRequest<GitLabEvents>) {
if (applicationFound.settings.previews) { if (applicationFound.settings.previews) {
if (applicationFound.destinationDockerId) { if (applicationFound.destinationDockerId) {
const isRunning = await checkContainer( const isRunning = await checkContainer(
applicationFound.destinationDocker.engine, {
applicationFound.id dockerId: applicationFound.destinationDocker.engine,
container: applicationFound.id
}
); );
if (!isRunning) { if (!isRunning) {
throw { status: 500, message: 'Application not running.' } throw { status: 500, message: 'Application not running.' }
@ -164,7 +166,7 @@ export async function gitLabEvents(request: FastifyRequest<GitLabEvents>) {
if (applicationFound.destinationDockerId) { if (applicationFound.destinationDockerId) {
const id = `${applicationFound.id}-${pullmergeRequestId}`; const id = `${applicationFound.id}-${pullmergeRequestId}`;
const engine = applicationFound.destinationDocker.engine; const engine = applicationFound.destinationDocker.engine;
await removeContainer({ id, engine }); await removeContainer({ id, dockerId: applicationFound.destinationDocker.id });
} }
return { return {
message: 'Removed preview. Thank you!' message: 'Removed preview. Thank you!'

View File

@ -104,7 +104,7 @@
async function getStatus() { async function getStatus() {
if ($status.database.loading) return; if ($status.database.loading) return;
$status.database.loading = true; $status.database.loading = true;
const data = await get(`/databases/${id}`); const data = await get(`/databases/${id}/status`);
$status.database.isRunning = data.isRunning; $status.database.isRunning = data.isRunning;
$status.database.initialLoading = false; $status.database.initialLoading = false;
$status.database.loading = false; $status.database.loading = false;

View File

@ -1,22 +1,24 @@
<script lang="ts"> <script lang="ts">
export let destination: any; export let destination: any;
export let settings: any; export let settings: any;
export let state: any;
import { toast } from '@zerodevx/svelte-toast'; import { toast } from '@zerodevx/svelte-toast';
import { page } from '$app/stores'; import { page } from '$app/stores';
import { post } from '$lib/api'; import { get, post } from '$lib/api';
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte'; import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { t } from '$lib/translations'; import { t } from '$lib/translations';
import { errorNotification } from '$lib/common'; import { errorNotification } from '$lib/common';
import { appSession } from '$lib/store'; import { appSession } from '$lib/store';
import Setting from '$lib/components/Setting.svelte'; import Setting from '$lib/components/Setting.svelte';
const { id } = $page.params; const { id } = $page.params;
let cannotDisable = settings.fqdn && destination.engine === '/var/run/docker.sock'; let cannotDisable = settings.fqdn && destination.engine === '/var/run/docker.sock';
let loading = false; let loading = false;
let loadingProxy = false; let loadingProxy = false;
let restarting = false; let restarting = false;
async function handleSubmit() { async function handleSubmit() {
loading = true; loading = true;
try { try {
@ -28,27 +30,31 @@
} }
} }
onMount(async () => { onMount(async () => {
if (state === false && destination.isCoolifyProxyUsed === true) { loadingProxy = true;
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed; const { isRunning } = await get(`/destinations/${id}/status`);
let proxyUsed = !destination.isCoolifyProxyUsed;
if (isRunning === false && destination.isCoolifyProxyUsed === true) {
try { try {
await post(`/destinations/${id}/settings`, { await post(`/destinations/${id}/settings`, {
isCoolifyProxyUsed: destination.isCoolifyProxyUsed, isCoolifyProxyUsed: proxyUsed,
engine: destination.engine engine: destination.engine
}); });
await stopProxy(); await stopProxy();
} catch (error) { } catch (error) {
return errorNotification(error); return errorNotification(error);
} }
} else if (state === true && destination.isCoolifyProxyUsed === false) { } else if (isRunning === true && destination.isCoolifyProxyUsed === false) {
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
try { try {
await post(`/destinations/${id}/settings`, { await post(`/destinations/${id}/settings`, {
isCoolifyProxyUsed: destination.isCoolifyProxyUsed, isCoolifyProxyUsed: proxyUsed,
engine: destination.engine engine: destination.engine
}); });
await startProxy(); await startProxy();
destination.isCoolifyProxyUsed = proxyUsed;
} catch (error) { } catch (error) {
return errorNotification(error); return errorNotification(error);
} finally {
loadingProxy = false;
} }
} }
}); });

View File

@ -1,12 +1,11 @@
<script lang="ts"> <script lang="ts">
export let destination: any; export let destination: any;
export let settings: any; export let settings: any;
export let state: any;
import { toast } from '@zerodevx/svelte-toast'; import { toast } from '@zerodevx/svelte-toast';
import { page, session } from '$app/stores'; import { page, session } from '$app/stores';
import Setting from '$lib/components/Setting.svelte'; import Setting from '$lib/components/Setting.svelte';
import { post } from '$lib/api'; import { get, post } from '$lib/api';
import CopyPasswordField from '$lib/components/CopyPasswordField.svelte'; import CopyPasswordField from '$lib/components/CopyPasswordField.svelte';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { t } from '$lib/translations'; import { t } from '$lib/translations';
@ -15,7 +14,9 @@
const { id } = $page.params; const { id } = $page.params;
let cannotDisable = settings.fqdn && destination.engine === '/var/run/docker.sock'; let cannotDisable = settings.fqdn && destination.engine === '/var/run/docker.sock';
let loading = false; let loading = false;
let loadingProxy = true;
let restarting = false; let restarting = false;
$: isDisabled = !$appSession.isAdmin; $: isDisabled = !$appSession.isAdmin;
async function handleSubmit() { async function handleSubmit() {
@ -29,7 +30,9 @@
} }
} }
onMount(async () => { onMount(async () => {
if (state === false && destination.isCoolifyProxyUsed === true) { loadingProxy = true;
const { isRunning } = await get(`/destinations/${id}/status`);
if (isRunning === false && destination.isCoolifyProxyUsed === true) {
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed; destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
try { try {
await post(`/destinations/${id}/settings`, { await post(`/destinations/${id}/settings`, {
@ -40,7 +43,7 @@
} catch (error) { } catch (error) {
return errorNotification(error); return errorNotification(error);
} }
} else if (state === true && destination.isCoolifyProxyUsed === false) { } else if (isRunning === true && destination.isCoolifyProxyUsed === false) {
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed; destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed;
try { try {
await post(`/destinations/${id}/settings`, { await post(`/destinations/${id}/settings`, {
@ -52,24 +55,27 @@
return errorNotification(error); return errorNotification(error);
} }
} }
loadingProxy = false;
}); });
async function changeProxySetting() { async function changeProxySetting() {
loadingProxy = true;
if (!cannotDisable) { if (!cannotDisable) {
const isProxyActivated = destination.isCoolifyProxyUsed; const isProxyActivated = destination.isCoolifyProxyUsed;
if (isProxyActivated) { if (isProxyActivated) {
const sure = confirm( const sure = confirm(
`Are you sure you want to ${ `Are you sure you want to ${
destination.isCoolifyProxyUsed ? 'disable' : 'enable' destination.isCoolifyProxyUsed ? 'disable' : 'enable'
} Coolify proxy? It will remove the proxy for all configured networks and all deployments on '${ } Coolify proxy? It will remove the proxy for all configured networks and all deployments! Nothing will be reachable if you do it!`
destination.engine
}'! Nothing will be reachable if you do it!`
); );
if (!sure) return; if (!sure) {
loadingProxy = false;
return;
}
} }
destination.isCoolifyProxyUsed = !destination.isCoolifyProxyUsed; let proxyUsed = !destination.isCoolifyProxyUsed;
try { try {
await post(`/destinations/${id}/settings`, { await post(`/destinations/${id}/settings`, {
isCoolifyProxyUsed: destination.isCoolifyProxyUsed, isCoolifyProxyUsed: proxyUsed,
engine: destination.engine engine: destination.engine
}); });
if (isProxyActivated) { if (isProxyActivated) {
@ -77,8 +83,11 @@
} else { } else {
await startProxy(); await startProxy();
} }
destination.isCoolifyProxyUsed = proxyUsed;
} catch (error) { } catch (error) {
return errorNotification(error); return errorNotification(error);
} finally {
loadingProxy = false;
} }
} }
} }
@ -223,6 +232,7 @@
<div class="grid grid-cols-2 items-center"> <div class="grid grid-cols-2 items-center">
<Setting <Setting
disabled={cannotDisable} disabled={cannotDisable}
loading={loadingProxy}
bind:setting={destination.isCoolifyProxyUsed} bind:setting={destination.isCoolifyProxyUsed}
on:click={changeProxySetting} on:click={changeProxySetting}
title={$t('destination.use_coolify_proxy')} title={$t('destination.use_coolify_proxy')}

View File

@ -12,7 +12,7 @@
try { try {
const { id } = params; const { id } = params;
const response = await get(`/destinations/${id}`); const response = await get(`/destinations/${id}`);
const { destination, settings, state } = response; const { destination, settings } = response;
if (id !== 'new' && (!destination || Object.entries(destination).length === 0)) { if (id !== 'new' && (!destination || Object.entries(destination).length === 0)) {
return { return {
status: 302, status: 302,
@ -36,8 +36,7 @@
}, },
stuff: { stuff: {
destination, destination,
settings, settings
state
} }
}; };
} catch (error) { } catch (error) {