fix: security hole
This commit is contained in:
		
							parent
							
								
									f12d453b5f
								
							
						
					
					
						commit
						b45ad19732
					
				| @ -49,6 +49,7 @@ | |||||||
|     "is-port-reachable": "4.0.0", |     "is-port-reachable": "4.0.0", | ||||||
|     "js-yaml": "4.1.0", |     "js-yaml": "4.1.0", | ||||||
|     "jsonwebtoken": "8.5.1", |     "jsonwebtoken": "8.5.1", | ||||||
|  |     "minimist": "^1.2.7", | ||||||
|     "node-forge": "1.3.1", |     "node-forge": "1.3.1", | ||||||
|     "node-os-utils": "1.3.7", |     "node-os-utils": "1.3.7", | ||||||
|     "p-all": "4.0.0", |     "p-all": "4.0.0", | ||||||
| @ -56,6 +57,7 @@ | |||||||
|     "prisma": "4.6.1", |     "prisma": "4.6.1", | ||||||
|     "public-ip": "6.0.1", |     "public-ip": "6.0.1", | ||||||
|     "pump": "3.0.0", |     "pump": "3.0.0", | ||||||
|  |     "shell-quote": "^1.7.4", | ||||||
|     "socket.io": "4.5.3", |     "socket.io": "4.5.3", | ||||||
|     "ssh-config": "4.1.6", |     "ssh-config": "4.1.6", | ||||||
|     "strip-ansi": "7.0.1", |     "strip-ansi": "7.0.1", | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ import autoLoad from '@fastify/autoload'; | |||||||
| import socketIO from 'fastify-socket.io' | import socketIO from 'fastify-socket.io' | ||||||
| import socketIOServer from './realtime' | import socketIOServer from './realtime' | ||||||
| 
 | 
 | ||||||
| import { asyncExecShell, cleanupDockerStorage, createRemoteEngineConfiguration, decrypt, executeDockerCmd, executeSSHCmd, generateDatabaseConfiguration, isDev, listSettings, prisma, sentryDSN, startTraefikProxy, startTraefikTCPProxy, version } from './lib/common'; | import { cleanupDockerStorage, createRemoteEngineConfiguration, decrypt, executeCommand, executeSSHCmd, generateDatabaseConfiguration, isDev, listSettings, prisma, sentryDSN, startTraefikProxy, startTraefikTCPProxy, version } from './lib/common'; | ||||||
| import { scheduler } from './lib/scheduler'; | import { scheduler } from './lib/scheduler'; | ||||||
| import { compareVersions } from 'compare-versions'; | import { compareVersions } from 'compare-versions'; | ||||||
| import Graceful from '@ladjs/graceful' | import Graceful from '@ladjs/graceful' | ||||||
| @ -261,7 +261,7 @@ async function initServer() { | |||||||
| 	} | 	} | ||||||
| 	try { | 	try { | ||||||
| 		console.log(`[001] Initializing server...`); | 		console.log(`[001] Initializing server...`); | ||||||
| 		await asyncExecShell(`docker network create --attachable coolify`); | 		await executeCommand({ command: `docker network create --attachable coolify` }); | ||||||
| 	} catch (error) { } | 	} catch (error) { } | ||||||
| 	try { | 	try { | ||||||
| 		console.log(`[002] Cleanup stucked builds...`); | 		console.log(`[002] Cleanup stucked builds...`); | ||||||
| @ -272,7 +272,7 @@ async function initServer() { | |||||||
| 	} catch (error) { } | 	} catch (error) { } | ||||||
| 	try { | 	try { | ||||||
| 		console.log('[003] Cleaning up old build sources under /tmp/build-sources/...'); | 		console.log('[003] Cleaning up old build sources under /tmp/build-sources/...'); | ||||||
| 		if (!isDev) await fs.rm('/tmp/build-sources', { recursive: true, force: true }) | 		await fs.rm('/tmp/build-sources', { recursive: true, force: true }) | ||||||
| 	} catch (error) { | 	} catch (error) { | ||||||
| 		console.log(error) | 		console.log(error) | ||||||
| 	} | 	} | ||||||
| @ -323,14 +323,10 @@ async function autoUpdater() { | |||||||
| 				if (!isDev) { | 				if (!isDev) { | ||||||
| 					const { isAutoUpdateEnabled } = await prisma.setting.findFirst(); | 					const { isAutoUpdateEnabled } = await prisma.setting.findFirst(); | ||||||
| 					if (isAutoUpdateEnabled) { | 					if (isAutoUpdateEnabled) { | ||||||
| 						await asyncExecShell(`docker pull coollabsio/coolify:${latestVersion}`); | 						await executeCommand({ command: `docker pull coollabsio/coolify:${latestVersion}` }) | ||||||
| 						await asyncExecShell(`env | grep '^COOLIFY' > .env`); | 						await executeCommand({ command: `env | grep '^COOLIFY' > .env` }) | ||||||
| 						await asyncExecShell( | 						await executeCommand({ command: `sed -i '/COOLIFY_AUTO_UPDATE=/cCOOLIFY_AUTO_UPDATE=${isAutoUpdateEnabled}' .env` }) | ||||||
| 							`sed -i '/COOLIFY_AUTO_UPDATE=/cCOOLIFY_AUTO_UPDATE=${isAutoUpdateEnabled}' .env` | 						await executeCommand({ command: `docker run --rm -tid --env-file .env -v /var/run/docker.sock:/var/run/docker.sock -v coolify-db coollabsio/coolify:${latestVersion} /bin/sh -c "env | grep COOLIFY > .env && echo 'TAG=${latestVersion}' >> .env && docker stop -t 0 coolify coolify-fluentbit && docker rm coolify coolify-fluentbit && docker compose pull && docker compose up -d --force-recreate"` }) | ||||||
| 						); |  | ||||||
| 						await asyncExecShell( |  | ||||||
| 							`docker run --rm -tid --env-file .env -v /var/run/docker.sock:/var/run/docker.sock -v coolify-db coollabsio/coolify:${latestVersion} /bin/sh -c "env | grep COOLIFY > .env && echo 'TAG=${latestVersion}' >> .env && docker stop -t 0 coolify coolify-fluentbit && docker rm coolify coolify-fluentbit && docker compose pull && docker compose up -d --force-recreate"` |  | ||||||
| 						); |  | ||||||
| 					} | 					} | ||||||
| 				} else { | 				} else { | ||||||
| 					console.log('Updating (not really in dev mode).'); | 					console.log('Updating (not really in dev mode).'); | ||||||
| @ -351,8 +347,8 @@ async function checkFluentBit() { | |||||||
| 			}); | 			}); | ||||||
| 			const { found } = await checkContainer({ dockerId: id, container: 'coolify-fluentbit', remove: true }); | 			const { found } = await checkContainer({ dockerId: id, container: 'coolify-fluentbit', remove: true }); | ||||||
| 			if (!found) { | 			if (!found) { | ||||||
| 				await asyncExecShell(`env | grep '^COOLIFY' > .env`); | 				await executeCommand({ command: `env | grep '^COOLIFY' > .env` }); | ||||||
| 				await asyncExecShell(`docker compose up -d fluent-bit`); | 				await executeCommand({ command: `docker compose up -d fluent-bit` }); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} catch (error) { | 	} catch (error) { | ||||||
| @ -462,13 +458,13 @@ async function copySSLCertificates() { | |||||||
| 	} catch (error) { | 	} catch (error) { | ||||||
| 		console.log(error) | 		console.log(error) | ||||||
| 	} finally { | 	} finally { | ||||||
| 		await asyncExecShell(`find /tmp/ -maxdepth 1 -type f -name '*-*.pem' -delete`) | 		await executeCommand({ command: `find /tmp/ -maxdepth 1 -type f -name '*-*.pem' -delete` }) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function copyRemoteCertificates(id: string, dockerId: string, remoteIpAddress: string) { | async function copyRemoteCertificates(id: string, dockerId: string, remoteIpAddress: string) { | ||||||
| 	try { | 	try { | ||||||
| 		await asyncExecShell(`scp /tmp/${id}-cert.pem /tmp/${id}-key.pem ${remoteIpAddress}:/tmp/`) | 		await executeCommand({ command: `scp /tmp/${id}-cert.pem /tmp/${id}-key.pem ${remoteIpAddress}:/tmp/` }) | ||||||
| 		await executeSSHCmd({ dockerId, command: `docker exec coolify-proxy sh -c 'test -d /etc/traefik/acme/custom/ || mkdir -p /etc/traefik/acme/custom/'` }) | 		await executeSSHCmd({ dockerId, command: `docker exec coolify-proxy sh -c 'test -d /etc/traefik/acme/custom/ || mkdir -p /etc/traefik/acme/custom/'` }) | ||||||
| 		await executeSSHCmd({ dockerId, command: `docker cp /tmp/${id}-key.pem coolify-proxy:/etc/traefik/acme/custom/` }) | 		await executeSSHCmd({ dockerId, command: `docker cp /tmp/${id}-key.pem coolify-proxy:/etc/traefik/acme/custom/` }) | ||||||
| 		await executeSSHCmd({ dockerId, command: `docker cp /tmp/${id}-cert.pem coolify-proxy:/etc/traefik/acme/custom/` }) | 		await executeSSHCmd({ dockerId, command: `docker cp /tmp/${id}-cert.pem coolify-proxy:/etc/traefik/acme/custom/` }) | ||||||
| @ -478,9 +474,9 @@ async function copyRemoteCertificates(id: string, dockerId: string, remoteIpAddr | |||||||
| } | } | ||||||
| async function copyLocalCertificates(id: string) { | async function copyLocalCertificates(id: string) { | ||||||
| 	try { | 	try { | ||||||
| 		await asyncExecShell(`docker exec coolify-proxy sh -c 'test -d /etc/traefik/acme/custom/ || mkdir -p /etc/traefik/acme/custom/'`) | 		await executeCommand({ command: `docker exec coolify-proxy sh -c 'test -d /etc/traefik/acme/custom/ || mkdir -p /etc/traefik/acme/custom/'`, shell: true }) | ||||||
| 		await asyncExecShell(`docker cp /tmp/${id}-key.pem coolify-proxy:/etc/traefik/acme/custom/`) | 		await executeCommand({ command: `docker cp /tmp/${id}-key.pem coolify-proxy:/etc/traefik/acme/custom/` }) | ||||||
| 		await asyncExecShell(`docker cp /tmp/${id}-cert.pem coolify-proxy:/etc/traefik/acme/custom/`) | 		await executeCommand({ command: `docker cp /tmp/${id}-cert.pem coolify-proxy:/etc/traefik/acme/custom/` }) | ||||||
| 	} catch (error) { | 	} catch (error) { | ||||||
| 		console.log({ error }) | 		console.log({ error }) | ||||||
| 	} | 	} | ||||||
| @ -498,12 +494,13 @@ async function cleanupStorage() { | |||||||
| 		try { | 		try { | ||||||
| 			let stdout = null | 			let stdout = null | ||||||
| 			if (!isDev) { | 			if (!isDev) { | ||||||
| 				const output = await executeDockerCmd({ dockerId: destination.id, command: `CONTAINER=$(docker ps -lq | head -1) && docker exec $CONTAINER sh -c 'df -kPT /'` }) | 				const output = await executeCommand({ dockerId: destination.id, command: `CONTAINER=$(docker ps -lq | head -1) && docker exec $CONTAINER sh -c 'df -kPT /'`, shell: true }) | ||||||
| 				stdout = output.stdout; | 				stdout = output.stdout; | ||||||
| 			} else { | 			} else { | ||||||
| 				const output = await asyncExecShell( | 				const output = await executeCommand({ | ||||||
| 					`df -kPT /` | 					command: | ||||||
| 				); | 						`df -kPT /` | ||||||
|  | 				}); | ||||||
| 				stdout = output.stdout; | 				stdout = output.stdout; | ||||||
| 			} | 			} | ||||||
| 			let lines = stdout.trim().split('\n'); | 			let lines = stdout.trim().split('\n'); | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import fs from 'fs/promises'; | |||||||
| import yaml from 'js-yaml'; | import yaml from 'js-yaml'; | ||||||
| 
 | 
 | ||||||
| import { copyBaseConfigurationFiles, makeLabelForSimpleDockerfile, makeLabelForStandaloneApplication, saveBuildLog, saveDockerRegistryCredentials, setDefaultConfiguration } from '../lib/buildPacks/common'; | import { copyBaseConfigurationFiles, makeLabelForSimpleDockerfile, makeLabelForStandaloneApplication, saveBuildLog, saveDockerRegistryCredentials, setDefaultConfiguration } from '../lib/buildPacks/common'; | ||||||
| import { createDirectories, decrypt, defaultComposeConfiguration, executeDockerCmd, getDomain, prisma, decryptApplication, isDev, pushToRegistry } from '../lib/common'; | import { createDirectories, decrypt, defaultComposeConfiguration, getDomain, prisma, decryptApplication, isDev, pushToRegistry, executeCommand } from '../lib/common'; | ||||||
| import * as importers from '../lib/importers'; | import * as importers from '../lib/importers'; | ||||||
| import * as buildpacks from '../lib/buildPacks'; | import * as buildpacks from '../lib/buildPacks'; | ||||||
| 
 | 
 | ||||||
| @ -70,14 +70,19 @@ import * as buildpacks from '../lib/buildPacks'; | |||||||
| 									if (destinationDockerId) { | 									if (destinationDockerId) { | ||||||
| 										await prisma.build.update({ where: { id: buildId }, data: { status: 'running' } }); | 										await prisma.build.update({ where: { id: buildId }, data: { status: 'running' } }); | ||||||
| 										try { | 										try { | ||||||
| 											await executeDockerCmd({ | 											const { stdout: containers } = await executeCommand({ | ||||||
| 												dockerId: destinationDockerId, | 												dockerId: destinationDockerId, | ||||||
| 												command: `docker ps -a --filter 'label=com.docker.compose.service=${applicationId}' --format {{.ID}}|xargs -r -n 1 docker stop -t 0` | 												command: `docker ps -a --filter 'label=com.docker.compose.service=${applicationId}' --format {{.ID}}` | ||||||
| 											}) |  | ||||||
| 											await executeDockerCmd({ |  | ||||||
| 												dockerId: destinationDockerId, |  | ||||||
| 												command: `docker ps -a --filter 'label=com.docker.compose.service=${applicationId}' --format {{.ID}}|xargs -r -n 1 docker rm --force` |  | ||||||
| 											}) | 											}) | ||||||
|  | 											if (containers) { | ||||||
|  | 												const containerArray = containers.split('\n'); | ||||||
|  | 												if (containerArray.length > 0) { | ||||||
|  | 													for (const container of containerArray) { | ||||||
|  | 														await executeCommand({ dockerId: destinationDockerId, command: `docker stop -t 0 ${container}` }) | ||||||
|  | 														await executeCommand({ dockerId: destinationDockerId, command: `docker rm --force ${container}` }) | ||||||
|  | 													} | ||||||
|  | 												} | ||||||
|  | 											} | ||||||
| 										} catch (error) { | 										} catch (error) { | ||||||
| 											//
 | 											//
 | ||||||
| 										} | 										} | ||||||
| @ -154,7 +159,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 executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose --project-directory ${workdir} up -d` }) | 											await executeCommand({ dockerId: destinationDocker.id, command: `docker compose --project-directory ${workdir} up -d` }) | ||||||
| 											await saveBuildLog({ line: 'Deployed successfully', buildId, applicationId }); | 											await saveBuildLog({ line: 'Deployed successfully', buildId, applicationId }); | ||||||
| 										} catch (error) { | 										} catch (error) { | ||||||
| 											await saveBuildLog({ line: error, buildId, applicationId }); | 											await saveBuildLog({ line: error, buildId, applicationId }); | ||||||
| @ -187,9 +192,7 @@ import * as buildpacks from '../lib/buildPacks'; | |||||||
| 									if (error instanceof Error) { | 									if (error instanceof Error) { | ||||||
| 										await saveBuildLog({ line: error.message, buildId, applicationId: application.id }); | 										await saveBuildLog({ line: error.message, buildId, applicationId: application.id }); | ||||||
| 									} | 									} | ||||||
| 									if (!isDev) { | 									await fs.rm(workdir, { recursive: true, force: true }); | ||||||
| 										await fs.rm(workdir, { recursive: true, force: true }); |  | ||||||
| 									} |  | ||||||
| 									return; | 									return; | ||||||
| 								} | 								} | ||||||
| 								try { | 								try { | ||||||
| @ -208,9 +211,7 @@ import * as buildpacks from '../lib/buildPacks'; | |||||||
| 										await saveBuildLog({ line: error.stderr, buildId, applicationId }); | 										await saveBuildLog({ line: error.stderr, buildId, applicationId }); | ||||||
| 									} | 									} | ||||||
| 								} finally { | 								} finally { | ||||||
| 									if (!isDev) { | 									await fs.rm(workdir, { recursive: true, force: true }); | ||||||
| 										await fs.rm(workdir, { recursive: true, force: true }); |  | ||||||
| 									} |  | ||||||
| 									await prisma.build.update({ where: { id: buildId }, data: { status: 'success' } }); | 									await prisma.build.update({ where: { id: buildId }, data: { status: 'success' } }); | ||||||
| 								} | 								} | ||||||
| 								return; | 								return; | ||||||
| @ -409,7 +410,7 @@ import * as buildpacks from '../lib/buildPacks'; | |||||||
| 									} | 									} | ||||||
| 
 | 
 | ||||||
| 									try { | 									try { | ||||||
| 										await executeDockerCmd({ | 										await executeCommand({ | ||||||
| 											dockerId: destinationDocker.id, | 											dockerId: destinationDocker.id, | ||||||
| 											command: `docker image inspect ${applicationId}:${tag}` | 											command: `docker image inspect ${applicationId}:${tag}` | ||||||
| 										}) | 										}) | ||||||
| @ -423,7 +424,7 @@ import * as buildpacks from '../lib/buildPacks'; | |||||||
| 									} | 									} | ||||||
| 
 | 
 | ||||||
| 									try { | 									try { | ||||||
| 										await executeDockerCmd({ | 										await executeCommand({ | ||||||
| 											dockerId: destinationDocker.id, | 											dockerId: destinationDocker.id, | ||||||
| 											command: `docker ${location ? `--config ${location}` : ''} pull ${imageName}:${customTag}` | 											command: `docker ${location ? `--config ${location}` : ''} pull ${imageName}:${customTag}` | ||||||
| 										}) | 										}) | ||||||
| @ -514,19 +515,24 @@ import * as buildpacks from '../lib/buildPacks'; | |||||||
| 
 | 
 | ||||||
| 									if (buildPack === 'compose') { | 									if (buildPack === 'compose') { | ||||||
| 										try { | 										try { | ||||||
| 											await executeDockerCmd({ | 											const { stdout: containers } = await executeCommand({ | ||||||
| 												dockerId: destinationDockerId, | 												dockerId: destinationDockerId, | ||||||
| 												command: `docker ps -a --filter 'label=coolify.applicationId=${applicationId}' --format {{.ID}}|xargs -r -n 1 docker stop -t 0` | 												command: `docker ps -a --filter 'label=coolify.applicationId=${applicationId}' --format {{.ID}}` | ||||||
| 											}) |  | ||||||
| 											await executeDockerCmd({ |  | ||||||
| 												dockerId: destinationDockerId, |  | ||||||
| 												command: `docker ps -a --filter 'label=coolify.applicationId=${applicationId}' --format {{.ID}}|xargs -r -n 1 docker rm --force` |  | ||||||
| 											}) | 											}) | ||||||
|  | 											if (containers) { | ||||||
|  | 												const containerArray = containers.split('\n'); | ||||||
|  | 												if (containerArray.length > 0) { | ||||||
|  | 													for (const container of containerArray) { | ||||||
|  | 														await executeCommand({ dockerId: destinationDockerId, command: `docker stop -t 0 ${container}` }) | ||||||
|  | 														await executeCommand({ dockerId: destinationDockerId, command: `docker rm --force ${container}` }) | ||||||
|  | 													} | ||||||
|  | 												} | ||||||
|  | 											} | ||||||
| 										} catch (error) { | 										} catch (error) { | ||||||
| 											//
 | 											//
 | ||||||
| 										} | 										} | ||||||
| 										try { | 										try { | ||||||
| 											await executeDockerCmd({ debug, buildId, applicationId, dockerId: destinationDocker.id, command: `docker compose --project-directory ${workdir} up -d` }) | 											await executeCommand({ debug, buildId, applicationId, dockerId: destinationDocker.id, command: `docker compose --project-directory ${workdir} up -d` }) | ||||||
| 											await saveBuildLog({ line: 'Deployed successfully', buildId, applicationId }); | 											await saveBuildLog({ line: 'Deployed successfully', buildId, applicationId }); | ||||||
| 											await prisma.build.update({ where: { id: buildId }, data: { status: 'success' } }); | 											await prisma.build.update({ where: { id: buildId }, data: { status: 'success' } }); | ||||||
| 											await prisma.application.update({ | 											await prisma.application.update({ | ||||||
| @ -549,14 +555,19 @@ import * as buildpacks from '../lib/buildPacks'; | |||||||
| 
 | 
 | ||||||
| 									} else { | 									} else { | ||||||
| 										try { | 										try { | ||||||
| 											await executeDockerCmd({ | 											const { stdout: containers } = await executeCommand({ | ||||||
| 												dockerId: destinationDockerId, | 												dockerId: destinationDockerId, | ||||||
| 												command: `docker ps -a --filter 'label=com.docker.compose.service=${pullmergeRequestId ? imageId : applicationId}' --format {{.ID}}|xargs -r -n 1 docker stop -t 0` | 												command: `docker ps -a --filter 'label=com.docker.compose.service=${pullmergeRequestId ? imageId : applicationId}' --format {{.ID}}` | ||||||
| 											}) |  | ||||||
| 											await executeDockerCmd({ |  | ||||||
| 												dockerId: destinationDockerId, |  | ||||||
| 												command: `docker ps -a --filter 'label=com.docker.compose.service=${pullmergeRequestId ? imageId : applicationId}' --format {{.ID}}|xargs -r -n 1 docker rm --force` |  | ||||||
| 											}) | 											}) | ||||||
|  | 											if (containers) { | ||||||
|  | 												const containerArray = containers.split('\n'); | ||||||
|  | 												if (containerArray.length > 0) { | ||||||
|  | 													for (const container of containerArray) { | ||||||
|  | 														await executeCommand({ dockerId: destinationDockerId, command: `docker stop -t 0 ${container}` }) | ||||||
|  | 														await executeCommand({ dockerId: destinationDockerId, command: `docker rm --force ${container}` }) | ||||||
|  | 													} | ||||||
|  | 												} | ||||||
|  | 											} | ||||||
| 										} catch (error) { | 										} catch (error) { | ||||||
| 											//
 | 											//
 | ||||||
| 										} | 										} | ||||||
| @ -622,7 +633,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 executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose --project-directory ${workdir} up -d` }) | 											await executeCommand({ dockerId: destinationDocker.id, command: `docker compose --project-directory ${workdir} up -d` }) | ||||||
| 											await saveBuildLog({ line: 'Deployed successfully', buildId, applicationId }); | 											await saveBuildLog({ line: 'Deployed successfully', buildId, applicationId }); | ||||||
| 										} catch (error) { | 										} catch (error) { | ||||||
| 											await saveBuildLog({ line: error, buildId, applicationId }); | 											await saveBuildLog({ line: error, buildId, applicationId }); | ||||||
| @ -660,9 +671,7 @@ import * as buildpacks from '../lib/buildPacks'; | |||||||
| 								if (error instanceof Error) { | 								if (error instanceof Error) { | ||||||
| 									await saveBuildLog({ line: error.message, buildId, applicationId: application.id }); | 									await saveBuildLog({ line: error.message, buildId, applicationId: application.id }); | ||||||
| 								} | 								} | ||||||
| 								if (!isDev) { | 								await fs.rm(workdir, { recursive: true, force: true }); | ||||||
| 									await fs.rm(workdir, { recursive: true, force: true }); |  | ||||||
| 								} |  | ||||||
| 								return; | 								return; | ||||||
| 							} | 							} | ||||||
| 							try { | 							try { | ||||||
| @ -680,9 +689,7 @@ import * as buildpacks from '../lib/buildPacks'; | |||||||
| 								} | 								} | ||||||
| 
 | 
 | ||||||
| 							} finally { | 							} finally { | ||||||
| 								if (!isDev) { | 								await fs.rm(workdir, { recursive: true, force: true }); | ||||||
| 									await fs.rm(workdir, { recursive: true, force: true }); |  | ||||||
| 								} |  | ||||||
| 								await prisma.build.update({ where: { id: buildId }, data: { status: 'success' } }); | 								await prisma.build.update({ where: { id: buildId }, data: { status: 'success' } }); | ||||||
| 							} | 							} | ||||||
| 						}); | 						}); | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| import { base64Encode, decrypt, encrypt, executeDockerCmd, generateTimestamp, getDomain, isARM, isDev, prisma, version } from "../common"; | import { base64Encode, decrypt, encrypt, executeCommand,  generateTimestamp, getDomain, isARM, isDev, prisma, version } from "../common"; | ||||||
| import { promises as fs } from 'fs'; | import { promises as fs } from 'fs'; | ||||||
| import { day } from "../dayjs"; | import { day } from "../dayjs"; | ||||||
| 
 | 
 | ||||||
| @ -656,7 +656,7 @@ export async function buildImage({ | |||||||
| 		location = await saveDockerRegistryCredentials({ url, username, password, workdir }) | 		location = await saveDockerRegistryCredentials({ url, username, password, workdir }) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	await executeDockerCmd({ debug, buildId, applicationId, dockerId, command: `docker ${location ? `--config ${location}` : ''} build --progress plain -f ${workdir}/${dockerFile} -t ${cache} --build-arg SOURCE_COMMIT=${commit} ${workdir}` }) | 	await executeCommand({ debug, buildId, applicationId, dockerId, command: `docker ${location ? `--config ${location}` : ''} build --progress plain -f ${workdir}/${dockerFile} -t ${cache} --build-arg SOURCE_COMMIT=${commit} ${workdir}` }) | ||||||
| 
 | 
 | ||||||
| 	const { status } = await prisma.build.findUnique({ where: { id: buildId } }) | 	const { status } = await prisma.build.findUnique({ where: { id: buildId } }) | ||||||
| 	if (status === 'canceled') { | 	if (status === 'canceled') { | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { promises as fs } from 'fs'; | import { promises as fs } from 'fs'; | ||||||
| import { defaultComposeConfiguration, executeDockerCmd } from '../common'; | import { defaultComposeConfiguration, executeCommand } from '../common'; | ||||||
| import { buildImage, saveBuildLog } from './common'; | import { buildImage, saveBuildLog } from './common'; | ||||||
| import yaml from 'js-yaml'; | import yaml from 'js-yaml'; | ||||||
| 
 | 
 | ||||||
| @ -108,8 +108,8 @@ export default async function (data) { | |||||||
|     } |     } | ||||||
|     dockerComposeYaml['networks'] = Object.assign({ ...networks }, { [network]: { external: true } }) |     dockerComposeYaml['networks'] = Object.assign({ ...networks }, { [network]: { external: true } }) | ||||||
|     await fs.writeFile(fileYaml, yaml.dump(dockerComposeYaml)); |     await fs.writeFile(fileYaml, yaml.dump(dockerComposeYaml)); | ||||||
|     await executeDockerCmd({ debug, buildId, applicationId, dockerId, command: `docker compose --project-directory ${workdir} pull` }) |     await executeCommand({ debug, buildId, applicationId, dockerId, command: `docker compose --project-directory ${workdir} pull` }) | ||||||
|     await saveBuildLog({ line: 'Pulling images from Compose file', buildId, applicationId }); |     await saveBuildLog({ line: 'Pulling images from Compose file', buildId, applicationId }); | ||||||
|     await executeDockerCmd({ debug, buildId, applicationId, dockerId, command: `docker compose --project-directory ${workdir} build --progress plain` }) |     await executeCommand({ debug, buildId, applicationId, dockerId, command: `docker compose --project-directory ${workdir} build --progress plain` }) | ||||||
|     await saveBuildLog({ line: 'Building images from Compose file', buildId, applicationId }); |     await saveBuildLog({ line: 'Building images from Compose file', buildId, applicationId }); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,11 +1,11 @@ | |||||||
| import { executeDockerCmd, prisma } from "../common" | import { executeCommand } from "../common" | ||||||
| import { saveBuildLog } from "./common"; | import { saveBuildLog } from "./common"; | ||||||
| 
 | 
 | ||||||
| export default async function (data: any): Promise<void> { | export default async function (data: any): Promise<void> { | ||||||
|     const { buildId, applicationId, tag, dockerId, debug, workdir, baseDirectory, baseImage } = data |     const { buildId, applicationId, tag, dockerId, debug, workdir, baseDirectory, baseImage } = data | ||||||
|     try { |     try { | ||||||
|         await saveBuildLog({ line: `Building image started.`, buildId, applicationId }); |         await saveBuildLog({ line: `Building image started.`, buildId, applicationId }); | ||||||
|         await executeDockerCmd({ |         await executeCommand({ | ||||||
|             buildId, |             buildId, | ||||||
|             debug, |             debug, | ||||||
|             dockerId, |             dockerId, | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| import { promises as fs } from 'fs'; | import { promises as fs } from 'fs'; | ||||||
| import TOML from '@iarna/toml'; | import TOML from '@iarna/toml'; | ||||||
| import { asyncExecShell } from '../common'; | import {  executeCommand } from '../common'; | ||||||
| import { buildCacheImageWithCargo, buildImage } from './common'; | import { buildCacheImageWithCargo, buildImage } from './common'; | ||||||
| 
 | 
 | ||||||
| const createDockerfile = async (data, image, name): Promise<void> => { | const createDockerfile = async (data, image, name): Promise<void> => { | ||||||
| @ -28,7 +28,7 @@ const createDockerfile = async (data, image, name): Promise<void> => { | |||||||
| export default async function (data) { | export default async function (data) { | ||||||
| 	try { | 	try { | ||||||
| 		const { workdir, baseImage, baseBuildImage } = data; | 		const { workdir, baseImage, baseBuildImage } = data; | ||||||
| 		const { stdout: cargoToml } = await asyncExecShell(`cat ${workdir}/Cargo.toml`); | 		const { stdout: cargoToml } = await executeCommand({ command: `cat ${workdir}/Cargo.toml` }); | ||||||
| 		const parsedToml: any = TOML.parse(cargoToml); | 		const parsedToml: any = TOML.parse(cargoToml); | ||||||
| 		const name = parsedToml.package.name; | 		const name = parsedToml.package.name; | ||||||
| 		await buildCacheImageWithCargo(data, baseBuildImage); | 		await buildCacheImageWithCargo(data, baseBuildImage); | ||||||
|  | |||||||
| @ -17,6 +17,7 @@ import { checkContainer, removeContainer } from './docker'; | |||||||
| import { day } from './dayjs'; | import { day } from './dayjs'; | ||||||
| import { saveBuildLog, saveDockerRegistryCredentials } from './buildPacks/common'; | import { saveBuildLog, saveDockerRegistryCredentials } from './buildPacks/common'; | ||||||
| import { scheduler } from './scheduler'; | import { scheduler } from './scheduler'; | ||||||
|  | import type { ExecaChildProcess } from 'execa'; | ||||||
| 
 | 
 | ||||||
| export const version = '3.12.0'; | export const version = '3.12.0'; | ||||||
| export const isDev = process.env.NODE_ENV === 'development'; | export const isDev = process.env.NODE_ENV === 'development'; | ||||||
| @ -63,7 +64,6 @@ const otherTraefikEndpoint = isDev | |||||||
| 	: 'http://coolify:3000/webhooks/traefik/other.json'; | 	: 'http://coolify:3000/webhooks/traefik/other.json'; | ||||||
| 
 | 
 | ||||||
| export const uniqueName = (): string => uniqueNamesGenerator(customConfig); | export const uniqueName = (): string => uniqueNamesGenerator(customConfig); | ||||||
| export const asyncExecShell = util.promisify(exec); |  | ||||||
| export const asyncExecShellStream = async ({ | export const asyncExecShellStream = async ({ | ||||||
| 	debug, | 	debug, | ||||||
| 	buildId, | 	buildId, | ||||||
| @ -303,7 +303,7 @@ export async function isDomainConfigured({ | |||||||
| 
 | 
 | ||||||
| export async function getContainerUsage(dockerId: string, container: string): Promise<any> { | export async function getContainerUsage(dockerId: string, container: string): Promise<any> { | ||||||
| 	try { | 	try { | ||||||
| 		const { stdout } = await executeDockerCmd({ | 		const { stdout } = await executeCommand({ | ||||||
| 			dockerId, | 			dockerId, | ||||||
| 			command: `docker container stats ${container} --no-stream --no-trunc --format "{{json .}}"` | 			command: `docker container stats ${container} --no-stream --no-trunc --format "{{json .}}"` | ||||||
| 		}); | 		}); | ||||||
| @ -508,36 +508,13 @@ export async function createRemoteEngineConfiguration(id: string) { | |||||||
| 		remoteUser | 		remoteUser | ||||||
| 	} = await prisma.destinationDocker.findFirst({ where: { id }, include: { sshKey: true } }); | 	} = await prisma.destinationDocker.findFirst({ where: { id }, include: { sshKey: true } }); | ||||||
| 	await fs.writeFile(sshKeyFile, decrypt(privateKey) + '\n', { encoding: 'utf8', mode: 400 }); | 	await fs.writeFile(sshKeyFile, decrypt(privateKey) + '\n', { encoding: 'utf8', mode: 400 }); | ||||||
| 	// Needed for remote docker compose
 |  | ||||||
| 	// const { stdout: numberOfSSHAgentsRunning } = await asyncExecShell(
 |  | ||||||
| 	// 	`ps ax | grep [s]sh-agent | grep coolify-ssh-agent.pid | grep -v grep | wc -l`
 |  | ||||||
| 	// );
 |  | ||||||
| 	// if (numberOfSSHAgentsRunning !== '' && Number(numberOfSSHAgentsRunning.trim()) == 0) {
 |  | ||||||
| 	// 	try {
 |  | ||||||
| 	// 		await fs.stat(`/tmp/coolify-ssh-agent.pid`);
 |  | ||||||
| 	// 		await fs.rm(`/tmp/coolify-ssh-agent.pid`);
 |  | ||||||
| 	// 	} catch (error) { }
 |  | ||||||
| 	// 	await asyncExecShell(`eval $(ssh-agent -sa /tmp/coolify-ssh-agent.pid)`);
 |  | ||||||
| 	// }
 |  | ||||||
| 	// await asyncExecShell(`SSH_AUTH_SOCK=/tmp/coolify-ssh-agent.pid ssh-add -q ${sshKeyFile}`);
 |  | ||||||
| 
 |  | ||||||
| 	// const { stdout: numberOfSSHTunnelsRunning } = await asyncExecShell(
 |  | ||||||
| 	// 	`ps ax | grep 'ssh -F /dev/null -o StrictHostKeyChecking no -fNL ${localPort}:localhost:${remotePort}' | grep -v grep | wc -l`
 |  | ||||||
| 	// );
 |  | ||||||
| 	// if (numberOfSSHTunnelsRunning !== '' && Number(numberOfSSHTunnelsRunning.trim()) == 0) {
 |  | ||||||
| 	// 	try {
 |  | ||||||
| 	// 		await asyncExecShell(
 |  | ||||||
| 	// 			`SSH_AUTH_SOCK=/tmp/coolify-ssh-agent.pid ssh -F /dev/null -o "StrictHostKeyChecking no" -fNL ${localPort}:localhost:${remotePort} ${remoteUser}@${remoteIpAddress}`
 |  | ||||||
| 	// 		);
 |  | ||||||
| 	// 	} catch (error) { }
 |  | ||||||
| 	// }
 |  | ||||||
| 	const config = sshConfig.parse(''); | 	const config = sshConfig.parse(''); | ||||||
| 	const Host = `${remoteIpAddress}-remote` | 	const Host = `${remoteIpAddress}-remote` | ||||||
| 
 | 
 | ||||||
| 	try { | 	try { | ||||||
| 		await asyncExecShell(`ssh-keygen -R ${Host}`); | 		await executeCommand({ command: `ssh-keygen -R ${Host}` }); | ||||||
| 		await asyncExecShell(`ssh-keygen -R ${remoteIpAddress}`); | 		await executeCommand({ command: `ssh-keygen -R ${remoteIpAddress}` }); | ||||||
| 		await asyncExecShell(`ssh-keygen -R localhost:${localPort}`); | 		await executeCommand({ command: `ssh-keygen -R localhost:${localPort}` }); | ||||||
| 	} catch (error) { } | 	} catch (error) { } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -566,8 +543,102 @@ export async function createRemoteEngineConfiguration(id: string) { | |||||||
| 	} | 	} | ||||||
| 	return await fs.writeFile(`${homedir}/.ssh/config`, sshConfig.stringify(config)); | 	return await fs.writeFile(`${homedir}/.ssh/config`, sshConfig.stringify(config)); | ||||||
| } | } | ||||||
|  | export async function executeCommand({ command, dockerId = null, sshCommand = false, shell = false, buildId, applicationId, debug }: { command: string, sshCommand?: boolean, shell?: boolean, dockerId?: string, buildId?: string, applicationId?: string, debug?: boolean }): Promise<ExecaChildProcess<string>> { | ||||||
|  | 	const { execa, execaCommand } = await import('execa') | ||||||
|  | 	const { parse } = await import('shell-quote') | ||||||
|  | 	const parsedCommand = parse(command); | ||||||
|  | 	const dockerCommand = parsedCommand[0]; | ||||||
|  | 	const dockerArgs = parsedCommand.slice(1); | ||||||
|  | 
 | ||||||
|  | 	if (dockerId) { | ||||||
|  | 		let { remoteEngine, remoteIpAddress, engine } = await prisma.destinationDocker.findUnique({ where: { id: dockerId } }) | ||||||
|  | 		if (remoteEngine) { | ||||||
|  | 			await createRemoteEngineConfiguration(dockerId); | ||||||
|  | 			engine = `ssh://${remoteIpAddress}-remote`; | ||||||
|  | 		} else { | ||||||
|  | 			engine = 'unix:///var/run/docker.sock'; | ||||||
|  | 		} | ||||||
|  | 		if (process.env.CODESANDBOX_HOST) { | ||||||
|  | 			if (command.startsWith('docker compose')) { | ||||||
|  | 				command = command.replace(/docker compose/gi, 'docker-compose'); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if (sshCommand) { | ||||||
|  | 			if (shell) { | ||||||
|  | 				return execaCommand(`ssh ${remoteIpAddress}-remote ${command}`, { shell: true, stdio: 'inherit' }); | ||||||
|  | 			} | ||||||
|  | 			return await execa('ssh', [`${remoteIpAddress}-remote`, ...dockerArgs]); | ||||||
|  | 		} | ||||||
|  | 		return await new Promise(async (resolve, reject) => { | ||||||
|  | 			let subprocess = null; | ||||||
|  | 			if (shell) { | ||||||
|  | 				subprocess = execaCommand(command, { | ||||||
|  | 					env: { DOCKER_BUILDKIT: '1', DOCKER_HOST: engine } | ||||||
|  | 				}); | ||||||
|  | 			} else { | ||||||
|  | 				subprocess = execa(dockerCommand, dockerArgs, { | ||||||
|  | 					env: { DOCKER_BUILDKIT: '1', DOCKER_HOST: engine } | ||||||
|  | 				}); | ||||||
|  | 			} | ||||||
|  | 			const logs = []; | ||||||
|  | 			subprocess.stdout.on('data', async (data) => { | ||||||
|  | 				const stdout = data.toString(); | ||||||
|  | 				const array = stdout.split('\n'); | ||||||
|  | 				for (const line of array) { | ||||||
|  | 					if (line !== '\n' && line !== '') { | ||||||
|  | 						const log = { | ||||||
|  | 							line: `${line.replace('\n', '')}`, | ||||||
|  | 							buildId, | ||||||
|  | 							applicationId | ||||||
|  | 						} | ||||||
|  | 						logs.push(log); | ||||||
|  | 						if (debug) { | ||||||
|  | 							await saveBuildLog(log); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}); | ||||||
|  | 			subprocess.stderr.on('data', async (data) => { | ||||||
|  | 				const stderr = data.toString(); | ||||||
|  | 				const array = stderr.split('\n'); | ||||||
|  | 				for (const line of array) { | ||||||
|  | 					if (line !== '\n' && line !== '') { | ||||||
|  | 						const log = { | ||||||
|  | 							line: `${line.replace('\n', '')}`, | ||||||
|  | 							buildId, | ||||||
|  | 							applicationId | ||||||
|  | 						} | ||||||
|  | 						logs.push(log); | ||||||
|  | 						if (debug) { | ||||||
|  | 							await saveBuildLog(log); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}); | ||||||
|  | 			subprocess.on('exit', async (code) => { | ||||||
|  | 				await asyncSleep(1000); | ||||||
|  | 				if (code === 0) { | ||||||
|  | 					resolve(code); | ||||||
|  | 				} else { | ||||||
|  | 					if (!debug) { | ||||||
|  | 						for (const log of logs) { | ||||||
|  | 							await saveBuildLog(log); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					reject(code); | ||||||
|  | 				} | ||||||
|  | 			}); | ||||||
|  | 		}) | ||||||
|  | 	} else { | ||||||
|  | 		if (shell) { | ||||||
|  | 			return execaCommand(command, { shell: true }); | ||||||
|  | 		} | ||||||
|  | 		return await execa(dockerCommand, dockerArgs); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| export async function executeSSHCmd({ dockerId, command }) { | export async function executeSSHCmd({ dockerId, command }) { | ||||||
| 	const { execaCommand } = await import('execa') | 	const { execaCommand, execa } = await import('execa') | ||||||
|  | 	const { parse } = await import('shell-quote') | ||||||
| 	let { remoteEngine, remoteIpAddress } = await prisma.destinationDocker.findUnique({ where: { id: dockerId } }) | 	let { remoteEngine, remoteIpAddress } = await prisma.destinationDocker.findUnique({ where: { id: dockerId } }) | ||||||
| 	if (remoteEngine) { | 	if (remoteEngine) { | ||||||
| 		await createRemoteEngineConfiguration(dockerId) | 		await createRemoteEngineConfiguration(dockerId) | ||||||
| @ -577,10 +648,12 @@ export async function executeSSHCmd({ dockerId, command }) { | |||||||
| 			command = command.replace(/docker compose/gi, 'docker-compose') | 			command = command.replace(/docker compose/gi, 'docker-compose') | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return await execaCommand(`ssh ${remoteIpAddress}-remote ${command}`) | 	const dockerArgs = parse(command); | ||||||
|  | 	return await execa('ssh', [`${remoteIpAddress}-remote`, ...dockerArgs]); | ||||||
| } | } | ||||||
| export async function executeDockerCmd({ debug, buildId, applicationId, dockerId, command }: { debug?: boolean, buildId?: string, applicationId?: string, dockerId: string, command: string }): Promise<any> { | export async function executeDockerCmd({ debug, buildId, applicationId, dockerId, command }: { debug?: boolean, buildId?: string, applicationId?: string, dockerId: string, command: string }): Promise<any> { | ||||||
| 	const { execaCommand } = await import('execa') | 	const { execa } = await import('execa') | ||||||
|  | 	const { parse } = await import('shell-quote') | ||||||
| 	let { remoteEngine, remoteIpAddress, engine } = await prisma.destinationDocker.findUnique({ where: { id: dockerId } }) | 	let { remoteEngine, remoteIpAddress, engine } = await prisma.destinationDocker.findUnique({ where: { id: dockerId } }) | ||||||
| 	if (remoteEngine) { | 	if (remoteEngine) { | ||||||
| 		await createRemoteEngineConfiguration(dockerId); | 		await createRemoteEngineConfiguration(dockerId); | ||||||
| @ -593,10 +666,13 @@ export async function executeDockerCmd({ debug, buildId, applicationId, dockerId | |||||||
| 			command = command.replace(/docker compose/gi, 'docker-compose'); | 			command = command.replace(/docker compose/gi, 'docker-compose'); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	const parsedCommand = parse(command); | ||||||
|  | 	const dockerCommand = parsedCommand[0]; | ||||||
|  | 	const dockerArgs = parsedCommand.slice(1); | ||||||
| 	if (command.startsWith(`docker build`) || command.startsWith(`pack build`) || command.startsWith(`docker compose build`)) { | 	if (command.startsWith(`docker build`) || command.startsWith(`pack build`) || command.startsWith(`docker compose build`)) { | ||||||
| 		return await asyncExecShellStream({ debug, buildId, applicationId, command, engine }); | 		return await asyncExecShellStream({ debug, buildId, applicationId, command, engine }); | ||||||
| 	} | 	} | ||||||
| 	return await execaCommand(command, { env: { DOCKER_BUILDKIT: "1", DOCKER_HOST: engine }, shell: true }) | 	return await execa(dockerCommand, dockerArgs, { env: { DOCKER_BUILDKIT: "1", DOCKER_HOST: engine } }); | ||||||
| } | } | ||||||
| export async function startTraefikProxy(id: string): Promise<void> { | export async function startTraefikProxy(id: string): Promise<void> { | ||||||
| 	const { engine, network, remoteEngine, remoteIpAddress } = await prisma.destinationDocker.findUnique({ where: { id } }) | 	const { engine, network, remoteEngine, remoteIpAddress } = await prisma.destinationDocker.findUnique({ where: { id } }) | ||||||
| @ -604,18 +680,18 @@ export async function startTraefikProxy(id: string): Promise<void> { | |||||||
| 	const { id: settingsId, ipv4, ipv6 } = await listSettings(); | 	const { id: settingsId, ipv4, ipv6 } = await listSettings(); | ||||||
| 
 | 
 | ||||||
| 	if (!found) { | 	if (!found) { | ||||||
| 		const { stdout: coolifyNetwork } = await executeDockerCmd({ | 		const { stdout: coolifyNetwork } = await executeCommand({ | ||||||
| 			dockerId: id, | 			dockerId: id, | ||||||
| 			command: `docker network ls --filter 'name=coolify-infra' --no-trunc --format "{{json .}}"` | 			command: `docker network ls --filter 'name=coolify-infra' --no-trunc --format "{{json .}}"` | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
| 		if (!coolifyNetwork) { | 		if (!coolifyNetwork) { | ||||||
| 			await executeDockerCmd({ | 			await executeCommand({ | ||||||
| 				dockerId: id, | 				dockerId: id, | ||||||
| 				command: `docker network create --attachable coolify-infra` | 				command: `docker network create --attachable coolify-infra` | ||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
| 		const { stdout: Config } = await executeDockerCmd({ | 		const { stdout: Config } = await executeCommand({ | ||||||
| 			dockerId: id, | 			dockerId: id, | ||||||
| 			command: `docker network inspect ${network} --format '{{json .IPAM.Config }}'` | 			command: `docker network inspect ${network} --format '{{json .IPAM.Config }}'` | ||||||
| 		}); | 		}); | ||||||
| @ -630,7 +706,7 @@ export async function startTraefikProxy(id: string): Promise<void> { | |||||||
| 			} | 			} | ||||||
| 			traefikUrl = `${ip}/webhooks/traefik/remote/${id}`; | 			traefikUrl = `${ip}/webhooks/traefik/remote/${id}`; | ||||||
| 		} | 		} | ||||||
| 		await executeDockerCmd({ | 		await executeCommand({ | ||||||
| 			dockerId: id, | 			dockerId: id, | ||||||
| 			command: `docker run --restart always \ | 			command: `docker run --restart always \ | ||||||
| 			--add-host 'host.docker.internal:host-gateway' \ | 			--add-host 'host.docker.internal:host-gateway' \ | ||||||
| @ -655,7 +731,6 @@ export async function startTraefikProxy(id: string): Promise<void> { | |||||||
| 			--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web \ | 			--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web \ | ||||||
| 			--log.level=error` | 			--log.level=error` | ||||||
| 		}); | 		}); | ||||||
| 		await prisma.setting.update({ where: { id: settingsId }, data: { proxyHash: null } }); |  | ||||||
| 		await prisma.destinationDocker.update({ | 		await prisma.destinationDocker.update({ | ||||||
| 			where: { id }, | 			where: { id }, | ||||||
| 			data: { isCoolifyProxyUsed: true } | 			data: { isCoolifyProxyUsed: true } | ||||||
| @ -679,13 +754,13 @@ export async function startTraefikProxy(id: string): Promise<void> { | |||||||
| 
 | 
 | ||||||
| export async function configureNetworkTraefikProxy(destination: any): Promise<void> { | export async function configureNetworkTraefikProxy(destination: any): Promise<void> { | ||||||
| 	const { id } = destination; | 	const { id } = destination; | ||||||
| 	const { stdout: networks } = await executeDockerCmd({ | 	const { stdout: networks } = await executeCommand({ | ||||||
| 		dockerId: id, | 		dockerId: id, | ||||||
| 		command: `docker ps -a --filter name=coolify-proxy --format '{{json .Networks}}'` | 		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(','); | ||||||
| 	if (!configuredNetworks.includes(destination.network)) { | 	if (!configuredNetworks.includes(destination.network)) { | ||||||
| 		await executeDockerCmd({ | 		await executeCommand({ | ||||||
| 			dockerId: destination.id, | 			dockerId: destination.id, | ||||||
| 			command: `docker network connect ${destination.network} coolify-proxy` | 			command: `docker network connect ${destination.network} coolify-proxy` | ||||||
| 		}); | 		}); | ||||||
| @ -700,13 +775,12 @@ export async function stopTraefikProxy( | |||||||
| 		where: { id }, | 		where: { id }, | ||||||
| 		data: { isCoolifyProxyUsed: false } | 		data: { isCoolifyProxyUsed: false } | ||||||
| 	}); | 	}); | ||||||
| 	const { id: settingsId } = await prisma.setting.findFirst({}); |  | ||||||
| 	await prisma.setting.update({ where: { id: settingsId }, data: { proxyHash: null } }); |  | ||||||
| 	try { | 	try { | ||||||
| 		if (found) { | 		if (found) { | ||||||
| 			await executeDockerCmd({ | 			await executeCommand({ | ||||||
| 				dockerId: id, | 				dockerId: id, | ||||||
| 				command: `docker stop -t 0 coolify-proxy && docker rm coolify-proxy` | 				command: `docker stop -t 0 coolify-proxy && docker rm coolify-proxy`, | ||||||
|  | 				shell: true | ||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
| 	} catch (error) { | 	} catch (error) { | ||||||
| @ -1099,9 +1173,9 @@ export const createDirectories = async ({ | |||||||
| 		workdirFound = !!(await fs.stat(workdir)); | 		workdirFound = !!(await fs.stat(workdir)); | ||||||
| 	} catch (error) { } | 	} catch (error) { } | ||||||
| 	if (workdirFound) { | 	if (workdirFound) { | ||||||
| 		await asyncExecShell(`rm -fr ${workdir}`); | 		await executeCommand({ command: `rm -fr ${workdir}` }); | ||||||
| 	} | 	} | ||||||
| 	await asyncExecShell(`mkdir -p ${workdir}`); | 	await executeCommand({ command: `mkdir -p ${workdir}` }); | ||||||
| 	return { | 	return { | ||||||
| 		workdir, | 		workdir, | ||||||
| 		repodir | 		repodir | ||||||
| @ -1117,7 +1191,7 @@ export async function stopDatabaseContainer(database: any): Promise<boolean> { | |||||||
| 	} = database; | 	} = database; | ||||||
| 	if (destinationDockerId) { | 	if (destinationDockerId) { | ||||||
| 		try { | 		try { | ||||||
| 			const { stdout } = await executeDockerCmd({ | 			const { stdout } = await executeCommand({ | ||||||
| 				dockerId, | 				dockerId, | ||||||
| 				command: `docker inspect --format '{{json .State}}' ${id}` | 				command: `docker inspect --format '{{json .State}}' ${id}` | ||||||
| 			}); | 			}); | ||||||
| @ -1145,9 +1219,10 @@ export async function stopTcpHttpProxy( | |||||||
| 	const { found } = await checkContainer({ dockerId, container }); | 	const { found } = await checkContainer({ dockerId, container }); | ||||||
| 	try { | 	try { | ||||||
| 		if (found) { | 		if (found) { | ||||||
| 			return await executeDockerCmd({ | 			return await executeCommand({ | ||||||
| 				dockerId, | 				dockerId, | ||||||
| 				command: `docker stop -t 0 ${container} && docker rm ${container}` | 				command: `docker stop -t 0 ${container} && docker rm ${container}`, | ||||||
|  | 				shell: true | ||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
| 	} catch (error) { | 	} catch (error) { | ||||||
| @ -1169,34 +1244,34 @@ export async function updatePasswordInDb(database, user, newPassword, isRoot) { | |||||||
| 	} = database; | 	} = database; | ||||||
| 	if (destinationDockerId) { | 	if (destinationDockerId) { | ||||||
| 		if (type === 'mysql') { | 		if (type === 'mysql') { | ||||||
| 			await executeDockerCmd({ | 			await executeCommand({ | ||||||
| 				dockerId, | 				dockerId, | ||||||
| 				command: `docker exec ${id} mysql -u ${rootUser} -p${rootUserPassword} -e \"ALTER USER '${user}'@'%' IDENTIFIED WITH caching_sha2_password BY '${newPassword}';\"` | 				command: `docker exec ${id} mysql -u ${rootUser} -p${rootUserPassword} -e \"ALTER USER '${user}'@'%' IDENTIFIED WITH caching_sha2_password BY '${newPassword}';\"` | ||||||
| 			}); | 			}); | ||||||
| 		} else if (type === 'mariadb') { | 		} else if (type === 'mariadb') { | ||||||
| 			await executeDockerCmd({ | 			await executeCommand({ | ||||||
| 				dockerId, | 				dockerId, | ||||||
| 				command: `docker exec ${id} mysql -u ${rootUser} -p${rootUserPassword} -e \"SET PASSWORD FOR '${user}'@'%' = PASSWORD('${newPassword}');\"` | 				command: `docker exec ${id} mysql -u ${rootUser} -p${rootUserPassword} -e \"SET PASSWORD FOR '${user}'@'%' = PASSWORD('${newPassword}');\"` | ||||||
| 			}); | 			}); | ||||||
| 		} else if (type === 'postgresql') { | 		} else if (type === 'postgresql') { | ||||||
| 			if (isRoot) { | 			if (isRoot) { | ||||||
| 				await executeDockerCmd({ | 				await executeCommand({ | ||||||
| 					dockerId, | 					dockerId, | ||||||
| 					command: `docker exec ${id} psql postgresql://postgres:${rootUserPassword}@${id}:5432/${defaultDatabase} -c "ALTER role postgres WITH PASSWORD '${newPassword}'"` | 					command: `docker exec ${id} psql postgresql://postgres:${rootUserPassword}@${id}:5432/${defaultDatabase} -c "ALTER role postgres WITH PASSWORD '${newPassword}'"` | ||||||
| 				}); | 				}); | ||||||
| 			} else { | 			} else { | ||||||
| 				await executeDockerCmd({ | 				await executeCommand({ | ||||||
| 					dockerId, | 					dockerId, | ||||||
| 					command: `docker exec ${id} psql postgresql://${dbUser}:${dbUserPassword}@${id}:5432/${defaultDatabase} -c "ALTER role ${user} WITH PASSWORD '${newPassword}'"` | 					command: `docker exec ${id} psql postgresql://${dbUser}:${dbUserPassword}@${id}:5432/${defaultDatabase} -c "ALTER role ${user} WITH PASSWORD '${newPassword}'"` | ||||||
| 				}); | 				}); | ||||||
| 			} | 			} | ||||||
| 		} else if (type === 'mongodb') { | 		} else if (type === 'mongodb') { | ||||||
| 			await executeDockerCmd({ | 			await executeCommand({ | ||||||
| 				dockerId, | 				dockerId, | ||||||
| 				command: `docker exec ${id} mongo 'mongodb://${rootUser}:${rootUserPassword}@${id}:27017/admin?readPreference=primary&ssl=false' --eval "db.changeUserPassword('${user}','${newPassword}')"` | 				command: `docker exec ${id} mongo 'mongodb://${rootUser}:${rootUserPassword}@${id}:27017/admin?readPreference=primary&ssl=false' --eval "db.changeUserPassword('${user}','${newPassword}')"` | ||||||
| 			}); | 			}); | ||||||
| 		} else if (type === 'redis') { | 		} else if (type === 'redis') { | ||||||
| 			await executeDockerCmd({ | 			await executeCommand({ | ||||||
| 				dockerId, | 				dockerId, | ||||||
| 				command: `docker exec ${id} redis-cli -u redis://${dbUserPassword}@${id}:6379 --raw CONFIG SET requirepass ${newPassword}` | 				command: `docker exec ${id} redis-cli -u redis://${dbUserPassword}@${id}:6379 --raw CONFIG SET requirepass ${newPassword}` | ||||||
| 			}); | 			}); | ||||||
| @ -1370,7 +1445,7 @@ export async function startTraefikTCPProxy( | |||||||
| 	}); | 	}); | ||||||
| 	try { | 	try { | ||||||
| 		if (foundDependentContainer && !found) { | 		if (foundDependentContainer && !found) { | ||||||
| 			const { stdout: Config } = await executeDockerCmd({ | 			const { stdout: Config } = await executeCommand({ | ||||||
| 				dockerId, | 				dockerId, | ||||||
| 				command: `docker network inspect ${network} --format '{{json .IPAM.Config }}'` | 				command: `docker network inspect ${network} --format '{{json .IPAM.Config }}'` | ||||||
| 			}); | 			}); | ||||||
| @ -1417,16 +1492,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 executeDockerCmd({ | 			await executeCommand({ | ||||||
| 				dockerId, | 				dockerId, | ||||||
| 				command: `docker compose -f /tmp/docker-compose-${id}.yaml up -d` | 				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) { | ||||||
| 			await executeDockerCmd({ | 			await executeCommand({ | ||||||
| 				dockerId, | 				dockerId, | ||||||
| 				command: `docker stop -t 0 ${container} && docker rm ${container}` | 				command: `docker stop -t 0 ${container} && docker rm ${container}`, | ||||||
|  | 				shell: true | ||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
| 	} catch (error) { | 	} catch (error) { | ||||||
| @ -1537,7 +1613,7 @@ export async function stopBuild(buildId, applicationId) { | |||||||
| 					await cleanupDB(buildId, applicationId); | 					await cleanupDB(buildId, applicationId); | ||||||
| 					return reject(new Error('Canceled.')); | 					return reject(new Error('Canceled.')); | ||||||
| 				} | 				} | ||||||
| 				const { stdout: buildContainers } = await executeDockerCmd({ | 				const { stdout: buildContainers } = await executeCommand({ | ||||||
| 					dockerId, | 					dockerId, | ||||||
| 					command: `docker container ls --filter "label=coolify.buildId=${buildId}" --format '{{json .}}'` | 					command: `docker container ls --filter "label=coolify.buildId=${buildId}" --format '{{json .}}'` | ||||||
| 				}); | 				}); | ||||||
| @ -1580,26 +1656,28 @@ export function convertTolOldVolumeNames(type) { | |||||||
| export async function cleanupDockerStorage(dockerId, lowDiskSpace, force) { | export async function cleanupDockerStorage(dockerId, lowDiskSpace, force) { | ||||||
| 	// Cleanup old coolify images
 | 	// Cleanup old coolify images
 | ||||||
| 	try { | 	try { | ||||||
| 		let { stdout: images } = await executeDockerCmd({ | 		let { stdout: images } = await executeCommand({ | ||||||
| 			dockerId, | 			dockerId, | ||||||
| 			command: `docker images coollabsio/coolify --filter before="coollabsio/coolify:${version}" -q | xargs -r` | 			command: `docker images coollabsio/coolify --filter before="coollabsio/coolify:${version}" -q | xargs -r`, | ||||||
|  | 			shell: true | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
| 		images = images.trim(); | 		images = images.trim(); | ||||||
| 		if (images) { | 		if (images) { | ||||||
| 			await executeDockerCmd({ dockerId, command: `docker rmi -f ${images}" -q | xargs -r` }); | 			await executeCommand({ dockerId, command: `docker rmi -f ${images}" -q | xargs -r`, shell: true }); | ||||||
| 		} | 		} | ||||||
| 	} catch (error) { } | 	} catch (error) { } | ||||||
| 	if (lowDiskSpace || force) { | 	if (lowDiskSpace || force) { | ||||||
| 		// Cleanup images that are not used
 | 		// Cleanup images that are not used
 | ||||||
| 		try { | 		try { | ||||||
| 			await executeDockerCmd({ dockerId, command: `docker image prune -f` }); | 			await executeCommand({ dockerId, command: `docker image prune -f` }); | ||||||
| 		} catch (error) { } | 		} catch (error) { } | ||||||
| 
 | 
 | ||||||
| 		const { numberOfDockerImagesKeptLocally } = await prisma.setting.findUnique({ where: { id: '0' } }) | 		const { numberOfDockerImagesKeptLocally } = await prisma.setting.findUnique({ where: { id: '0' } }) | ||||||
| 		const { stdout: images } = await executeDockerCmd({ | 		const { stdout: images } = await executeCommand({ | ||||||
| 			dockerId, | 			dockerId, | ||||||
| 			command: `docker images | grep -v "<none>" | grep -v REPOSITORY | awk '{print $1, $2}'` | 			command: `docker images | grep -v "<none>" | grep -v REPOSITORY | awk '{print $1, $2}'`, | ||||||
|  | 			shell: true | ||||||
| 		}); | 		}); | ||||||
| 		const imagesArray = images.trim().replaceAll(' ', ':').split('\n'); | 		const imagesArray = images.trim().replaceAll(' ', ':').split('\n'); | ||||||
| 		const imagesSet = new Set(imagesArray.map((image) => image.split(':')[0])); | 		const imagesSet = new Set(imagesArray.map((image) => image.split(':')[0])); | ||||||
| @ -1618,12 +1696,12 @@ export async function cleanupDockerStorage(dockerId, lowDiskSpace, force) { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		for (const image of deleteImage) { | 		for (const image of deleteImage) { | ||||||
| 			await executeDockerCmd({ dockerId, command: `docker image rm -f ${image}` }); | 			await executeCommand({ dockerId, command: `docker image rm -f ${image}` }); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Prune coolify managed containers
 | 		// Prune coolify managed containers
 | ||||||
| 		try { | 		try { | ||||||
| 			await executeDockerCmd({ | 			await executeCommand({ | ||||||
| 				dockerId, | 				dockerId, | ||||||
| 				command: `docker container prune -f --filter "label=coolify.managed=true"` | 				command: `docker container prune -f --filter "label=coolify.managed=true"` | ||||||
| 			}); | 			}); | ||||||
| @ -1631,7 +1709,7 @@ export async function cleanupDockerStorage(dockerId, lowDiskSpace, force) { | |||||||
| 
 | 
 | ||||||
| 		// Cleanup build caches
 | 		// Cleanup build caches
 | ||||||
| 		try { | 		try { | ||||||
| 			await executeDockerCmd({ dockerId, command: `docker builder prune -a -f` }); | 			await executeCommand({ dockerId, command: `docker builder prune -a -f` }); | ||||||
| 		} catch (error) { } | 		} catch (error) { } | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -1718,11 +1796,11 @@ export async function pushToRegistry(application: any, workdir: string, tag: str | |||||||
| 	const location = `${workdir}/.docker` | 	const location = `${workdir}/.docker` | ||||||
| 	const tagCommand = `docker tag ${application.id}:${tag} ${imageName}:${customTag}` | 	const tagCommand = `docker tag ${application.id}:${tag} ${imageName}:${customTag}` | ||||||
| 	const pushCommand = `docker --config ${location} push ${imageName}:${customTag}` | 	const pushCommand = `docker --config ${location} push ${imageName}:${customTag}` | ||||||
| 	await executeDockerCmd({ | 	await executeCommand({ | ||||||
| 		dockerId: application.destinationDockerId, | 		dockerId: application.destinationDockerId, | ||||||
| 		command: tagCommand | 		command: tagCommand | ||||||
| 	}) | 	}) | ||||||
| 	await executeDockerCmd({ | 	await executeCommand({ | ||||||
| 		dockerId: application.destinationDockerId, | 		dockerId: application.destinationDockerId, | ||||||
| 		command: pushCommand | 		command: pushCommand | ||||||
| 	}) | 	}) | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| import { executeDockerCmd } from './common'; | import { executeCommand } from './common'; | ||||||
| 
 | 
 | ||||||
| export function formatLabelsOnDocker(data) { | export function formatLabelsOnDocker(data) { | ||||||
| 	return data.trim().split('\n').map(a => JSON.parse(a)).map((container) => { | 	return data.trim().split('\n').map(a => JSON.parse(a)).map((container) => { | ||||||
| @ -16,7 +16,7 @@ export function formatLabelsOnDocker(data) { | |||||||
| export async function checkContainer({ dockerId, container, remove = false }: { dockerId: string, container: string, remove?: boolean }): Promise<{ found: boolean, status?: { isExited: boolean, isRunning: boolean, isRestarting: boolean } }> { | export async function checkContainer({ dockerId, container, remove = false }: { dockerId: string, container: string, remove?: boolean }): Promise<{ found: boolean, status?: { isExited: boolean, isRunning: boolean, isRestarting: boolean } }> { | ||||||
| 	let containerFound = false; | 	let containerFound = false; | ||||||
| 	try { | 	try { | ||||||
| 		const { stdout } = await executeDockerCmd({ | 		const { stdout } = await executeCommand({ | ||||||
| 			dockerId, | 			dockerId, | ||||||
| 			command: | 			command: | ||||||
| 				`docker inspect --format '{{json .State}}' ${container}` | 				`docker inspect --format '{{json .State}}' ${container}` | ||||||
| @ -28,14 +28,14 @@ export async function checkContainer({ dockerId, container, remove = false }: { | |||||||
| 		const isRestarting = status === 'restarting' | 		const isRestarting = status === 'restarting' | ||||||
| 		const isExited = status === 'exited' | 		const isExited = status === 'exited' | ||||||
| 		if (status === 'created') { | 		if (status === 'created') { | ||||||
| 			await executeDockerCmd({ | 			await executeCommand({ | ||||||
| 				dockerId, | 				dockerId, | ||||||
| 				command: | 				command: | ||||||
| 					`docker rm ${container}` | 					`docker rm ${container}` | ||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
| 		if (remove && status === 'exited') { | 		if (remove && status === 'exited') { | ||||||
| 			await executeDockerCmd({ | 			await executeCommand({ | ||||||
| 				dockerId, | 				dockerId, | ||||||
| 				command: | 				command: | ||||||
| 					`docker rm ${container}` | 					`docker rm ${container}` | ||||||
| @ -62,7 +62,7 @@ export async function checkContainer({ dockerId, container, remove = false }: { | |||||||
| export async function isContainerExited(dockerId: string, containerName: string): Promise<boolean> { | export async function isContainerExited(dockerId: string, containerName: string): Promise<boolean> { | ||||||
| 	let isExited = false; | 	let isExited = false; | ||||||
| 	try { | 	try { | ||||||
| 		const { stdout } = await executeDockerCmd({ dockerId, command: `docker inspect -f '{{.State.Status}}' ${containerName}` }) | 		const { stdout } = await executeCommand({ dockerId, command: `docker inspect -f '{{.State.Status}}' ${containerName}` }) | ||||||
| 		if (stdout.trim() === 'exited') { | 		if (stdout.trim() === 'exited') { | ||||||
| 			isExited = true; | 			isExited = true; | ||||||
| 		} | 		} | ||||||
| @ -81,13 +81,13 @@ export async function removeContainer({ | |||||||
| 	dockerId: string; | 	dockerId: string; | ||||||
| }): Promise<void> { | }): Promise<void> { | ||||||
| 	try { | 	try { | ||||||
| 		const { stdout } = await executeDockerCmd({ dockerId, command: `docker inspect --format '{{json .State}}' ${id}` }) | 		const { stdout } = await executeCommand({ dockerId, command: `docker inspect --format '{{json .State}}' ${id}` }) | ||||||
| 		if (JSON.parse(stdout).Running) { | 		if (JSON.parse(stdout).Running) { | ||||||
| 			await executeDockerCmd({ dockerId, command: `docker stop -t 0 ${id}` }) | 			await executeCommand({ dockerId, command: `docker stop -t 0 ${id}` }) | ||||||
| 			await executeDockerCmd({ dockerId, command: `docker rm ${id}` }) | 			await executeCommand({ dockerId, command: `docker rm ${id}` }) | ||||||
| 		} | 		} | ||||||
| 		if (JSON.parse(stdout).Status === 'exited') { | 		if (JSON.parse(stdout).Status === 'exited') { | ||||||
| 			await executeDockerCmd({ dockerId, command: `docker rm ${id}` }) | 			await executeCommand({ dockerId, command: `docker rm ${id}` }) | ||||||
| 		} | 		} | ||||||
| 	} catch (error) { | 	} catch (error) { | ||||||
| 		throw error; | 		throw error; | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| 
 | 
 | ||||||
| import jsonwebtoken from 'jsonwebtoken'; | import jsonwebtoken from 'jsonwebtoken'; | ||||||
| import { saveBuildLog } from '../buildPacks/common'; | import { saveBuildLog } from '../buildPacks/common'; | ||||||
| import { asyncExecShell, decrypt, prisma } from '../common'; | import { decrypt, executeCommand, prisma } from '../common'; | ||||||
| 
 | 
 | ||||||
| export default async function ({ | export default async function ({ | ||||||
| 	applicationId, | 	applicationId, | ||||||
| @ -43,9 +43,11 @@ export default async function ({ | |||||||
| 				applicationId | 				applicationId | ||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
| 		await asyncExecShell( | 		await executeCommand({ | ||||||
| 			`git clone -q -b ${branch} https://${url}/${repository}.git ${workdir}/ && cd ${workdir} && git checkout ${gitCommitHash || ""} && git submodule update --init --recursive && git lfs pull && cd .. ` | 			command: | ||||||
| 		); | 				`git clone -q -b ${branch} https://${url}/${repository}.git ${workdir}/ && cd ${workdir} && git checkout ${gitCommitHash || ""} && git submodule update --init --recursive && git lfs pull && cd .. `, | ||||||
|  | 			shell: true | ||||||
|  | 		}); | ||||||
| 
 | 
 | ||||||
| 	} else { | 	} else { | ||||||
| 		const body = await prisma.githubApp.findUnique({ where: { id: githubAppId } }); | 		const body = await prisma.githubApp.findUnique({ where: { id: githubAppId } }); | ||||||
| @ -81,11 +83,13 @@ export default async function ({ | |||||||
| 				applicationId | 				applicationId | ||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
| 		await asyncExecShell( | 		await executeCommand({ | ||||||
| 			`git clone -q -b ${branch} https://x-access-token:${token}@${url}/${repository}.git --config core.sshCommand="ssh -p ${customPort}" ${workdir}/ && cd ${workdir} && git checkout ${gitCommitHash || ""} && git submodule update --init --recursive && git lfs pull && cd .. ` | 			command: | ||||||
| 		); | 				`git clone -q -b ${branch} https://x-access-token:${token}@${url}/${repository}.git --config core.sshCommand="ssh -p ${customPort}" ${workdir}/ && cd ${workdir} && git checkout ${gitCommitHash || ""} && git submodule update --init --recursive && git lfs pull && cd .. `, | ||||||
|  | 			shell: true | ||||||
|  | 		}); | ||||||
| 	} | 	} | ||||||
| 	const { stdout: commit } = await asyncExecShell(`cd ${workdir}/ && git rev-parse HEAD`); | 	const { stdout: commit } = await executeCommand({ command: `cd ${workdir}/ && git rev-parse HEAD`, shell: true }); | ||||||
| 
 | 	console.log({ commit }) | ||||||
| 	return commit.replace('\n', ''); | 	return commit.replace('\n', ''); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { saveBuildLog } from "../buildPacks/common"; | import { saveBuildLog } from "../buildPacks/common"; | ||||||
| import { asyncExecShell } from "../common"; | import {  executeCommand } from "../common"; | ||||||
| 
 | 
 | ||||||
| export default async function ({ | export default async function ({ | ||||||
| 	applicationId, | 	applicationId, | ||||||
| @ -28,8 +28,8 @@ export default async function ({ | |||||||
| }): Promise<string> { | }): Promise<string> { | ||||||
| 	const url = htmlUrl.replace('https://', '').replace('http://', '').replace(/\/$/, ''); | 	const url = htmlUrl.replace('https://', '').replace('http://', '').replace(/\/$/, ''); | ||||||
| 	if (!forPublic) { | 	if (!forPublic) { | ||||||
| 		await asyncExecShell(`echo '${privateSshKey}' > ${repodir}/id.rsa`); | 		await executeCommand({ command: `echo '${privateSshKey}' > ${repodir}/id.rsa`, shell: true }); | ||||||
| 		await asyncExecShell(`chmod 600 ${repodir}/id.rsa`); | 		await executeCommand({ command: `chmod 600 ${repodir}/id.rsa` }); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	await saveBuildLog({ | 	await saveBuildLog({ | ||||||
| @ -45,15 +45,19 @@ export default async function ({ | |||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
| 	if (forPublic) { | 	if (forPublic) { | ||||||
| 		await asyncExecShell( | 		await executeCommand({ | ||||||
| 			`git clone -q -b ${branch} https://${url}/${repository}.git ${workdir}/ && cd ${workdir}/ && git checkout ${gitCommitHash || ""} && git submodule update --init --recursive && git lfs pull && cd .. ` | 			command: | ||||||
|  | 				`git clone -q -b ${branch} https://${url}/${repository}.git ${workdir}/ && cd ${workdir}/ && git checkout ${gitCommitHash || ""} && git submodule update --init --recursive && git lfs pull && cd .. `, shell: true | ||||||
|  | 		} | ||||||
| 		); | 		); | ||||||
| 	} else { | 	} else { | ||||||
| 		await asyncExecShell( | 		await executeCommand({ | ||||||
| 			`git clone -q -b ${branch} git@${url}:${repository}.git --config core.sshCommand="ssh -p ${customPort} -q -i ${repodir}id.rsa -o StrictHostKeyChecking=no" ${workdir}/ && cd ${workdir}/ && git checkout ${gitCommitHash || ""} && git submodule update --init --recursive && git lfs pull && cd .. ` | 			command: | ||||||
|  | 				`git clone -q -b ${branch} git@${url}:${repository}.git --config core.sshCommand="ssh -p ${customPort} -q -i ${repodir}id.rsa -o StrictHostKeyChecking=no" ${workdir}/ && cd ${workdir}/ && git checkout ${gitCommitHash || ""} && git submodule update --init --recursive && git lfs pull && cd .. `, shell: true | ||||||
|  | 		} | ||||||
| 		); | 		); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	const { stdout: commit } = await asyncExecShell(`cd ${workdir}/ && git rev-parse HEAD`); | 	const { stdout: commit } = await executeCommand({ command: `cd ${workdir}/ && git rev-parse HEAD`, shell: true }); | ||||||
| 	return commit.replace('\n', ''); | 	return commit.replace('\n', ''); | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ import type { FastifyReply, FastifyRequest } from 'fastify'; | |||||||
| import fs from 'fs/promises'; | import fs from 'fs/promises'; | ||||||
| import yaml from 'js-yaml'; | import yaml from 'js-yaml'; | ||||||
| import path from 'path'; | import path from 'path'; | ||||||
| import { asyncSleep, ComposeFile, createDirectories, decrypt, defaultComposeConfiguration, errorHandler, executeDockerCmd, getServiceFromDB, isARM, makeLabelForServices, persistentVolumes, prisma, stopTcpHttpProxy } from '../common'; | import { asyncSleep, ComposeFile, createDirectories, decrypt, defaultComposeConfiguration, errorHandler, executeCommand, getServiceFromDB, isARM, makeLabelForServices, persistentVolumes, prisma, stopTcpHttpProxy } from '../common'; | ||||||
| import { parseAndFindServiceTemplates } from '../../routes/api/v1/services/handlers'; | import { parseAndFindServiceTemplates } from '../../routes/api/v1/services/handlers'; | ||||||
| 
 | 
 | ||||||
| import { ServiceStartStop } from '../../routes/api/v1/services/types'; | import { ServiceStartStop } from '../../routes/api/v1/services/types'; | ||||||
| @ -15,14 +15,19 @@ export async function stopService(request: FastifyRequest<ServiceStartStop>) { | |||||||
|         const teamId = request.user.teamId; |         const teamId = request.user.teamId; | ||||||
|         const { destinationDockerId } = await getServiceFromDB({ id, teamId }); |         const { destinationDockerId } = await getServiceFromDB({ id, teamId }); | ||||||
|         if (destinationDockerId) { |         if (destinationDockerId) { | ||||||
|             await executeDockerCmd({ |             const { stdout: containers } = await executeCommand({ | ||||||
|                 dockerId: destinationDockerId, |                 dockerId: destinationDockerId, | ||||||
|                 command: `docker ps -a --filter 'label=com.docker.compose.project=${id}' --format {{.ID}}|xargs -r -n 1 docker stop -t 0` |                 command: `docker ps -a --filter 'label=com.docker.compose.project=${id}' --format {{.ID}}` | ||||||
|             }) |  | ||||||
|             await executeDockerCmd({ |  | ||||||
|                 dockerId: destinationDockerId, |  | ||||||
|                 command: `docker ps -a --filter 'label=com.docker.compose.project=${id}' --format {{.ID}}|xargs -r -n 1 docker rm --force` |  | ||||||
|             }) |             }) | ||||||
|  |             if (containers) { | ||||||
|  |                 const containerArray = containers.split('\n'); | ||||||
|  |                 if (containerArray.length > 0) { | ||||||
|  |                     for (const container of containerArray) { | ||||||
|  |                         await executeCommand({ dockerId: destinationDockerId, command: `docker stop -t 0 ${container}` }) | ||||||
|  |                         await executeCommand({ dockerId: destinationDockerId, command: `docker rm --force ${container}` }) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|             return {} |             return {} | ||||||
|         } |         } | ||||||
|         throw { status: 500, message: 'Could not stop containers.' } |         throw { status: 500, message: 'Could not stop containers.' } | ||||||
| @ -182,19 +187,36 @@ export async function startService(request: FastifyRequest<ServiceStartStop>, fa | |||||||
|         // Workaround: Stop old minio proxies
 |         // Workaround: Stop old minio proxies
 | ||||||
|         if (service.type === 'minio') { |         if (service.type === 'minio') { | ||||||
|             try { |             try { | ||||||
|                 await executeDockerCmd({ |                 const { stdout: containers } = await executeCommand({ | ||||||
|                     dockerId: destinationDocker.id, |                     dockerId: destinationDocker.id, | ||||||
|                     command: |                     command: | ||||||
|                         `docker container ls -a --filter 'name=${id}-' --format {{.ID}}|xargs -r -n 1 docker container stop -t 0` |                         `docker container ls -a --filter 'name=${id}-' --format {{.ID}}` | ||||||
|                 }); |                 }); | ||||||
| 
 |                 if (containers) { | ||||||
|  |                     const containerArray = containers.split('\n'); | ||||||
|  |                     if (containerArray.length > 0) { | ||||||
|  |                         for (const container of containerArray) { | ||||||
|  |                             await executeCommand({ dockerId: destinationDockerId, command: `docker stop -t 0 ${container}` }) | ||||||
|  |                             await executeCommand({ dockerId: destinationDockerId, command: `docker rm --force ${container}` }) | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|             } catch (error) { } |             } catch (error) { } | ||||||
|             try { |             try { | ||||||
|                 await executeDockerCmd({ |                 const { stdout: containers } = await executeCommand({ | ||||||
|                     dockerId: destinationDocker.id, |                     dockerId: destinationDocker.id, | ||||||
|                     command: |                     command: | ||||||
|                         `docker container ls -a --filter 'name=${id}-' --format {{.ID}}|xargs -r -n 1 docker container rm -f` |                         `docker container ls -a --filter 'name=${id}-' --format {{.ID}}` | ||||||
|                 }); |                 }); | ||||||
|  |                 if (containers) { | ||||||
|  |                     const containerArray = containers.split('\n'); | ||||||
|  |                     if (containerArray.length > 0) { | ||||||
|  |                         for (const container of containerArray) { | ||||||
|  |                             await executeCommand({ dockerId: destinationDockerId, command: `docker stop -t 0 ${container}` }) | ||||||
|  |                             await executeCommand({ dockerId: destinationDockerId, command: `docker rm --force ${container}` }) | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|             } catch (error) { } |             } catch (error) { } | ||||||
|         } |         } | ||||||
|         return {} |         return {} | ||||||
| @ -205,16 +227,16 @@ export async function startService(request: FastifyRequest<ServiceStartStop>, fa | |||||||
| async function startServiceContainers(fastify, id, teamId, dockerId, composeFileDestination) { | async function startServiceContainers(fastify, id, teamId, dockerId, composeFileDestination) { | ||||||
|     try { |     try { | ||||||
|         fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 'Pulling images...' }) |         fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 'Pulling images...' }) | ||||||
|         await executeDockerCmd({ dockerId, command: `docker compose -f ${composeFileDestination} pull` }) |         await executeCommand({ dockerId, command: `docker compose -f ${composeFileDestination} pull` }) | ||||||
|     } catch (error) { } |     } catch (error) { } | ||||||
|     fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 'Building images...' }) |     fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 'Building images...' }) | ||||||
|     await executeDockerCmd({ dockerId, command: `docker compose -f ${composeFileDestination} build --no-cache` }) |     await executeCommand({ dockerId, command: `docker compose -f ${composeFileDestination} build --no-cache` }) | ||||||
|     fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 'Creating containers...' }) |     fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 'Creating containers...' }) | ||||||
|     await executeDockerCmd({ dockerId, command: `docker compose -f ${composeFileDestination} create` }) |     await executeCommand({ dockerId, command: `docker compose -f ${composeFileDestination} create` }) | ||||||
|     fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 'Starting containers...' }) |     fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 'Starting containers...' }) | ||||||
|     await executeDockerCmd({ dockerId, command: `docker compose -f ${composeFileDestination} start` }) |     await executeCommand({ dockerId, command: `docker compose -f ${composeFileDestination} start` }) | ||||||
|     await asyncSleep(1000); |     await asyncSleep(1000); | ||||||
|     await executeDockerCmd({ dockerId, command: `docker compose -f ${composeFileDestination} up -d` }) |     await executeCommand({ dockerId, command: `docker compose -f ${composeFileDestination} up -d` }) | ||||||
|     fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 0 }) |     fastify.io.to(teamId).emit(`start-service`, { serviceId: id, state: 0 }) | ||||||
| } | } | ||||||
| export async function migrateAppwriteDB(request: FastifyRequest<OnlyId>, reply: FastifyReply) { | export async function migrateAppwriteDB(request: FastifyRequest<OnlyId>, reply: FastifyReply) { | ||||||
| @ -226,7 +248,7 @@ export async function migrateAppwriteDB(request: FastifyRequest<OnlyId>, reply: | |||||||
|             destinationDocker, |             destinationDocker, | ||||||
|         } = await getServiceFromDB({ id, teamId }); |         } = await getServiceFromDB({ id, teamId }); | ||||||
|         if (destinationDockerId) { |         if (destinationDockerId) { | ||||||
|             await executeDockerCmd({ |             await executeCommand({ | ||||||
|                 dockerId: destinationDocker.id, |                 dockerId: destinationDocker.id, | ||||||
|                 command: `docker exec ${id} migrate` |                 command: `docker exec ${id} migrate` | ||||||
|             }) |             }) | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ import csv from 'csvtojson'; | |||||||
| 
 | 
 | ||||||
| import { day } from '../../../../lib/dayjs'; | import { day } from '../../../../lib/dayjs'; | ||||||
| import { saveDockerRegistryCredentials, setDefaultBaseImage, setDefaultConfiguration } from '../../../../lib/buildPacks/common'; | import { saveDockerRegistryCredentials, setDefaultBaseImage, setDefaultConfiguration } from '../../../../lib/buildPacks/common'; | ||||||
| import { checkDomainsIsValidInDNS, checkExposedPort, createDirectories, decrypt, defaultComposeConfiguration, encrypt, errorHandler, executeDockerCmd, generateSshKeyPair, getContainerUsage, getDomain, isDev, isDomainConfigured, listSettings, prisma, stopBuild, uniqueName } from '../../../../lib/common'; | import { checkDomainsIsValidInDNS, checkExposedPort, createDirectories, decrypt, defaultComposeConfiguration, encrypt, errorHandler, executeCommand, generateSshKeyPair, getContainerUsage, getDomain, isDev, isDomainConfigured, listSettings, prisma, stopBuild, uniqueName } from '../../../../lib/common'; | ||||||
| import { checkContainer, formatLabelsOnDocker, removeContainer } from '../../../../lib/docker'; | import { checkContainer, formatLabelsOnDocker, removeContainer } from '../../../../lib/docker'; | ||||||
| 
 | 
 | ||||||
| import type { FastifyRequest } from 'fastify'; | import type { FastifyRequest } from 'fastify'; | ||||||
| @ -78,7 +78,7 @@ export async function cleanupUnconfiguredApplications(request: FastifyRequest<an | |||||||
|         for (const application of applications) { |         for (const application of applications) { | ||||||
|             if (!application.buildPack || !application.destinationDockerId || !application.branch || (!application.settings?.isBot && !application?.fqdn)) { |             if (!application.buildPack || !application.destinationDockerId || !application.branch || (!application.settings?.isBot && !application?.fqdn)) { | ||||||
|                 if (application?.destinationDockerId && application.destinationDocker?.network) { |                 if (application?.destinationDockerId && application.destinationDocker?.network) { | ||||||
|                     const { stdout: containers } = await executeDockerCmd({ |                     const { stdout: containers } = await executeCommand({ | ||||||
|                         dockerId: application.destinationDocker.id, |                         dockerId: application.destinationDocker.id, | ||||||
|                         command: `docker ps -a --filter network=${application.destinationDocker.network} --filter name=${application.id} --format '{{json .}}'` |                         command: `docker ps -a --filter network=${application.destinationDocker.network} --filter name=${application.id} --format '{{json .}}'` | ||||||
|                     }) |                     }) | ||||||
| @ -113,7 +113,7 @@ export async function getApplicationStatus(request: FastifyRequest<OnlyId>) { | |||||||
|         const application: any = await getApplicationFromDB(id, teamId); |         const application: any = await getApplicationFromDB(id, teamId); | ||||||
|         if (application?.destinationDockerId) { |         if (application?.destinationDockerId) { | ||||||
|             if (application.buildPack === 'compose') { |             if (application.buildPack === 'compose') { | ||||||
|                 const { stdout: containers } = await executeDockerCmd({ |                 const { stdout: containers } = await executeCommand({ | ||||||
|                     dockerId: application.destinationDocker.id, |                     dockerId: application.destinationDocker.id, | ||||||
|                     command: |                     command: | ||||||
|                         `docker ps -a --filter "label=coolify.applicationId=${id}" --format '{{json .}}'` |                         `docker ps -a --filter "label=coolify.applicationId=${id}" --format '{{json .}}'` | ||||||
| @ -485,7 +485,7 @@ export async function restartApplication(request: FastifyRequest<RestartApplicat | |||||||
|             if (imageId) { |             if (imageId) { | ||||||
|                 image = imageId |                 image = imageId | ||||||
|             } else { |             } else { | ||||||
|                 const { stdout: container } = await executeDockerCmd({ dockerId, command: `docker container ls --filter 'label=com.docker.compose.service=${id}' --format '{{json .}}'` }) |                 const { stdout: container } = await executeCommand({ dockerId, command: `docker container ls --filter 'label=com.docker.compose.service=${id}' --format '{{json .}}'` }) | ||||||
|                 const containersArray = container.trim().split('\n'); |                 const containersArray = container.trim().split('\n'); | ||||||
|                 for (const container of containersArray) { |                 for (const container of containersArray) { | ||||||
|                     const containerObj = formatLabelsOnDocker(container); |                     const containerObj = formatLabelsOnDocker(container); | ||||||
| @ -504,7 +504,7 @@ export async function restartApplication(request: FastifyRequest<RestartApplicat | |||||||
| 
 | 
 | ||||||
|             let imageFoundLocally = false; |             let imageFoundLocally = false; | ||||||
|             try { |             try { | ||||||
|                 await executeDockerCmd({ |                 await executeCommand({ | ||||||
|                     dockerId, |                     dockerId, | ||||||
|                     command: `docker image inspect ${image}` |                     command: `docker image inspect ${image}` | ||||||
|                 }) |                 }) | ||||||
| @ -514,7 +514,7 @@ export async function restartApplication(request: FastifyRequest<RestartApplicat | |||||||
|             } |             } | ||||||
|             let imageFoundRemotely = false; |             let imageFoundRemotely = false; | ||||||
|             try { |             try { | ||||||
|                 await executeDockerCmd({ |                 await executeCommand({ | ||||||
|                     dockerId, |                     dockerId, | ||||||
|                     command: `docker ${location ? `--config ${location}` : ''} pull ${image}` |                     command: `docker ${location ? `--config ${location}` : ''} pull ${image}` | ||||||
|                 }) |                 }) | ||||||
| @ -570,13 +570,13 @@ export async function restartApplication(request: FastifyRequest<RestartApplicat | |||||||
|             }; |             }; | ||||||
|             await fs.writeFile(`${workdir}/docker-compose.yml`, yaml.dump(composeFile)); |             await fs.writeFile(`${workdir}/docker-compose.yml`, yaml.dump(composeFile)); | ||||||
|             try { |             try { | ||||||
|                 await executeDockerCmd({ dockerId, command: `docker stop -t 0 ${id}` }) |                 await executeCommand({ dockerId, command: `docker stop -t 0 ${id}` }) | ||||||
|                 await executeDockerCmd({ dockerId, command: `docker rm ${id}` }) |                 await executeCommand({ dockerId, command: `docker rm ${id}` }) | ||||||
|             } catch (error) { |             } catch (error) { | ||||||
|                 //
 |                 //
 | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             await executeDockerCmd({ dockerId, command: `docker compose --project-directory ${workdir} up -d` }) |             await executeCommand({ dockerId, command: `docker compose --project-directory ${workdir} up -d` }) | ||||||
|             return reply.code(201).send(); |             return reply.code(201).send(); | ||||||
|         } |         } | ||||||
|         throw { status: 500, message: 'Application cannot be restarted.' } |         throw { status: 500, message: 'Application cannot be restarted.' } | ||||||
| @ -592,7 +592,7 @@ export async function stopApplication(request: FastifyRequest<OnlyId>, reply: Fa | |||||||
|         if (application?.destinationDockerId) { |         if (application?.destinationDockerId) { | ||||||
|             const { id: dockerId } = application.destinationDocker; |             const { id: dockerId } = application.destinationDocker; | ||||||
|             if (application.buildPack === 'compose') { |             if (application.buildPack === 'compose') { | ||||||
|                 const { stdout: containers } = await executeDockerCmd({ |                 const { stdout: containers } = await executeCommand({ | ||||||
|                     dockerId: application.destinationDocker.id, |                     dockerId: application.destinationDocker.id, | ||||||
|                     command: |                     command: | ||||||
|                         `docker ps -a --filter "label=coolify.applicationId=${id}" --format '{{json .}}'` |                         `docker ps -a --filter "label=coolify.applicationId=${id}" --format '{{json .}}'` | ||||||
| @ -627,7 +627,7 @@ export async function deleteApplication(request: FastifyRequest<DeleteApplicatio | |||||||
|             include: { destinationDocker: true } |             include: { destinationDocker: true } | ||||||
|         }); |         }); | ||||||
|         if (!force && application?.destinationDockerId && application.destinationDocker?.network) { |         if (!force && application?.destinationDockerId && application.destinationDocker?.network) { | ||||||
|             const { stdout: containers } = await executeDockerCmd({ |             const { stdout: containers } = await executeCommand({ | ||||||
|                 dockerId: application.destinationDocker.id, |                 dockerId: application.destinationDocker.id, | ||||||
|                 command: `docker ps -a --filter network=${application.destinationDocker.network} --filter name=${id} --format '{{json .}}'` |                 command: `docker ps -a --filter network=${application.destinationDocker.network} --filter name=${id} --format '{{json .}}'` | ||||||
|             }) |             }) | ||||||
| @ -720,8 +720,8 @@ export async function getDockerImages(request) { | |||||||
|         const application: any = await getApplicationFromDB(id, teamId); |         const application: any = await getApplicationFromDB(id, teamId); | ||||||
|         let imagesAvailables = []; |         let imagesAvailables = []; | ||||||
|         try { |         try { | ||||||
|             const { stdout } = await executeDockerCmd({ dockerId: application.destinationDocker.id, command: `docker images --format '{{.Repository}}#{{.Tag}}#{{.CreatedAt}}' | grep -i ${id} | grep -v cache` }); |             const { stdout } = await executeCommand({ dockerId: application.destinationDocker.id, command: `docker images --format '{{.Repository}}#{{.Tag}}#{{.CreatedAt}}' | grep -i ${id} | grep -v cache`, shell: true }); | ||||||
|             const { stdout: runningImage } = await executeDockerCmd({ dockerId: application.destinationDocker.id, command: `docker ps -a --filter 'label=com.docker.compose.service=${id}' --format {{.Image}}` }); |             const { stdout: runningImage } = await executeCommand({ dockerId: application.destinationDocker.id, command: `docker ps -a --filter 'label=com.docker.compose.service=${id}' --format {{.Image}}` }); | ||||||
|             const images = stdout.trim().split('\n'); |             const images = stdout.trim().split('\n'); | ||||||
| 
 | 
 | ||||||
|             for (const image of images) { |             for (const image of images) { | ||||||
| @ -1184,7 +1184,7 @@ export async function restartPreview(request: FastifyRequest<RestartPreviewAppli | |||||||
|             const { workdir } = await createDirectories({ repository, buildId }); |             const { workdir } = await createDirectories({ repository, buildId }); | ||||||
|             const labels = [] |             const labels = [] | ||||||
|             let image = null |             let image = null | ||||||
|             const { stdout: container } = await executeDockerCmd({ dockerId, command: `docker container ls --filter 'label=com.docker.compose.service=${id}-${pullmergeRequestId}' --format '{{json .}}'` }) |             const { stdout: container } = await executeCommand({ dockerId, command: `docker container ls --filter 'label=com.docker.compose.service=${id}-${pullmergeRequestId}' --format '{{json .}}'` }) | ||||||
|             const containersArray = container.trim().split('\n'); |             const containersArray = container.trim().split('\n'); | ||||||
|             for (const container of containersArray) { |             for (const container of containersArray) { | ||||||
|                 const containerObj = formatLabelsOnDocker(container); |                 const containerObj = formatLabelsOnDocker(container); | ||||||
| @ -1197,7 +1197,7 @@ export async function restartPreview(request: FastifyRequest<RestartPreviewAppli | |||||||
|             } |             } | ||||||
|             let imageFound = false; |             let imageFound = false; | ||||||
|             try { |             try { | ||||||
|                 await executeDockerCmd({ |                 await executeCommand({ | ||||||
|                     dockerId, |                     dockerId, | ||||||
|                     command: `docker image inspect ${image}` |                     command: `docker image inspect ${image}` | ||||||
|                 }) |                 }) | ||||||
| @ -1251,9 +1251,9 @@ export async function restartPreview(request: FastifyRequest<RestartPreviewAppli | |||||||
|                 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 executeDockerCmd({ dockerId, command: `docker stop -t 0 ${id}-${pullmergeRequestId}` }) |             await executeCommand({ dockerId, command: `docker stop -t 0 ${id}-${pullmergeRequestId}` }) | ||||||
|             await executeDockerCmd({ dockerId, command: `docker rm ${id}-${pullmergeRequestId}` }) |             await executeCommand({ dockerId, command: `docker rm ${id}-${pullmergeRequestId}` }) | ||||||
|             await executeDockerCmd({ dockerId, command: `docker compose --project-directory ${workdir} up -d` }) |             await executeCommand({ dockerId, command: `docker compose --project-directory ${workdir} up -d` }) | ||||||
|             return reply.code(201).send(); |             return reply.code(201).send(); | ||||||
|         } |         } | ||||||
|         throw { status: 500, message: 'Application cannot be restarted.' } |         throw { status: 500, message: 'Application cannot be restarted.' } | ||||||
| @ -1294,7 +1294,7 @@ export async function loadPreviews(request: FastifyRequest<OnlyId>) { | |||||||
|     try { |     try { | ||||||
|         const { id } = request.params |         const { id } = request.params | ||||||
|         const application = await prisma.application.findUnique({ where: { id }, include: { destinationDocker: true } }); |         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 .}}"` }) |         const { stdout } = await executeCommand({ dockerId: application.destinationDocker.id, command: `docker container ls --filter 'name=${id}-' --format "{{json .}}"` }) | ||||||
|         if (stdout === '') { |         if (stdout === '') { | ||||||
|             throw { status: 500, message: 'No previews found.' } |             throw { status: 500, message: 'No previews found.' } | ||||||
|         } |         } | ||||||
| @ -1369,7 +1369,7 @@ export async function getApplicationLogs(request: FastifyRequest<GetApplicationL | |||||||
|         if (destinationDockerId) { |         if (destinationDockerId) { | ||||||
|             try { |             try { | ||||||
|                 const { default: ansi } = await import('strip-ansi') |                 const { default: ansi } = await import('strip-ansi') | ||||||
|                 const { stdout, stderr } = await executeDockerCmd({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${containerId}` }) |                 const { stdout, stderr } = await executeCommand({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${containerId}` }) | ||||||
|                 const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a); |                 const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a); | ||||||
|                 const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a); |                 const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a); | ||||||
|                 const logs = stripLogsStderr.concat(stripLogsStdout) |                 const logs = stripLogsStderr.concat(stripLogsStdout) | ||||||
| @ -1560,19 +1560,19 @@ export async function createdBranchDatabase(database: any, baseDatabaseBranch: s | |||||||
|         if (destinationDockerId) { |         if (destinationDockerId) { | ||||||
|             if (type === 'postgresql') { |             if (type === 'postgresql') { | ||||||
|                 const decryptedRootUserPassword = decrypt(rootUserPassword); |                 const decryptedRootUserPassword = decrypt(rootUserPassword); | ||||||
|                 await executeDockerCmd({ |                 await executeCommand({ | ||||||
|                     dockerId: destinationDockerId, |                     dockerId: destinationDockerId, | ||||||
|                     command: `docker exec ${id} pg_dump -d "postgresql://postgres:${decryptedRootUserPassword}@${id}:5432/${baseDatabaseBranch}" --encoding=UTF8 --schema-only -f /tmp/${baseDatabaseBranch}.dump` |                     command: `docker exec ${id} pg_dump -d "postgresql://postgres:${decryptedRootUserPassword}@${id}:5432/${baseDatabaseBranch}" --encoding=UTF8 --schema-only -f /tmp/${baseDatabaseBranch}.dump` | ||||||
|                 }) |                 }) | ||||||
|                 await executeDockerCmd({ |                 await executeCommand({ | ||||||
|                     dockerId: destinationDockerId, |                     dockerId: destinationDockerId, | ||||||
|                     command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "CREATE DATABASE branch_${pullmergeRequestId}"` |                     command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "CREATE DATABASE branch_${pullmergeRequestId}"` | ||||||
|                 }) |                 }) | ||||||
|                 await executeDockerCmd({ |                 await executeCommand({ | ||||||
|                     dockerId: destinationDockerId, |                     dockerId: destinationDockerId, | ||||||
|                     command: `docker exec ${id} psql -d "postgresql://postgres:${decryptedRootUserPassword}@${id}:5432/branch_${pullmergeRequestId}" -f /tmp/${baseDatabaseBranch}.dump` |                     command: `docker exec ${id} psql -d "postgresql://postgres:${decryptedRootUserPassword}@${id}:5432/branch_${pullmergeRequestId}" -f /tmp/${baseDatabaseBranch}.dump` | ||||||
|                 }) |                 }) | ||||||
|                 await executeDockerCmd({ |                 await executeCommand({ | ||||||
|                     dockerId: destinationDockerId, |                     dockerId: destinationDockerId, | ||||||
|                     command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "ALTER DATABASE branch_${pullmergeRequestId} OWNER TO ${dbUser}"` |                     command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "ALTER DATABASE branch_${pullmergeRequestId} OWNER TO ${dbUser}"` | ||||||
|                 }) |                 }) | ||||||
| @ -1591,12 +1591,12 @@ export async function removeBranchDatabase(database: any, pullmergeRequestId: st | |||||||
|             if (type === 'postgresql') { |             if (type === 'postgresql') { | ||||||
|                 const decryptedRootUserPassword = decrypt(rootUserPassword); |                 const decryptedRootUserPassword = decrypt(rootUserPassword); | ||||||
|                 // Terminate all connections to the database
 |                 // Terminate all connections to the database
 | ||||||
|                 await executeDockerCmd({ |                 await executeCommand({ | ||||||
|                     dockerId: destinationDockerId, |                     dockerId: destinationDockerId, | ||||||
|                     command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = 'branch_${pullmergeRequestId}' AND pid <> pg_backend_pid();"` |                     command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = 'branch_${pullmergeRequestId}' AND pid <> pg_backend_pid();"` | ||||||
|                 }) |                 }) | ||||||
| 
 | 
 | ||||||
|                 await executeDockerCmd({ |                 await executeCommand({ | ||||||
|                     dockerId: destinationDockerId, |                     dockerId: destinationDockerId, | ||||||
|                     command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "DROP DATABASE branch_${pullmergeRequestId}"` |                     command: `docker exec ${id} psql postgresql://postgres:${decryptedRootUserPassword}@${id}:5432 -c "DROP DATABASE branch_${pullmergeRequestId}"` | ||||||
|                 }) |                 }) | ||||||
|  | |||||||
| @ -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 { ComposeFile, createDirectories, decrypt, defaultComposeConfiguration, encrypt, errorHandler, executeDockerCmd, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePublicPort, listSettings, makeLabelForStandaloneDatabase, prisma, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common'; | import { ComposeFile, createDirectories, decrypt, defaultComposeConfiguration, encrypt, errorHandler, executeCommand, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePublicPort, listSettings, makeLabelForStandaloneDatabase, prisma, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common'; | ||||||
| import { day } from '../../../../lib/dayjs'; | import { day } from '../../../../lib/dayjs'; | ||||||
| 
 | 
 | ||||||
| import type { OnlyId } from '../../../../types'; | import type { OnlyId } from '../../../../types'; | ||||||
| @ -89,7 +89,7 @@ export async function getDatabaseStatus(request: FastifyRequest<OnlyId>) { | |||||||
|             const { destinationDockerId, destinationDocker } = database; |             const { destinationDockerId, destinationDocker } = database; | ||||||
|             if (destinationDockerId) { |             if (destinationDockerId) { | ||||||
|                 try { |                 try { | ||||||
|                     const { stdout } = await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker inspect --format '{{json .State}}' ${id}` }) |                     const { stdout } = await executeCommand({ dockerId: destinationDocker.id, command: `docker inspect --format '{{json .State}}' ${id}` }) | ||||||
| 
 | 
 | ||||||
|                     if (JSON.parse(stdout).Running) { |                     if (JSON.parse(stdout).Running) { | ||||||
|                         isRunning = true; |                         isRunning = true; | ||||||
| @ -208,7 +208,7 @@ export async function saveDatabaseDestination(request: FastifyRequest<SaveDataba | |||||||
|         if (destinationDockerId) { |         if (destinationDockerId) { | ||||||
|             if (type && version) { |             if (type && version) { | ||||||
|                 const baseImage = getDatabaseImage(type, arch); |                 const baseImage = getDatabaseImage(type, arch); | ||||||
|                 executeDockerCmd({ dockerId, command: `docker pull ${baseImage}:${version}` }) |                 executeCommand({ dockerId, command: `docker pull ${baseImage}:${version}` }) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         return reply.code(201).send({}) |         return reply.code(201).send({}) | ||||||
| @ -298,7 +298,7 @@ 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)); | ||||||
|         await executeDockerCmd({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up -d` }) |         await executeCommand({ dockerId: destinationDocker.id, command: `docker compose -f ${composeFileDestination} up -d` }) | ||||||
|         if (isPublic) await startTraefikTCPProxy(destinationDocker, id, publicPort, privatePort); |         if (isPublic) await startTraefikTCPProxy(destinationDocker, id, publicPort, privatePort); | ||||||
|         return {}; |         return {}; | ||||||
| 
 | 
 | ||||||
| @ -347,7 +347,7 @@ export async function getDatabaseLogs(request: FastifyRequest<GetDatabaseLogs>) | |||||||
|                 // const found = await checkContainer({ dockerId, container: id })
 |                 // const found = await checkContainer({ dockerId, container: id })
 | ||||||
|                 // if (found) {
 |                 // if (found) {
 | ||||||
|                 const { default: ansi } = await import('strip-ansi') |                 const { default: ansi } = await import('strip-ansi') | ||||||
|                 const { stdout, stderr } = await executeDockerCmd({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${id}` }) |                 const { stdout, stderr } = await executeCommand({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${id}` }) | ||||||
|                 const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a); |                 const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a); | ||||||
|                 const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a); |                 const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a); | ||||||
|                 const logs = stripLogsStderr.concat(stripLogsStdout) |                 const logs = stripLogsStderr.concat(stripLogsStdout) | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import sshConfig from 'ssh-config' | |||||||
| import fs from 'fs/promises' | import fs from 'fs/promises' | ||||||
| import os from 'os'; | import os from 'os'; | ||||||
| 
 | 
 | ||||||
| import { asyncExecShell, createRemoteEngineConfiguration, decrypt, errorHandler, executeDockerCmd, executeSSHCmd, listSettings, prisma, startTraefikProxy, stopTraefikProxy } from '../../../../lib/common'; | import { createRemoteEngineConfiguration, decrypt, errorHandler, executeCommand,  executeSSHCmd, listSettings, prisma, startTraefikProxy, stopTraefikProxy } from '../../../../lib/common'; | ||||||
| import { checkContainer } from '../../../../lib/docker'; | import { checkContainer } from '../../../../lib/docker'; | ||||||
| 
 | 
 | ||||||
| import type { OnlyId } from '../../../../types'; | import type { OnlyId } from '../../../../types'; | ||||||
| @ -79,9 +79,9 @@ export async function newDestination(request: FastifyRequest<NewDestination>, re | |||||||
|         let { name, network, engine, isCoolifyProxyUsed, remoteIpAddress, remoteUser, remotePort } = request.body |         let { name, network, engine, isCoolifyProxyUsed, remoteIpAddress, remoteUser, remotePort } = request.body | ||||||
|         if (id === 'new') { |         if (id === 'new') { | ||||||
|             if (engine) { |             if (engine) { | ||||||
|                 const { stdout } = await asyncExecShell(`DOCKER_HOST=unix:///var/run/docker.sock docker network ls --filter 'name=^${network}$' --format '{{json .}}'`); |                 const { stdout } = await await executeCommand({ command: `docker network ls --filter 'name=^${network}$' --format '{{json .}}'` }); | ||||||
|                 if (stdout === '') { |                 if (stdout === '') { | ||||||
|                     await asyncExecShell(`DOCKER_HOST=unix:///var/run/docker.sock docker network create --attachable ${network}`); |                     await await executeCommand({ command: `docker network create --attachable ${network}` }); | ||||||
|                 } |                 } | ||||||
|                 await prisma.destinationDocker.create({ |                 await prisma.destinationDocker.create({ | ||||||
|                     data: { name, teams: { connect: { id: teamId } }, engine, network, isCoolifyProxyUsed } |                     data: { name, teams: { connect: { id: teamId } }, engine, network, isCoolifyProxyUsed } | ||||||
| @ -122,13 +122,13 @@ export async function deleteDestination(request: FastifyRequest<OnlyId>) { | |||||||
|         const { network, remoteVerified, engine, isCoolifyProxyUsed } = await prisma.destinationDocker.findUnique({ where: { id } }); |         const { network, remoteVerified, engine, isCoolifyProxyUsed } = await prisma.destinationDocker.findUnique({ where: { id } }); | ||||||
|         if (isCoolifyProxyUsed) { |         if (isCoolifyProxyUsed) { | ||||||
|             if (engine || remoteVerified) { |             if (engine || remoteVerified) { | ||||||
|                 const { stdout: found } = await executeDockerCmd({ |                 const { stdout: found } = await executeCommand({ | ||||||
|                     dockerId: id, |                     dockerId: id, | ||||||
|                     command: `docker ps -a --filter network=${network} --filter name=coolify-proxy --format '{{.}}'` |                     command: `docker ps -a --filter network=${network} --filter name=coolify-proxy --format '{{.}}'` | ||||||
|                 }) |                 }) | ||||||
|                 if (found) { |                 if (found) { | ||||||
|                     await executeDockerCmd({ dockerId: id, command: `docker network disconnect ${network} coolify-proxy` }) |                     await executeCommand({ dockerId: id, command: `docker network disconnect ${network} coolify-proxy` }) | ||||||
|                     await executeDockerCmd({ dockerId: id, command: `docker network rm ${network}` }) |                     await executeCommand({ dockerId: id, command: `docker network rm ${network}` }) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -206,13 +206,13 @@ export async function verifyRemoteDockerEngineFn(id: string) { | |||||||
|     await createRemoteEngineConfiguration(id); |     await createRemoteEngineConfiguration(id); | ||||||
|     const { remoteIpAddress, network, isCoolifyProxyUsed } = await prisma.destinationDocker.findFirst({ where: { id } }) |     const { remoteIpAddress, network, isCoolifyProxyUsed } = await prisma.destinationDocker.findFirst({ where: { id } }) | ||||||
|     const host = `ssh://${remoteIpAddress}-remote` |     const host = `ssh://${remoteIpAddress}-remote` | ||||||
|     const { stdout } = await asyncExecShell(`DOCKER_HOST=${host} docker network ls --filter 'name=${network}' --no-trunc --format "{{json .}}"`); |     const { stdout } = await executeCommand({ command: `docker network ls --filter 'name=${network}' --no-trunc --format "{{json .}}"`, dockerId: id }); | ||||||
|     if (!stdout) { |     if (!stdout) { | ||||||
|         await asyncExecShell(`DOCKER_HOST=${host} docker network create --attachable ${network}`); |         await executeCommand({ command: `docker network create --attachable ${network}`, dockerId: id }); | ||||||
|     } |     } | ||||||
|     const { stdout: coolifyNetwork } = await asyncExecShell(`DOCKER_HOST=${host} docker network ls --filter 'name=coolify-infra' --no-trunc --format "{{json .}}"`); |     const { stdout: coolifyNetwork } = await executeCommand({ command: `docker network ls --filter 'name=coolify-infra' --no-trunc --format "{{json .}}"`, dockerId: id }); | ||||||
|     if (!coolifyNetwork) { |     if (!coolifyNetwork) { | ||||||
|         await asyncExecShell(`DOCKER_HOST=${host} docker network create --attachable coolify-infra`); |         await executeCommand({ command: `docker network create --attachable coolify-infra`, dockerId: id }); | ||||||
|     } |     } | ||||||
|     if (isCoolifyProxyUsed) await startTraefikProxy(id); |     if (isCoolifyProxyUsed) await startTraefikProxy(id); | ||||||
|     try { |     try { | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ import bcrypt from "bcryptjs"; | |||||||
| import fs from 'fs/promises'; | import fs from 'fs/promises'; | ||||||
| import yaml from 'js-yaml'; | import yaml from 'js-yaml'; | ||||||
| import { | import { | ||||||
| 	asyncExecShell, |  | ||||||
| 	asyncSleep, | 	asyncSleep, | ||||||
| 	cleanupDockerStorage, | 	cleanupDockerStorage, | ||||||
| 	errorHandler, | 	errorHandler, | ||||||
| @ -15,6 +14,7 @@ import { | |||||||
| 	version, | 	version, | ||||||
| 	sentryDSN, | 	sentryDSN, | ||||||
| 	executeDockerCmd, | 	executeDockerCmd, | ||||||
|  | 	executeCommand, | ||||||
| } from "../../../lib/common"; | } from "../../../lib/common"; | ||||||
| import { scheduler } from "../../../lib/scheduler"; | import { scheduler } from "../../../lib/scheduler"; | ||||||
| import type { FastifyReply, FastifyRequest } from "fastify"; | import type { FastifyReply, FastifyRequest } from "fastify"; | ||||||
| @ -38,7 +38,7 @@ export async function backup(request: FastifyRequest) { | |||||||
| 			// 	dockerId: database.destinationDockerId,
 | 			// 	dockerId: database.destinationDockerId,
 | ||||||
| 			// 	command: `docker pull coollabsio/backup:latest`,
 | 			// 	command: `docker pull coollabsio/backup:latest`,
 | ||||||
| 			// })
 | 			// })
 | ||||||
| 			std = await executeDockerCmd({ | 			std = await executeCommand({ | ||||||
| 				dockerId: database.destinationDockerId, | 				dockerId: database.destinationDockerId, | ||||||
| 				command: `docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v coolify-local-backup:/app/backups -e CONTAINERS_TO_BACKUP="${backupData}" coollabsio/backup` | 				command: `docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v coolify-local-backup:/app/backups -e CONTAINERS_TO_BACKUP="${backupData}" coollabsio/backup` | ||||||
| 			}) | 			}) | ||||||
| @ -141,14 +141,10 @@ export async function update(request: FastifyRequest<Update>) { | |||||||
| 	try { | 	try { | ||||||
| 		if (!isDev) { | 		if (!isDev) { | ||||||
| 			const { isAutoUpdateEnabled } = await prisma.setting.findFirst(); | 			const { isAutoUpdateEnabled } = await prisma.setting.findFirst(); | ||||||
| 			await asyncExecShell(`docker pull coollabsio/coolify:${latestVersion}`); | 			await executeCommand({ command: `docker pull coollabsio/coolify:${latestVersion}` }); | ||||||
| 			await asyncExecShell(`env | grep COOLIFY > .env`); | 			await executeCommand({ command: `env | grep COOLIFY > .env` }); | ||||||
| 			await asyncExecShell( | 			await executeCommand({ command: `sed -i '/COOLIFY_AUTO_UPDATE=/cCOOLIFY_AUTO_UPDATE=${isAutoUpdateEnabled}' .env` }); | ||||||
| 				`sed -i '/COOLIFY_AUTO_UPDATE=/cCOOLIFY_AUTO_UPDATE=${isAutoUpdateEnabled}' .env` | 			await executeCommand({ command: `docker run --rm -tid --env-file .env -v /var/run/docker.sock:/var/run/docker.sock -v coolify-db coollabsio/coolify:${latestVersion} /bin/sh -c "env | grep COOLIFY > .env && echo 'TAG=${latestVersion}' >> .env && docker stop -t 0 coolify coolify-fluentbit && docker rm coolify coolify-fluentbit && docker compose pull && docker compose up -d --force-recreate"` }); | ||||||
| 			); |  | ||||||
| 			await asyncExecShell( |  | ||||||
| 				`docker run --rm -tid --env-file .env -v /var/run/docker.sock:/var/run/docker.sock -v coolify-db coollabsio/coolify:${latestVersion} /bin/sh -c "env | grep COOLIFY > .env && echo 'TAG=${latestVersion}' >> .env && docker stop -t 0 coolify coolify-fluentbit && docker rm coolify coolify-fluentbit && docker compose pull && docker compose up -d --force-recreate"` |  | ||||||
| 			); |  | ||||||
| 			return {}; | 			return {}; | ||||||
| 		} else { | 		} else { | ||||||
| 			await asyncSleep(2000); | 			await asyncSleep(2000); | ||||||
| @ -177,7 +173,7 @@ export async function restartCoolify(request: FastifyRequest<any>) { | |||||||
| 		const teamId = request.user.teamId; | 		const teamId = request.user.teamId; | ||||||
| 		if (teamId === "0") { | 		if (teamId === "0") { | ||||||
| 			if (!isDev) { | 			if (!isDev) { | ||||||
| 				asyncExecShell(`docker restart coolify`); | 				await executeCommand({ command: `docker restart coolify` }); | ||||||
| 				return {}; | 				return {}; | ||||||
| 			} else { | 			} else { | ||||||
| 				return {}; | 				return {}; | ||||||
|  | |||||||
| @ -53,9 +53,9 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => { | |||||||
| 		onRequest: [fastify.authenticate] | 		onRequest: [fastify.authenticate] | ||||||
| 	}, async (request) => await cleanupManually(request)); | 	}, async (request) => await cleanupManually(request)); | ||||||
| 
 | 
 | ||||||
| 	fastify.get('/internal/backup/:backupData', { | 	// fastify.get('/internal/backup/:backupData', {
 | ||||||
| 		onRequest: [fastify.authenticate] | 	// 	onRequest: [fastify.authenticate]
 | ||||||
| 	}, async (request) => await backup(request)); | 	// }, async (request) => await backup(request));
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export default root; | export default root; | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import type { FastifyRequest } from 'fastify'; | import type { FastifyRequest } from 'fastify'; | ||||||
| import { errorHandler, executeDockerCmd, prisma, createRemoteEngineConfiguration, executeSSHCmd } from '../../../../lib/common'; | import { errorHandler, prisma, executeSSHCmd } from '../../../../lib/common'; | ||||||
| import os from 'node:os'; | import os from 'node:os'; | ||||||
| import osu from 'node-os-utils'; | import osu from 'node-os-utils'; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import yaml from 'js-yaml'; | |||||||
| import bcrypt from 'bcryptjs'; | import bcrypt from 'bcryptjs'; | ||||||
| import cuid from 'cuid'; | import cuid from 'cuid'; | ||||||
| 
 | 
 | ||||||
| import { prisma, uniqueName, asyncExecShell, getServiceFromDB, getContainerUsage, isDomainConfigured, fixType, decrypt, encrypt, ComposeFile, getFreePublicPort, getDomain, errorHandler, generatePassword, isDev, stopTcpHttpProxy, executeDockerCmd, checkDomainsIsValidInDNS, checkExposedPort, listSettings, generateToken } from '../../../../lib/common'; | import { prisma, uniqueName, getServiceFromDB, getContainerUsage, isDomainConfigured, fixType, decrypt, encrypt, ComposeFile, getFreePublicPort, getDomain, errorHandler, generatePassword, isDev, stopTcpHttpProxy, checkDomainsIsValidInDNS, checkExposedPort, listSettings, generateToken, executeCommand } from '../../../../lib/common'; | ||||||
| import { day } from '../../../../lib/dayjs'; | import { day } from '../../../../lib/dayjs'; | ||||||
| import { checkContainer, } from '../../../../lib/docker'; | import { checkContainer, } from '../../../../lib/docker'; | ||||||
| import { removeService } from '../../../../lib/services/common'; | import { removeService } from '../../../../lib/services/common'; | ||||||
| @ -48,14 +48,19 @@ export async function cleanupUnconfiguredServices(request: FastifyRequest) { | |||||||
|         for (const service of services) { |         for (const service of services) { | ||||||
|             if (!service.fqdn) { |             if (!service.fqdn) { | ||||||
|                 if (service.destinationDockerId) { |                 if (service.destinationDockerId) { | ||||||
|                     await executeDockerCmd({ |                     const { stdout: containers } = await executeCommand({ | ||||||
|                         dockerId: service.destinationDockerId, |                         dockerId: service.destinationDockerId, | ||||||
|                         command: `docker ps -a --filter 'label=com.docker.compose.project=${service.id}' --format {{.ID}}|xargs -r -n 1 docker stop -t 0` |                         command: `docker ps -a --filter 'label=com.docker.compose.project=${service.id}' --format {{.ID}}` | ||||||
|                     }) |  | ||||||
|                     await executeDockerCmd({ |  | ||||||
|                         dockerId: service.destinationDockerId, |  | ||||||
|                         command: `docker ps -a --filter 'label=com.docker.compose.project=${service.id}' --format {{.ID}}|xargs -r -n 1 docker rm --force` |  | ||||||
|                     }) |                     }) | ||||||
|  |                     if (containers) { | ||||||
|  |                         const containerArray = containers.split('\n'); | ||||||
|  |                         if (containerArray.length > 0) { | ||||||
|  |                             for (const container of containerArray) { | ||||||
|  |                                 await executeCommand({ dockerId: service.destinationDockerId, command: `docker stop -t 0 ${container}` }) | ||||||
|  |                                 await executeCommand({ dockerId: service.destinationDockerId, command: `docker rm --force ${container}` }) | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|                 await removeService({ id: service.id }); |                 await removeService({ id: service.id }); | ||||||
|             } |             } | ||||||
| @ -73,7 +78,7 @@ export async function getServiceStatus(request: FastifyRequest<OnlyId>) { | |||||||
|         const { destinationDockerId, settings } = service; |         const { destinationDockerId, settings } = service; | ||||||
|         let payload = {} |         let payload = {} | ||||||
|         if (destinationDockerId) { |         if (destinationDockerId) { | ||||||
|             const { stdout: containers } = await executeDockerCmd({ |             const { stdout: containers } = await executeCommand({ | ||||||
|                 dockerId: service.destinationDocker.id, |                 dockerId: service.destinationDocker.id, | ||||||
|                 command: |                 command: | ||||||
|                     `docker ps -a --filter "label=com.docker.compose.project=${id}" --format '{{json .}}'` |                     `docker ps -a --filter "label=com.docker.compose.project=${id}" --format '{{json .}}'` | ||||||
| @ -443,7 +448,7 @@ export async function getServiceLogs(request: FastifyRequest<GetServiceLogs>) { | |||||||
|         if (destinationDockerId) { |         if (destinationDockerId) { | ||||||
|             try { |             try { | ||||||
|                 const { default: ansi } = await import('strip-ansi') |                 const { default: ansi } = await import('strip-ansi') | ||||||
|                 const { stdout, stderr } = await executeDockerCmd({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${containerId}` }) |                 const { stdout, stderr } = await executeCommand({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${containerId}` }) | ||||||
|                 const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a); |                 const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a); | ||||||
|                 const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a); |                 const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a); | ||||||
|                 const logs = stripLogsStderr.concat(stripLogsStdout) |                 const logs = stripLogsStderr.concat(stripLogsStdout) | ||||||
| @ -749,7 +754,7 @@ export async function activatePlausibleUsers(request: FastifyRequest<OnlyId>, re | |||||||
|         if (destinationDockerId) { |         if (destinationDockerId) { | ||||||
|             const databaseUrl = serviceSecret.find((secret) => secret.name === 'DATABASE_URL'); |             const databaseUrl = serviceSecret.find((secret) => secret.name === 'DATABASE_URL'); | ||||||
|             if (databaseUrl) { |             if (databaseUrl) { | ||||||
|                 await executeDockerCmd({ |                 await executeCommand({ | ||||||
|                     dockerId: destinationDocker.id, |                     dockerId: destinationDocker.id, | ||||||
|                     command: `docker exec ${id}-postgresql psql -H ${databaseUrl.value} -c "UPDATE users SET email_verified = true;"` |                     command: `docker exec ${id}-postgresql psql -H ${databaseUrl.value} -c "UPDATE users SET email_verified = true;"` | ||||||
|                 }) |                 }) | ||||||
| @ -770,9 +775,10 @@ export async function cleanupPlausibleLogs(request: FastifyRequest<OnlyId>, repl | |||||||
|             destinationDocker, |             destinationDocker, | ||||||
|         } = await getServiceFromDB({ id, teamId }); |         } = await getServiceFromDB({ id, teamId }); | ||||||
|         if (destinationDockerId) { |         if (destinationDockerId) { | ||||||
|             await executeDockerCmd({ |             await executeCommand({ | ||||||
|                 dockerId: destinationDocker.id, |                 dockerId: destinationDocker.id, | ||||||
|                 command: `docker exec ${id}-clickhouse /usr/bin/clickhouse-client -q \\"SELECT name FROM system.tables WHERE name LIKE '%log%';\\"| xargs -I{} /usr/bin/clickhouse-client -q \"TRUNCATE TABLE system.{};\"` |                 command: `docker exec ${id}-clickhouse /usr/bin/clickhouse-client -q \\"SELECT name FROM system.tables WHERE name LIKE '%log%';\\"| xargs -I{} /usr/bin/clickhouse-client -q \"TRUNCATE TABLE system.{};\"`, | ||||||
|  |                 shell: true | ||||||
|             }) |             }) | ||||||
|             return await reply.code(201).send() |             return await reply.code(201).send() | ||||||
|         } |         } | ||||||
| @ -812,36 +818,42 @@ export async function activateWordpressFtp(request: FastifyRequest<ActivateWordp | |||||||
|             if (user) ftpUser = user; |             if (user) ftpUser = user; | ||||||
|             if (savedPassword) ftpPassword = decrypt(savedPassword); |             if (savedPassword) ftpPassword = decrypt(savedPassword); | ||||||
| 
 | 
 | ||||||
|             const { stdout: password } = await asyncExecShell( |             // TODO: rewrite these to usable without shell
 | ||||||
|                 `echo ${ftpPassword} | openssl passwd -1 -stdin` |             const { stdout: password } = await executeCommand({ | ||||||
|  |                 command: | ||||||
|  |                     `echo ${ftpPassword} | openssl passwd -1 -stdin`, | ||||||
|  |                 shell: true | ||||||
|  |             } | ||||||
|             ); |             ); | ||||||
|             if (destinationDockerId) { |             if (destinationDockerId) { | ||||||
|                 try { |                 try { | ||||||
|                     await fs.stat(hostkeyDir); |                     await fs.stat(hostkeyDir); | ||||||
|                 } catch (error) { |                 } catch (error) { | ||||||
|                     await asyncExecShell(`mkdir -p ${hostkeyDir}`); |                     await executeCommand({ command: `mkdir -p ${hostkeyDir}` }); | ||||||
|                 } |                 } | ||||||
|                 if (!ftpHostKey) { |                 if (!ftpHostKey) { | ||||||
|                     await asyncExecShell( |                     await executeCommand({ | ||||||
|                         `ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" -q -f ${hostkeyDir}/${id}.ed25519` |                         command: | ||||||
|  |                             `ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" -q -f ${hostkeyDir}/${id}.ed25519` | ||||||
|  |                     } | ||||||
|                     ); |                     ); | ||||||
|                     const { stdout: ftpHostKey } = await asyncExecShell(`cat ${hostkeyDir}/${id}.ed25519`); |                     const { stdout: ftpHostKey } = await executeCommand({ command: `cat ${hostkeyDir}/${id}.ed25519` }); | ||||||
|                     await prisma.wordpress.update({ |                     await prisma.wordpress.update({ | ||||||
|                         where: { serviceId: id }, |                         where: { serviceId: id }, | ||||||
|                         data: { ftpHostKey: encrypt(ftpHostKey) } |                         data: { ftpHostKey: encrypt(ftpHostKey) } | ||||||
|                     }); |                     }); | ||||||
|                 } else { |                 } else { | ||||||
|                     await asyncExecShell(`echo "${decrypt(ftpHostKey)}" > ${hostkeyDir}/${id}.ed25519`); |                     await executeCommand({ command: `echo "${decrypt(ftpHostKey)}" > ${hostkeyDir}/${id}.ed25519`, shell: true }); | ||||||
|                 } |                 } | ||||||
|                 if (!ftpHostKeyPrivate) { |                 if (!ftpHostKeyPrivate) { | ||||||
|                     await asyncExecShell(`ssh-keygen -t rsa -b 4096 -N "" -f ${hostkeyDir}/${id}.rsa`); |                     await executeCommand({ command: `ssh-keygen -t rsa -b 4096 -N "" -f ${hostkeyDir}/${id}.rsa` }); | ||||||
|                     const { stdout: ftpHostKeyPrivate } = await asyncExecShell(`cat ${hostkeyDir}/${id}.rsa`); |                     const { stdout: ftpHostKeyPrivate } = await executeCommand({ command: `cat ${hostkeyDir}/${id}.rsa` }); | ||||||
|                     await prisma.wordpress.update({ |                     await prisma.wordpress.update({ | ||||||
|                         where: { serviceId: id }, |                         where: { serviceId: id }, | ||||||
|                         data: { ftpHostKeyPrivate: encrypt(ftpHostKeyPrivate) } |                         data: { ftpHostKeyPrivate: encrypt(ftpHostKeyPrivate) } | ||||||
|                     }); |                     }); | ||||||
|                 } else { |                 } else { | ||||||
|                     await asyncExecShell(`echo "${decrypt(ftpHostKeyPrivate)}" > ${hostkeyDir}/${id}.rsa`); |                     await executeCommand({ command: `echo "${decrypt(ftpHostKeyPrivate)}" > ${hostkeyDir}/${id}.rsa`, shell: true }); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 await prisma.wordpress.update({ |                 await prisma.wordpress.update({ | ||||||
| @ -856,9 +868,10 @@ export async function activateWordpressFtp(request: FastifyRequest<ActivateWordp | |||||||
|                 try { |                 try { | ||||||
|                     const { found: isRunning } = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-ftp` }); |                     const { found: isRunning } = await checkContainer({ dockerId: destinationDocker.id, container: `${id}-ftp` }); | ||||||
|                     if (isRunning) { |                     if (isRunning) { | ||||||
|                         await executeDockerCmd({ |                         await executeCommand({ | ||||||
|                             dockerId: destinationDocker.id, |                             dockerId: destinationDocker.id, | ||||||
|                             command: `docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp` |                             command: `docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`, | ||||||
|  |                             shell: true | ||||||
|                         }) |                         }) | ||||||
|                     } |                     } | ||||||
|                 } catch (error) { } |                 } catch (error) { } | ||||||
| @ -902,9 +915,9 @@ export async function activateWordpressFtp(request: FastifyRequest<ActivateWordp | |||||||
|                     `${hostkeyDir}/${id}.sh`, |                     `${hostkeyDir}/${id}.sh`, | ||||||
|                     `#!/bin/bash\nchmod 600 /etc/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_rsa_key\nuserdel -f xfs\nchown -R 33:33 /home/${ftpUser}/wordpress/` |                     `#!/bin/bash\nchmod 600 /etc/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_rsa_key\nuserdel -f xfs\nchown -R 33:33 /home/${ftpUser}/wordpress/` | ||||||
|                 ); |                 ); | ||||||
|                 await asyncExecShell(`chmod +x ${hostkeyDir}/${id}.sh`); |                 await executeCommand({ command: `chmod +x ${hostkeyDir}/${id}.sh` }); | ||||||
|                 await fs.writeFile(`${hostkeyDir}/${id}-docker-compose.yml`, yaml.dump(compose)); |                 await fs.writeFile(`${hostkeyDir}/${id}-docker-compose.yml`, yaml.dump(compose)); | ||||||
|                 await executeDockerCmd({ |                 await executeCommand({ | ||||||
|                     dockerId: destinationDocker.id, |                     dockerId: destinationDocker.id, | ||||||
|                     command: `docker compose -f ${hostkeyDir}/${id}-docker-compose.yml up -d` |                     command: `docker compose -f ${hostkeyDir}/${id}-docker-compose.yml up -d` | ||||||
|                 }) |                 }) | ||||||
| @ -921,9 +934,10 @@ export async function activateWordpressFtp(request: FastifyRequest<ActivateWordp | |||||||
|                 data: { ftpPublicPort: null } |                 data: { ftpPublicPort: null } | ||||||
|             }); |             }); | ||||||
|             try { |             try { | ||||||
|                 await executeDockerCmd({ |                 await executeCommand({ | ||||||
|                     dockerId: destinationDocker.id, |                     dockerId: destinationDocker.id, | ||||||
|                     command: `docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp` |                     command: `docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`, | ||||||
|  |                     shell: true | ||||||
|                 }) |                 }) | ||||||
| 
 | 
 | ||||||
|             } catch (error) { |             } catch (error) { | ||||||
| @ -937,8 +951,10 @@ export async function activateWordpressFtp(request: FastifyRequest<ActivateWordp | |||||||
|         return errorHandler({ status, message }) |         return errorHandler({ status, message }) | ||||||
|     } finally { |     } finally { | ||||||
|         try { |         try { | ||||||
|             await asyncExecShell( |             await executeCommand({ | ||||||
|                 `rm -fr ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub ${hostkeyDir}/${id}.sh` |                 command: | ||||||
|  |                     `rm -fr ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub ${hostkeyDir}/${id}.sh` | ||||||
|  |             } | ||||||
|             ); |             ); | ||||||
|         } catch (error) { } |         } catch (error) { } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ import { promises as dns } from 'dns'; | |||||||
| import { X509Certificate } from 'node:crypto'; | import { X509Certificate } from 'node:crypto'; | ||||||
| import * as Sentry from '@sentry/node'; | import * as Sentry from '@sentry/node'; | ||||||
| import type { FastifyReply, FastifyRequest } from 'fastify'; | import type { FastifyReply, FastifyRequest } from 'fastify'; | ||||||
| import { asyncExecShell, checkDomainsIsValidInDNS, decrypt, encrypt, errorHandler, getDomain, isDev, isDNSValid, isDomainConfigured, listSettings, prisma, sentryDSN, version } from '../../../../lib/common'; | import { checkDomainsIsValidInDNS, decrypt, encrypt, errorHandler, executeCommand, getDomain, isDev, isDNSValid, isDomainConfigured, listSettings, prisma, sentryDSN, version } from '../../../../lib/common'; | ||||||
| import { AddDefaultRegistry, CheckDNS, CheckDomain, DeleteDomain, OnlyIdInBody, SaveSettings, SaveSSHKey, SetDefaultRegistry } from './types'; | import { AddDefaultRegistry, CheckDNS, CheckDomain, DeleteDomain, OnlyIdInBody, SaveSettings, SaveSSHKey, SetDefaultRegistry } from './types'; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -182,7 +182,7 @@ export async function deleteCertificates(request: FastifyRequest<OnlyIdInBody>, | |||||||
|     try { |     try { | ||||||
|         const teamId = request.user.teamId; |         const teamId = request.user.teamId; | ||||||
|         const { id } = request.body; |         const { id } = request.body; | ||||||
|         await asyncExecShell(`docker exec coolify-proxy sh -c 'rm -f /etc/traefik/acme/custom/${id}-key.pem /etc/traefik/acme/custom/${id}-cert.pem'`) |         await executeCommand({ command: `docker exec coolify-proxy sh -c 'rm -f /etc/traefik/acme/custom/${id}-key.pem /etc/traefik/acme/custom/${id}-cert.pem'`, shell: true }) | ||||||
|         await prisma.certificate.deleteMany({ where: { id, teamId } }) |         await prisma.certificate.deleteMany({ where: { id, teamId } }) | ||||||
|         return reply.code(201).send() |         return reply.code(201).send() | ||||||
|     } catch ({ status, message }) { |     } catch ({ status, message }) { | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import { FastifyRequest } from "fastify"; | import { FastifyRequest } from "fastify"; | ||||||
| import { errorHandler, getDomain, isDev, prisma, executeDockerCmd, fixType } from "../../../lib/common"; | import { errorHandler, getDomain, isDev, prisma, executeCommand } from "../../../lib/common"; | ||||||
| import { getTemplates } from "../../../lib/services"; | import { getTemplates } from "../../../lib/services"; | ||||||
| import { OnlyId } from "../../../types"; | import { OnlyId } from "../../../types"; | ||||||
| 
 | 
 | ||||||
| @ -263,10 +263,12 @@ export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote | |||||||
| 			const runningContainers = {} | 			const runningContainers = {} | ||||||
| 			applications.forEach((app) => dockerIds.add(app.destinationDocker.id)); | 			applications.forEach((app) => dockerIds.add(app.destinationDocker.id)); | ||||||
| 			for (const dockerId of dockerIds) { | 			for (const dockerId of dockerIds) { | ||||||
| 				const { stdout: container } = await executeDockerCmd({ dockerId, command: `docker container ls --filter 'label=coolify.managed=true' --format '{{ .Names}}'` }) | 				const { stdout: container } = await executeCommand({ dockerId, command: `docker container ls --filter 'label=coolify.managed=true' --format '{{ .Names}}'` }) | ||||||
| 				const containersArray = container.trim().split('\n'); | 				if (container) { | ||||||
| 				if (containersArray.length > 0) { | 					const containersArray = container.trim().split('\n'); | ||||||
| 					runningContainers[dockerId] = containersArray | 					if (containersArray.length > 0) { | ||||||
|  | 						runningContainers[dockerId] = containersArray | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			for (const application of applications) { | 			for (const application of applications) { | ||||||
| @ -332,7 +334,7 @@ export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote | |||||||
| 					traefik.http.routers = { ...traefik.http.routers, ...generateRouters(serviceId, domain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) } | 					traefik.http.routers = { ...traefik.http.routers, ...generateRouters(serviceId, domain, nakedDomain, pathPrefix, isHttps, isWWW, dualCerts, isCustomSSL) } | ||||||
| 					traefik.http.services = { ...traefik.http.services, ...generateServices(serviceId, id, port) } | 					traefik.http.services = { ...traefik.http.services, ...generateServices(serviceId, id, port) } | ||||||
| 					if (previews) { | 					if (previews) { | ||||||
| 						const { stdout } = await executeDockerCmd({ dockerId, command: `docker container ls --filter="status=running" --filter="network=${network}" --filter="name=${id}-" --format="{{json .Names}}"` }) | 						const { stdout } = await executeCommand({ dockerId, command: `docker container ls --filter="status=running" --filter="network=${network}" --filter="name=${id}-" --format="{{json .Names}}"` }) | ||||||
| 						const containers = stdout | 						const containers = stdout | ||||||
| 							.trim() | 							.trim() | ||||||
| 							.split('\n') | 							.split('\n') | ||||||
| @ -359,7 +361,7 @@ export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote | |||||||
| 			const runningContainers = {} | 			const runningContainers = {} | ||||||
| 			services.forEach((app) => dockerIds.add(app.destinationDocker.id)); | 			services.forEach((app) => dockerIds.add(app.destinationDocker.id)); | ||||||
| 			for (const dockerId of dockerIds) { | 			for (const dockerId of dockerIds) { | ||||||
| 				const { stdout: container } = await executeDockerCmd({ dockerId, command: `docker container ls --filter 'label=coolify.managed=true' --format '{{ .Names}}'` }) | 				const { stdout: container } = await executeCommand({ dockerId, command: `docker container ls --filter 'label=coolify.managed=true' --format '{{ .Names}}'` }) | ||||||
| 				const containersArray = container.trim().split('\n'); | 				const containersArray = container.trim().split('\n'); | ||||||
| 				if (containersArray.length > 0) { | 				if (containersArray.length > 0) { | ||||||
| 					runningContainers[dockerId] = containersArray | 					runningContainers[dockerId] = containersArray | ||||||
|  | |||||||
							
								
								
									
										13
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										13
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @ -56,6 +56,7 @@ importers: | |||||||
|       is-port-reachable: 4.0.0 |       is-port-reachable: 4.0.0 | ||||||
|       js-yaml: 4.1.0 |       js-yaml: 4.1.0 | ||||||
|       jsonwebtoken: 8.5.1 |       jsonwebtoken: 8.5.1 | ||||||
|  |       minimist: ^1.2.7 | ||||||
|       node-forge: 1.3.1 |       node-forge: 1.3.1 | ||||||
|       node-os-utils: 1.3.7 |       node-os-utils: 1.3.7 | ||||||
|       nodemon: 2.0.20 |       nodemon: 2.0.20 | ||||||
| @ -66,6 +67,7 @@ importers: | |||||||
|       public-ip: 6.0.1 |       public-ip: 6.0.1 | ||||||
|       pump: 3.0.0 |       pump: 3.0.0 | ||||||
|       rimraf: 3.0.2 |       rimraf: 3.0.2 | ||||||
|  |       shell-quote: ^1.7.4 | ||||||
|       socket.io: 4.5.3 |       socket.io: 4.5.3 | ||||||
|       ssh-config: 4.1.6 |       ssh-config: 4.1.6 | ||||||
|       strip-ansi: 7.0.1 |       strip-ansi: 7.0.1 | ||||||
| @ -108,6 +110,7 @@ importers: | |||||||
|       is-port-reachable: 4.0.0 |       is-port-reachable: 4.0.0 | ||||||
|       js-yaml: 4.1.0 |       js-yaml: 4.1.0 | ||||||
|       jsonwebtoken: 8.5.1 |       jsonwebtoken: 8.5.1 | ||||||
|  |       minimist: 1.2.7 | ||||||
|       node-forge: 1.3.1 |       node-forge: 1.3.1 | ||||||
|       node-os-utils: 1.3.7 |       node-os-utils: 1.3.7 | ||||||
|       p-all: 4.0.0 |       p-all: 4.0.0 | ||||||
| @ -115,6 +118,7 @@ importers: | |||||||
|       prisma: 4.6.1 |       prisma: 4.6.1 | ||||||
|       public-ip: 6.0.1 |       public-ip: 6.0.1 | ||||||
|       pump: 3.0.0 |       pump: 3.0.0 | ||||||
|  |       shell-quote: 1.7.4 | ||||||
|       socket.io: 4.5.3 |       socket.io: 4.5.3 | ||||||
|       ssh-config: 4.1.6 |       ssh-config: 4.1.6 | ||||||
|       strip-ansi: 7.0.1 |       strip-ansi: 7.0.1 | ||||||
| @ -5599,6 +5603,9 @@ packages: | |||||||
|   /minimist/1.2.6: |   /minimist/1.2.6: | ||||||
|     resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} |     resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} | ||||||
| 
 | 
 | ||||||
|  |   /minimist/1.2.7: | ||||||
|  |     resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==} | ||||||
|  | 
 | ||||||
|   /mkdirp-classic/0.5.3: |   /mkdirp-classic/0.5.3: | ||||||
|     resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} |     resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} | ||||||
|     dev: false |     dev: false | ||||||
| @ -6702,6 +6709,10 @@ packages: | |||||||
|     resolution: {integrity: sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==} |     resolution: {integrity: sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==} | ||||||
|     dev: true |     dev: true | ||||||
| 
 | 
 | ||||||
|  |   /shell-quote/1.7.4: | ||||||
|  |     resolution: {integrity: sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==} | ||||||
|  |     dev: false | ||||||
|  | 
 | ||||||
|   /side-channel/1.0.4: |   /side-channel/1.0.4: | ||||||
|     resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} |     resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} | ||||||
|     dependencies: |     dependencies: | ||||||
| @ -7310,7 +7321,7 @@ packages: | |||||||
|     engines: {node: '>=6'} |     engines: {node: '>=6'} | ||||||
|     dependencies: |     dependencies: | ||||||
|       json5: 2.2.1 |       json5: 2.2.1 | ||||||
|       minimist: 1.2.6 |       minimist: 1.2.7 | ||||||
|       strip-bom: 3.0.0 |       strip-bom: 3.0.0 | ||||||
| 
 | 
 | ||||||
|   /tslib/1.14.1: |   /tslib/1.14.1: | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user