Compare commits

...

18 Commits

Author SHA1 Message Date
Andras Bacsai
e007a773fd Merge pull request #1030 from coollabsio/next
v3.12.30
2023-04-03 10:40:27 +02:00
Andras Bacsai
e2821118eb fix. removing git 2023-04-03 10:21:08 +02:00
Andras Bacsai
4c8e73ac86 fix: harder to remove destinations and sources 2023-04-03 09:55:13 +02:00
Andras Bacsai
cb980fb814 fix: docker compose generator 2023-04-03 08:59:48 +02:00
Andras Bacsai
41c84e3642 Merge pull request #1001 from coollabsio/next
v3.12.29
2023-03-20 13:57:01 +01:00
Andras Bacsai
2bad98424f switch back to aarch-runners 2023-03-20 13:49:41 +01:00
Andras Bacsai
bc6b1e2dea fix: remove .git dir from final image 2023-03-20 13:05:53 +01:00
Andras Bacsai
911c15d1be update versions 2023-03-20 12:44:45 +01:00
Andras Bacsai
f79d570870 fix: gitea 2023-03-20 12:28:23 +01:00
Andras Bacsai
7fffa9fba5 Merge branch 'main' into next 2023-03-20 12:05:21 +01:00
Andras Bacsai
cbd634fb99 Update README.md 2023-03-17 15:31:00 +01:00
Andras Bacsai
7ae7436d4f Update staging-release.yml 2023-03-17 15:27:16 +01:00
Andras Bacsai
641bada100 ignore dockerhub releases 2023-03-16 13:54:58 +01:00
Andras Bacsai
3416d8d88e only arm 2023-03-16 13:42:19 +01:00
Andras Bacsai
0bb503368b concurrency 2023-03-16 13:37:49 +01:00
Andras Bacsai
ac3a77c3c7 no qemu 2023-03-16 13:35:04 +01:00
Andras Bacsai
79b4178d76 vcpu increase 2023-03-16 13:32:48 +01:00
Andras Bacsai
42a61296d7 test buildjet 2023-03-16 13:29:13 +01:00
31 changed files with 700 additions and 550 deletions

View File

@@ -1,8 +1,9 @@
name: Production Release to DockerHub name: Production Release to DockerHub
on: on:
release: push:
types: [released] branches:
- "this-branch-does-not-exists"
jobs: jobs:
arm64: arm64:

View File

@@ -3,7 +3,7 @@ name: Staging Release to DockerHub
on: on:
push: push:
branches: branches:
- "next" - "this-branch-does-not-exists"
jobs: jobs:
arm64: arm64:

View File

@@ -1,23 +1,24 @@
name: Staging Release to ghcr.io name: Staging Release to ghcr.io
concurrency:
group: staging_environment
cancel-in-progress: true
on: on:
push: push:
branches-ignore: branches-ignore:
- "main" - "main"
- "v4"
env: env:
REGISTRY: ghcr.io REGISTRY: ghcr.io
IMAGE_NAME: "coollabsio/coolify" IMAGE_NAME: "coollabsio/coolify"
jobs: jobs:
amd64: amd64:
runs-on: ubuntu-latest runs-on: ubuntu-22.04
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
ref: "next" ref: "next"
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v2
- name: Login to ghcr.io - name: Login to ghcr.io
@@ -40,14 +41,13 @@ jobs:
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
aarch64: aarch64:
runs-on: [self-hosted, arm64] runs-on:
group: aarch-runners
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
ref: "next" ref: "next"
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v2
- name: Login to ghcr.io - name: Login to ghcr.io

View File

@@ -100,7 +100,7 @@ Deploy your resource to:
- Mastodon: [@andrasbacsai@fosstodon.org](https://fosstodon.org/@andrasbacsai) - Mastodon: [@andrasbacsai@fosstodon.org](https://fosstodon.org/@andrasbacsai)
- Telegram: [@andrasbacsai](https://t.me/andrasbacsai) - Telegram: [@andrasbacsai](https://t.me/andrasbacsai)
- Twitter: [@andrasbacsai](https://twitter.com/andrasbacsai) - Twitter: [@andrasbacsai](https://twitter.com/heyandras)
- Email: [andras@coollabs.io](mailto:andras@coollabs.io) - Email: [andras@coollabs.io](mailto:andras@coollabs.io)
- Discord: [Invitation](https://coollabs.io/discord) - Discord: [Invitation](https://coollabs.io/discord)

View File

@@ -414,6 +414,7 @@
proxy: proxy:
- port: "22" - port: "22"
hostPort: $$config_hostport_ssh hostPort: $$config_hostport_ssh
- port: "3000"
variables: variables:
- id: $$config_hostport_ssh - id: $$config_hostport_ssh
name: SSH_PORT name: SSH_PORT

View File

@@ -306,7 +306,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/...');
await fs.rm('/tmp/build-sources', { recursive: true, force: true }); if (!isDev) await fs.rm('/tmp/build-sources', { recursive: true, force: true });
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }

View File

@@ -240,7 +240,7 @@ import * as buildpacks from '../lib/buildPacks';
applicationId: application.id applicationId: application.id
}); });
} }
await fs.rm(workdir, { recursive: true, force: true }); if (!isDev) await fs.rm(workdir, { recursive: true, force: true });
return; return;
} }
try { try {
@@ -263,7 +263,7 @@ import * as buildpacks from '../lib/buildPacks';
await saveBuildLog({ line: error.stderr, buildId, applicationId }); await saveBuildLog({ line: error.stderr, buildId, applicationId });
} }
} finally { } finally {
await fs.rm(workdir, { recursive: true, force: true }); if (!isDev) await fs.rm(workdir, { recursive: true, force: true });
await prisma.build.update({ await prisma.build.update({
where: { id: buildId }, where: { id: buildId },
data: { status: 'success' } data: { status: 'success' }
@@ -782,7 +782,7 @@ import * as buildpacks from '../lib/buildPacks';
applicationId: application.id applicationId: application.id
}); });
} }
await fs.rm(workdir, { recursive: true, force: true }); if (!isDev) await fs.rm(workdir, { recursive: true, force: true });
return; return;
} }
try { try {
@@ -803,7 +803,7 @@ import * as buildpacks from '../lib/buildPacks';
await saveBuildLog({ line: error.stderr, buildId, applicationId }); await saveBuildLog({ line: error.stderr, buildId, applicationId });
} }
} finally { } finally {
await fs.rm(workdir, { recursive: true, force: true }); if (!isDev) 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' } });
} }
}); });

View File

@@ -804,6 +804,7 @@ export async function buildCacheImageWithNode(data, imageForBuild) {
Dockerfile.push(`RUN ${installCommand}`); Dockerfile.push(`RUN ${installCommand}`);
} }
Dockerfile.push(`RUN ${buildCommand}`); Dockerfile.push(`RUN ${buildCommand}`);
Dockerfile.push('RUN rm -fr .git');
await fs.writeFile(`${workdir}/Dockerfile-cache`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile-cache`, Dockerfile.join('\n'));
await buildImage({ ...data, isCache: true }); await buildImage({ ...data, isCache: true });
} }
@@ -821,6 +822,7 @@ export async function buildCacheImageForLaravel(data, imageForBuild) {
} }
Dockerfile.push(`COPY *.json *.mix.js /app/`); Dockerfile.push(`COPY *.json *.mix.js /app/`);
Dockerfile.push(`COPY resources /app/resources`); Dockerfile.push(`COPY resources /app/resources`);
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`RUN yarn install && yarn production`); Dockerfile.push(`RUN yarn install && yarn production`);
await fs.writeFile(`${workdir}/Dockerfile-cache`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile-cache`, Dockerfile.join('\n'));
await buildImage({ ...data, isCache: true }); await buildImage({ ...data, isCache: true });
@@ -842,6 +844,7 @@ export async function buildCacheImageWithCargo(data, imageForBuild) {
Dockerfile.push('RUN cargo install cargo-chef'); Dockerfile.push('RUN cargo install cargo-chef');
Dockerfile.push(`COPY --from=planner-${applicationId} /app/recipe.json recipe.json`); Dockerfile.push(`COPY --from=planner-${applicationId} /app/recipe.json recipe.json`);
Dockerfile.push('RUN cargo chef cook --release --recipe-path recipe.json'); Dockerfile.push('RUN cargo chef cook --release --recipe-path recipe.json');
Dockerfile.push('RUN rm -fr .git');
await fs.writeFile(`${workdir}/Dockerfile-cache`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile-cache`, Dockerfile.join('\n'));
await buildImage({ ...data, isCache: true }); await buildImage({ ...data, isCache: true });
} }

View File

@@ -47,7 +47,12 @@ export default async function (data) {
for (let [key, value] of Object.entries(dockerComposeYaml.services)) { for (let [key, value] of Object.entries(dockerComposeYaml.services)) {
value['container_name'] = `${applicationId}-${key}`; value['container_name'] = `${applicationId}-${key}`;
if (value['env_file']) {
delete value['env_file'];
}
let environment = typeof value['environment'] === 'undefined' ? [] : value['environment']; let environment = typeof value['environment'] === 'undefined' ? [] : value['environment'];
console.log({ key, environment });
if (Object.keys(environment).length > 0) { if (Object.keys(environment).length > 0) {
environment = Object.entries(environment).map(([key, value]) => `${key}=${value}`); environment = Object.entries(environment).map(([key, value]) => `${key}=${value}`);
} }
@@ -60,7 +65,7 @@ export default async function (data) {
const buildArgs = typeof build['args'] === 'undefined' ? [] : build['args']; const buildArgs = typeof build['args'] === 'undefined' ? [] : build['args'];
let finalArgs = [...buildEnvs]; let finalArgs = [...buildEnvs];
if (Object.keys(buildArgs).length > 0) { if (Object.keys(buildArgs).length > 0) {
for (const arg of buildArgs) { for (const arg of Object.keys(buildArgs)) {
const [key, _] = arg.split('='); const [key, _] = arg.split('=');
if (finalArgs.filter((env) => env.startsWith(key)).length === 0) { if (finalArgs.filter((env) => env.startsWith(key)).length === 0) {
finalArgs.push(arg); finalArgs.push(arg);
@@ -87,7 +92,10 @@ export default async function (data) {
v.startsWith('~') || v.startsWith('~') ||
v.startsWith('$PWD') v.startsWith('$PWD')
) { ) {
v = v.replace(/^\./, `~`).replace(/^\.\./, '~').replace(/^\$PWD/, '~'); v = v
.replace(/^\./, `~`)
.replace(/^\.\./, '~')
.replace(/^\$PWD/, '~');
} else { } else {
if (!path) { if (!path) {
path = v; path = v;
@@ -110,10 +118,11 @@ export default async function (data) {
source.startsWith('~') || source.startsWith('~') ||
source.startsWith('$PWD') source.startsWith('$PWD')
) { ) {
source = source
source = source.replace(/^\./, `~`).replace(/^\.\./, '~').replace(/^\$PWD/, '~'); .replace(/^\./, `~`)
console.log({source}) .replace(/^\.\./, '~')
.replace(/^\$PWD/, '~');
console.log({ source });
} else { } else {
if (!target) { if (!target) {
target = source; target = source;
@@ -125,7 +134,6 @@ export default async function (data) {
return `${source}:${target}${mode ? ':' + mode : ''}`; return `${source}:${target}${mode ? ':' + mode : ''}`;
} }
}); });
} }
if (volumes.length > 0) { if (volumes.length > 0) {
@@ -136,16 +144,20 @@ export default async function (data) {
if (dockerComposeConfiguration[key]?.port) { if (dockerComposeConfiguration[key]?.port) {
value['expose'] = [dockerComposeConfiguration[key].port]; value['expose'] = [dockerComposeConfiguration[key].port];
} }
if (value['networks']?.length > 0) {
value['networks'].forEach((network) => {
networks[network] = {
name: network
};
});
value['networks'] = [...(value['networks'] || ''), network];
} else {
value['networks'] = [network]; value['networks'] = [network];
if (value['build']?.network) {
delete value['build']['network'];
} }
// if (value['networks']?.length > 0) {
// value['networks'].forEach((network) => {
// networks[network] = {
// name: network
// };
// });
// value['networks'] = [...(value['networks'] || ''), network];
// } else {
// value['networks'] = [network];
// }
dockerComposeYaml.services[key] = { dockerComposeYaml.services[key] = {
...dockerComposeYaml.services[key], ...dockerComposeYaml.services[key],

View File

@@ -36,6 +36,7 @@ const createDockerfile = async (data, image): Promise<void> => {
Dockerfile.push(`COPY .${baseDirectory || ''} ./`); Dockerfile.push(`COPY .${baseDirectory || ''} ./`);
Dockerfile.push(`RUN deno cache ${denoMainFile}`); Dockerfile.push(`RUN deno cache ${denoMainFile}`);
Dockerfile.push(`ENV NO_COLOR true`); Dockerfile.push(`ENV NO_COLOR true`);
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`EXPOSE ${port}`); Dockerfile.push(`EXPOSE ${port}`);
Dockerfile.push(`CMD deno run ${denoOptions || ''} ${denoMainFile}`); Dockerfile.push(`CMD deno run ${denoOptions || ''} ${denoMainFile}`);
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));

View File

@@ -22,6 +22,7 @@ export default async function (data) {
}); });
}); });
} }
Dockerfile.push(`RUN rm -fr .git`);
await fs.writeFile(`${data.workdir}${dockerFileLocation}`, Dockerfile.join('\n')); await fs.writeFile(`${data.workdir}${dockerFileLocation}`, Dockerfile.join('\n'));
await buildImage(data); await buildImage(data);
} }

View File

@@ -12,6 +12,7 @@ const createDockerfile = async (data, imageforBuild): Promise<void> => {
if (baseImage?.includes('nginx')) { if (baseImage?.includes('nginx')) {
Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`); Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`);
} }
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`EXPOSE ${port}`); Dockerfile.push(`EXPOSE ${port}`);
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
}; };

View File

@@ -30,6 +30,7 @@ const createDockerfile = async (data, image): Promise<void> => {
`COPY --chown=application:application --from=${applicationId}:${tag}-cache /app/mix-manifest.json /app/public/mix-manifest.json` `COPY --chown=application:application --from=${applicationId}:${tag}-cache /app/mix-manifest.json /app/public/mix-manifest.json`
); );
Dockerfile.push(`COPY --chown=application:application . ./`); Dockerfile.push(`COPY --chown=application:application . ./`);
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`EXPOSE ${port}`); Dockerfile.push(`EXPOSE ${port}`);
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
}; };

View File

@@ -13,7 +13,7 @@ const createDockerfile = async (data, image): Promise<void> => {
Dockerfile.push('RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@7'); Dockerfile.push('RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@7');
} }
Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /app${publishDirectory} ./`); Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /app${publishDirectory} ./`);
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`EXPOSE ${port}`); Dockerfile.push(`EXPOSE ${port}`);
Dockerfile.push(`CMD ${startCommand}`); Dockerfile.push(`CMD ${startCommand}`);
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));

View File

@@ -36,6 +36,7 @@ const createDockerfile = async (data, image): Promise<void> => {
Dockerfile.push(`COPY .${baseDirectory || ''} ./`); Dockerfile.push(`COPY .${baseDirectory || ''} ./`);
Dockerfile.push(`RUN ${installCommand}`); Dockerfile.push(`RUN ${installCommand}`);
Dockerfile.push(`RUN ${buildCommand}`); Dockerfile.push(`RUN ${buildCommand}`);
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`EXPOSE ${port}`); Dockerfile.push(`EXPOSE ${port}`);
Dockerfile.push(`CMD ${startCommand}`); Dockerfile.push(`CMD ${startCommand}`);
} else if (deploymentType === 'static') { } else if (deploymentType === 'static') {
@@ -43,6 +44,7 @@ const createDockerfile = async (data, image): Promise<void> => {
Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`); Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`);
} }
Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /app${publishDirectory} ./`); Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /app${publishDirectory} ./`);
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`EXPOSE 80`); Dockerfile.push(`EXPOSE 80`);
} }

View File

@@ -34,6 +34,7 @@ const createDockerfile = async (data, image): Promise<void> => {
Dockerfile.push(`RUN ${buildCommand}`); Dockerfile.push(`RUN ${buildCommand}`);
} }
Dockerfile.push(`EXPOSE ${port}`); Dockerfile.push(`EXPOSE ${port}`);
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`CMD ${startCommand}`); Dockerfile.push(`CMD ${startCommand}`);
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
}; };

View File

@@ -36,6 +36,7 @@ const createDockerfile = async (data, image): Promise<void> => {
Dockerfile.push(`COPY .${baseDirectory || ''} ./`); Dockerfile.push(`COPY .${baseDirectory || ''} ./`);
Dockerfile.push(`RUN ${installCommand}`); Dockerfile.push(`RUN ${installCommand}`);
Dockerfile.push(`RUN ${buildCommand}`); Dockerfile.push(`RUN ${buildCommand}`);
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`EXPOSE ${port}`); Dockerfile.push(`EXPOSE ${port}`);
Dockerfile.push(`CMD ${startCommand}`); Dockerfile.push(`CMD ${startCommand}`);
} else if (deploymentType === 'static') { } else if (deploymentType === 'static') {
@@ -43,6 +44,7 @@ const createDockerfile = async (data, image): Promise<void> => {
Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`); Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`);
} }
Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /app${publishDirectory} ./`); Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /app${publishDirectory} ./`);
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`EXPOSE 80`); Dockerfile.push(`EXPOSE 80`);
} }

View File

@@ -28,6 +28,7 @@ const createDockerfile = async (data, image, htaccessFound): Promise<void> => {
} }
Dockerfile.push(`COPY /entrypoint.sh /opt/docker/provision/entrypoint.d/30-entrypoint.sh`); Dockerfile.push(`COPY /entrypoint.sh /opt/docker/provision/entrypoint.d/30-entrypoint.sh`);
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`EXPOSE ${port}`); Dockerfile.push(`EXPOSE ${port}`);
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
}; };

View File

@@ -52,7 +52,7 @@ const createDockerfile = async (data, image): Promise<void> => {
} else { } else {
Dockerfile.push(`CMD python ${pythonModule}`); Dockerfile.push(`CMD python ${pythonModule}`);
} }
Dockerfile.push('RUN rm -fr .git');
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
}; };

View File

@@ -12,6 +12,7 @@ const createDockerfile = async (data, image): Promise<void> => {
if (baseImage?.includes('nginx')) { if (baseImage?.includes('nginx')) {
Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`); Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`);
} }
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`EXPOSE ${port}`); Dockerfile.push(`EXPOSE ${port}`);
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
}; };

View File

@@ -20,6 +20,7 @@ const createDockerfile = async (data, image, name): Promise<void> => {
); );
Dockerfile.push(`RUN update-ca-certificates`); Dockerfile.push(`RUN update-ca-certificates`);
Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /app/target/release/${name} ${name}`); Dockerfile.push(`COPY --from=${applicationId}:${tag}-cache /app/target/release/${name} ${name}`);
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`EXPOSE ${port}`); Dockerfile.push(`EXPOSE ${port}`);
Dockerfile.push(`CMD ["/app/${name}"]`); Dockerfile.push(`CMD ["/app/${name}"]`);
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));

View File

@@ -38,6 +38,7 @@ const createDockerfile = async (data, image): Promise<void> => {
if (baseImage?.includes('nginx')) { if (baseImage?.includes('nginx')) {
Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`); Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`);
} }
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`EXPOSE ${port}`); Dockerfile.push(`EXPOSE ${port}`);
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
}; };

View File

@@ -12,6 +12,7 @@ const createDockerfile = async (data, image): Promise<void> => {
if (baseImage?.includes('nginx')) { if (baseImage?.includes('nginx')) {
Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`); Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`);
} }
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`EXPOSE ${port}`); Dockerfile.push(`EXPOSE ${port}`);
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
}; };

View File

@@ -12,6 +12,7 @@ const createDockerfile = async (data, image): Promise<void> => {
if (baseImage?.includes('nginx')) { if (baseImage?.includes('nginx')) {
Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`); Dockerfile.push(`COPY /nginx.conf /etc/nginx/nginx.conf`);
} }
Dockerfile.push('RUN rm -fr .git');
Dockerfile.push(`EXPOSE ${port}`); Dockerfile.push(`EXPOSE ${port}`);
await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n')); await fs.writeFile(`${workdir}/Dockerfile`, Dockerfile.join('\n'));
}; };

View File

@@ -19,7 +19,7 @@ import { saveBuildLog } from './buildPacks/common';
import { scheduler } from './scheduler'; import { scheduler } from './scheduler';
import type { ExecaChildProcess } from 'execa'; import type { ExecaChildProcess } from 'execa';
export const version = '3.12.28'; export const version = '3.12.30';
export const isDev = process.env.NODE_ENV === 'development'; export const isDev = process.env.NODE_ENV === 'development';
export const proxyPort = process.env.COOLIFY_PROXY_PORT; export const proxyPort = process.env.COOLIFY_PROXY_PORT;
export const proxySecurePort = process.env.COOLIFY_PROXY_SECURE_PORT; export const proxySecurePort = process.env.COOLIFY_PROXY_SECURE_PORT;
@@ -402,8 +402,8 @@ export const supportedDatabaseTypesAndVersions = [
fancyName: 'MongoDB', fancyName: 'MongoDB',
baseImage: 'bitnami/mongodb', baseImage: 'bitnami/mongodb',
baseImageARM: 'mongo', baseImageARM: 'mongo',
versions: ['5.0', '4.4', '4.2'], versions: ['6.0', '5.0', '4.4', '4.2'],
versionsARM: ['5.0', '4.4', '4.2'] versionsARM: ['6.0', '5.0', '4.4', '4.2']
}, },
{ {
name: 'mysql', name: 'mysql',
@@ -418,16 +418,16 @@ export const supportedDatabaseTypesAndVersions = [
fancyName: 'MariaDB', fancyName: 'MariaDB',
baseImage: 'bitnami/mariadb', baseImage: 'bitnami/mariadb',
baseImageARM: 'mariadb', baseImageARM: 'mariadb',
versions: ['10.8', '10.7', '10.6', '10.5', '10.4', '10.3', '10.2'], versions: ['10.11', '10.10', '10.9', '10.8', '10.7', '10.6', '10.5', '10.4', '10.3', '10.2'],
versionsARM: ['10.8', '10.7', '10.6', '10.5', '10.4', '10.3', '10.2'] versionsARM: ['10.11', '10.10', '10.9', '10.8', '10.7', '10.6', '10.5', '10.4', '10.3', '10.2']
}, },
{ {
name: 'postgresql', name: 'postgresql',
fancyName: 'PostgreSQL', fancyName: 'PostgreSQL',
baseImage: 'bitnami/postgresql', baseImage: 'bitnami/postgresql',
baseImageARM: 'postgres', baseImageARM: 'postgres',
versions: ['14.5.0', '13.8.0', '12.12.0', '11.17.0', '10.22.0'], versions: ['15.2.0', '14.7.0', '14.5.0', '13.8.0', '12.12.0', '11.17.0', '10.22.0'],
versionsARM: ['14.5', '13.8', '12.12', '11.17', '10.22'] versionsARM: ['15.2', '14.7', '14.5', '13.8', '12.12', '11.17', '10.22']
}, },
{ {
name: 'redis', name: 'redis',
@@ -442,14 +442,14 @@ export const supportedDatabaseTypesAndVersions = [
fancyName: 'CouchDB', fancyName: 'CouchDB',
baseImage: 'bitnami/couchdb', baseImage: 'bitnami/couchdb',
baseImageARM: 'couchdb', baseImageARM: 'couchdb',
versions: ['3.2.2', '3.1.2', '2.3.1'], versions: ['3.3.1', '3.2.2', '3.1.2', '2.3.1'],
versionsARM: ['3.2.2', '3.1.2', '2.3.1'] versionsARM: ['3.3', '3.2.2', '3.1.2', '2.3.1']
}, },
{ {
name: 'edgedb', name: 'edgedb',
fancyName: 'EdgeDB', fancyName: 'EdgeDB',
baseImage: 'edgedb/edgedb', baseImage: 'edgedb/edgedb',
versions: ['latest', '2.1', '2.0', '1.4'] versions: ['latest', '2.9', '2.8', '2.7']
} }
]; ];
@@ -1013,7 +1013,7 @@ export function generateDatabaseConfiguration(database: any): DatabaseConfigurat
ulimits: {} ulimits: {}
}; };
if (isARM()) { if (isARM()) {
configuration.volume = `${id}-${type}-data:/var/lib/postgresql`; configuration.volume = `${id}-${type}-data:/var/lib/postgresql/data`;
configuration.environmentVariables = { configuration.environmentVariables = {
POSTGRES_PASSWORD: dbUserPassword, POSTGRES_PASSWORD: dbUserPassword,
POSTGRES_USER: dbUser, POSTGRES_USER: dbUser,
@@ -1038,7 +1038,8 @@ export function generateDatabaseConfiguration(database: any): DatabaseConfigurat
}; };
if (isARM()) { if (isARM()) {
configuration.volume = `${id}-${type}-data:/data`; configuration.volume = `${id}-${type}-data:/data`;
configuration.command = `/usr/local/bin/redis-server --appendonly ${appendOnly ? 'yes' : 'no' configuration.command = `/usr/local/bin/redis-server --appendonly ${
appendOnly ? 'yes' : 'no'
} --requirepass ${dbUserPassword}`; } --requirepass ${dbUserPassword}`;
} }
return configuration; return configuration;
@@ -1200,7 +1201,7 @@ export const createDirectories = async ({
let workdirFound = false; let workdirFound = false;
try { try {
workdirFound = !!(await fs.stat(workdir)); workdirFound = !!(await fs.stat(workdir));
} catch (error) { } } catch (error) {}
if (workdirFound) { if (workdirFound) {
await executeCommand({ command: `rm -fr ${workdir}` }); await executeCommand({ command: `rm -fr ${workdir}` });
} }
@@ -1727,7 +1728,7 @@ export async function stopBuild(buildId, applicationId) {
} }
} }
count++; count++;
} catch (error) { } } catch (error) {}
}, 100); }, 100);
}); });
} }
@@ -1750,7 +1751,7 @@ export async function cleanupDockerStorage(dockerId) {
// Cleanup images that are not used by any container // Cleanup images that are not used by any container
try { try {
await executeCommand({ dockerId, command: `docker image prune -af` }); await executeCommand({ dockerId, command: `docker image prune -af` });
} catch (error) { } } catch (error) {}
// Prune coolify managed containers // Prune coolify managed containers
try { try {
@@ -1758,12 +1759,12 @@ export async function cleanupDockerStorage(dockerId) {
dockerId, dockerId,
command: `docker container prune -f --filter "label=coolify.managed=true"` command: `docker container prune -f --filter "label=coolify.managed=true"`
}); });
} catch (error) { } } catch (error) {}
// Cleanup build caches // Cleanup build caches
try { try {
await executeCommand({ dockerId, command: `docker builder prune -af` }); await executeCommand({ dockerId, command: `docker builder prune -af` });
} catch (error) { } } catch (error) {}
} }
export function persistentVolumes(id, persistentStorage, config) { export function persistentVolumes(id, persistentStorage, config) {

View File

@@ -302,7 +302,7 @@ export async function startDatabase(request: FastifyRequest<OnlyId>) {
databaseSecret databaseSecret
} = database; } = database;
const { privatePort, command, environmentVariables, image, volume, ulimits } = const { privatePort, command, environmentVariables, image, volume, ulimits } =
generateDatabaseConfiguration(database, arch); generateDatabaseConfiguration(database);
const network = destinationDockerId && destinationDocker.network; const network = destinationDockerId && destinationDocker.network;
const volumeName = volume.split(':')[0]; const volumeName = volume.split(':')[0];

View File

@@ -1,20 +1,29 @@
import type { FastifyRequest } from 'fastify'; import type { FastifyRequest } from 'fastify';
import { FastifyReply } from 'fastify'; import { FastifyReply } from 'fastify';
import sshConfig from 'ssh-config' import {
import fs from 'fs/promises' errorHandler,
import os from 'os'; executeCommand,
listSettings,
import { createRemoteEngineConfiguration, decrypt, errorHandler, executeCommand, listSettings, prisma, startTraefikProxy, stopTraefikProxy } from '../../../../lib/common'; 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';
import type { CheckDestination, ListDestinations, NewDestination, Proxy, SaveDestinationSettings } from './types'; import type {
CheckDestination,
ListDestinations,
NewDestination,
Proxy,
SaveDestinationSettings
} from './types';
export async function listDestinations(request: FastifyRequest<ListDestinations>) { export async function listDestinations(request: FastifyRequest<ListDestinations>) {
try { try {
const teamId = request.user.teamId; const teamId = request.user.teamId;
const { onlyVerified = false } = request.query const { onlyVerified = false } = request.query;
let destinations = [] let destinations = [];
if (teamId === '0') { if (teamId === '0') {
destinations = await prisma.destinationDocker.findMany({ include: { teams: true } }); destinations = await prisma.destinationDocker.findMany({ include: { teams: true } });
} else { } else {
@@ -24,13 +33,16 @@ export async function listDestinations(request: FastifyRequest<ListDestinations>
}); });
} }
if (onlyVerified) { if (onlyVerified) {
destinations = destinations.filter(destination => destination.engine || (destination.remoteEngine && destination.remoteVerified)) destinations = destinations.filter(
(destination) =>
destination.engine || (destination.remoteEngine && destination.remoteVerified)
);
} }
return { return {
destinations destinations
} };
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function checkDestination(request: FastifyRequest<CheckDestination>) { export async function checkDestination(request: FastifyRequest<CheckDestination>) {
@@ -42,14 +54,14 @@ export async function checkDestination(request: FastifyRequest<CheckDestination>
message: `Network already exists: ${network}` message: `Network already exists: ${network}`
}; };
} }
return {} return {};
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function getDestination(request: FastifyRequest<OnlyId>) { export async function getDestination(request: FastifyRequest<OnlyId>) {
try { try {
const { id } = request.params const { id } = request.params;
const teamId = request.user?.teamId; const teamId = request.user?.teamId;
const destination = await prisma.destinationDocker.findFirst({ const destination = await prisma.destinationDocker.findFirst({
where: { id, teams: { some: { id: teamId === '0' ? undefined : teamId } } }, where: { id, teams: { some: { id: teamId === '0' ? undefined : teamId } } },
@@ -66,20 +78,22 @@ export async function getDestination(request: FastifyRequest<OnlyId>) {
return { return {
...payload ...payload
}; };
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function newDestination(request: FastifyRequest<NewDestination>, reply: FastifyReply) { export async function newDestination(request: FastifyRequest<NewDestination>, reply: FastifyReply) {
try { try {
const teamId = request.user.teamId; const teamId = request.user.teamId;
const { id } = request.params const { id } = request.params;
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 await executeCommand({ command: `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 await executeCommand({ command: `docker network create --attachable ${network}` }); await await executeCommand({ command: `docker network create --attachable ${network}` });
} }
@@ -90,12 +104,16 @@ export async function newDestination(request: FastifyRequest<NewDestination>, re
const destination = destinations.find((destination) => destination.network === network); const destination = destinations.find((destination) => destination.network === network);
if (destinations.length > 0) { if (destinations.length > 0) {
const proxyConfigured = destinations.find( const proxyConfigured = destinations.find(
(destination) => destination.network !== network && destination.isCoolifyProxyUsed === true (destination) =>
destination.network !== network && destination.isCoolifyProxyUsed === true
); );
if (proxyConfigured) { if (proxyConfigured) {
isCoolifyProxyUsed = !!proxyConfigured.isCoolifyProxyUsed; isCoolifyProxyUsed = !!proxyConfigured.isCoolifyProxyUsed;
} }
await prisma.destinationDocker.updateMany({ where: { engine }, data: { isCoolifyProxyUsed } }); await prisma.destinationDocker.updateMany({
where: { engine },
data: { isCoolifyProxyUsed }
});
} }
if (isCoolifyProxyUsed) { if (isCoolifyProxyUsed) {
await startTraefikProxy(destination.id); await startTraefikProxy(destination.id);
@@ -103,39 +121,60 @@ export async function newDestination(request: FastifyRequest<NewDestination>, re
return reply.code(201).send({ id: destination.id }); return reply.code(201).send({ id: destination.id });
} else { } else {
const destination = await prisma.destinationDocker.create({ const destination = await prisma.destinationDocker.create({
data: { name, teams: { connect: { id: teamId } }, engine, network, isCoolifyProxyUsed, remoteEngine: true, remoteIpAddress, remoteUser, remotePort: Number(remotePort) } data: {
name,
teams: { connect: { id: teamId } },
engine,
network,
isCoolifyProxyUsed,
remoteEngine: true,
remoteIpAddress,
remoteUser,
remotePort: Number(remotePort)
}
}); });
return reply.code(201).send({ id: destination.id }) return reply.code(201).send({ id: destination.id });
} }
} else { } else {
await prisma.destinationDocker.update({ where: { id }, data: { name, engine, network } }); await prisma.destinationDocker.update({ where: { id }, data: { name, engine, network } });
return reply.code(201).send(); return reply.code(201).send();
} }
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function deleteDestination(request: FastifyRequest<OnlyId>) { export async function deleteDestination(request: FastifyRequest<OnlyId>) {
try { try {
const { id } = request.params const { id } = request.params;
const { network, remoteVerified, engine, isCoolifyProxyUsed } = await prisma.destinationDocker.findUnique({ where: { id } }); const appFound = await prisma.application.findFirst({ where: { destinationDockerId: id } });
const serviceFound = await prisma.service.findFirst({ where: { destinationDockerId: id } });
const databaseFound = await prisma.database.findFirst({ where: { destinationDockerId: id } });
if (appFound || serviceFound || databaseFound) {
throw {
message: `Destination is in use.<br>Remove all applications, services and databases using this destination first.`
};
}
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 executeCommand({ 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 executeCommand({ dockerId: id, command: `docker network disconnect ${network} coolify-proxy` }) await executeCommand({
await executeCommand({ dockerId: id, command: `docker network rm ${network}` }) dockerId: id,
command: `docker network disconnect ${network} coolify-proxy`
});
await executeCommand({ dockerId: id, command: `docker network rm ${network}` });
} }
} }
} }
await prisma.destinationDocker.delete({ where: { id } }); await prisma.destinationDocker.delete({ where: { id } });
return {} return {};
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function saveDestinationSettings(request: FastifyRequest<SaveDestinationSettings>) { export async function saveDestinationSettings(request: FastifyRequest<SaveDestinationSettings>) {
@@ -148,33 +187,33 @@ export async function saveDestinationSettings(request: FastifyRequest<SaveDestin
return { return {
status: 202 status: 202
} };
// return reply.code(201).send(); // return reply.code(201).send();
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function startProxy(request: FastifyRequest<Proxy>) { export async function startProxy(request: FastifyRequest<Proxy>) {
const { id } = request.params const { id } = request.params;
try { try {
await startTraefikProxy(id); await startTraefikProxy(id);
return {} return {};
} catch ({ status, message }) { } catch ({ status, message }) {
await stopTraefikProxy(id); await stopTraefikProxy(id);
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function stopProxy(request: FastifyRequest<Proxy>) { export async function stopProxy(request: FastifyRequest<Proxy>) {
const { id } = request.params const { id } = request.params;
try { try {
await stopTraefikProxy(id); await stopTraefikProxy(id);
return {} return {};
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function restartProxy(request: FastifyRequest<Proxy>) { export async function restartProxy(request: FastifyRequest<Proxy>) {
const { id } = request.params const { id } = request.params;
try { try {
await stopTraefikProxy(id); await stopTraefikProxy(id);
await startTraefikProxy(id); await startTraefikProxy(id);
@@ -182,13 +221,13 @@ export async function restartProxy(request: FastifyRequest<Proxy>) {
where: { id }, where: { id },
data: { isCoolifyProxyUsed: true } data: { isCoolifyProxyUsed: true }
}); });
return {} return {};
} catch ({ status, message }) { } catch ({ status, message }) {
await prisma.destinationDocker.update({ await prisma.destinationDocker.update({
where: { id }, where: { id },
data: { isCoolifyProxyUsed: false } data: { isCoolifyProxyUsed: false }
}); });
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
@@ -196,84 +235,119 @@ export async function assignSSHKey(request: FastifyRequest) {
try { try {
const { id: sshKeyId } = request.body; const { id: sshKeyId } = request.body;
const { id } = request.params; const { id } = request.params;
await prisma.destinationDocker.update({ where: { id }, data: { sshKey: { connect: { id: sshKeyId } } } }) await prisma.destinationDocker.update({
return {} where: { id },
data: { sshKey: { connect: { id: sshKeyId } } }
});
return {};
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function verifyRemoteDockerEngineFn(id: string) { export async function verifyRemoteDockerEngineFn(id: string) {
const { remoteIpAddress, network, isCoolifyProxyUsed } = await prisma.destinationDocker.findFirst({ where: { id } }) const { remoteIpAddress, network, isCoolifyProxyUsed } = await prisma.destinationDocker.findFirst(
const daemonJson = `daemon-${id}.json` { where: { id } }
);
const daemonJson = `daemon-${id}.json`;
try { try {
await executeCommand({ sshCommand: true, command: `docker network inspect ${network}`, dockerId: id }); await executeCommand({
sshCommand: true,
command: `docker network inspect ${network}`,
dockerId: id
});
} catch (error) { } catch (error) {
await executeCommand({ command: `docker network create --attachable ${network}`, dockerId: id }); await executeCommand({
command: `docker network create --attachable ${network}`,
dockerId: id
});
} }
try { try {
await executeCommand({ sshCommand: true, command: `docker network inspect coolify-infra`, dockerId: id }); await executeCommand({
sshCommand: true,
command: `docker network inspect coolify-infra`,
dockerId: id
});
} catch (error) { } catch (error) {
await executeCommand({ command: `docker network create --attachable coolify-infra`, dockerId: id }); await executeCommand({
command: `docker network create --attachable coolify-infra`,
dockerId: id
});
} }
if (isCoolifyProxyUsed) await startTraefikProxy(id); if (isCoolifyProxyUsed) await startTraefikProxy(id);
let isUpdated = false; let isUpdated = false;
let daemonJsonParsed = { let daemonJsonParsed = {
"live-restore": true, 'live-restore': true,
"features": { features: {
"buildkit": true buildkit: true
} }
}; };
try { try {
const { stdout: daemonJson } = await executeCommand({ sshCommand: true, dockerId: id, command: `cat /etc/docker/daemon.json` }); const { stdout: daemonJson } = await executeCommand({
sshCommand: true,
dockerId: id,
command: `cat /etc/docker/daemon.json`
});
daemonJsonParsed = JSON.parse(daemonJson); daemonJsonParsed = JSON.parse(daemonJson);
if (!daemonJsonParsed['live-restore'] || daemonJsonParsed['live-restore'] !== true) { if (!daemonJsonParsed['live-restore'] || daemonJsonParsed['live-restore'] !== true) {
isUpdated = true; isUpdated = true;
daemonJsonParsed['live-restore'] = true daemonJsonParsed['live-restore'] = true;
} }
if (!daemonJsonParsed?.features?.buildkit) { if (!daemonJsonParsed?.features?.buildkit) {
isUpdated = true; isUpdated = true;
daemonJsonParsed.features = { daemonJsonParsed.features = {
buildkit: true buildkit: true
} };
} }
} catch (error) { } catch (error) {
isUpdated = true; isUpdated = true;
} }
try { try {
if (isUpdated) { if (isUpdated) {
await executeCommand({ shell: true, command: `echo '${JSON.stringify(daemonJsonParsed, null, 2)}' > /tmp/${daemonJson}` }) await executeCommand({
await executeCommand({ dockerId: id, command: `scp /tmp/${daemonJson} ${remoteIpAddress}-remote:/etc/docker/daemon.json` }); shell: true,
await executeCommand({ command: `rm /tmp/${daemonJson}` }) command: `echo '${JSON.stringify(daemonJsonParsed, null, 2)}' > /tmp/${daemonJson}`
});
await executeCommand({
dockerId: id,
command: `scp /tmp/${daemonJson} ${remoteIpAddress}-remote:/etc/docker/daemon.json`
});
await executeCommand({ command: `rm /tmp/${daemonJson}` });
await executeCommand({ sshCommand: true, dockerId: id, command: `systemctl restart docker` }); await executeCommand({ sshCommand: true, dockerId: id, command: `systemctl restart docker` });
} }
await prisma.destinationDocker.update({ where: { id }, data: { remoteVerified: true } }) await prisma.destinationDocker.update({ where: { id }, data: { remoteVerified: true } });
} catch (error) { } catch (error) {
throw new Error('Error while verifying remote docker engine') throw new Error('Error while verifying remote docker engine');
} }
} }
export async function verifyRemoteDockerEngine(request: FastifyRequest<OnlyId>, reply: FastifyReply) { export async function verifyRemoteDockerEngine(
request: FastifyRequest<OnlyId>,
reply: FastifyReply
) {
const { id } = request.params; const { id } = request.params;
try { try {
await verifyRemoteDockerEngineFn(id); await verifyRemoteDockerEngineFn(id);
return reply.code(201).send() return reply.code(201).send();
} catch ({ status, message }) { } catch ({ status, message }) {
await prisma.destinationDocker.update({ where: { id }, data: { remoteVerified: false } }) await prisma.destinationDocker.update({ where: { id }, data: { remoteVerified: false } });
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function getDestinationStatus(request: FastifyRequest<OnlyId>) { export async function getDestinationStatus(request: FastifyRequest<OnlyId>) {
try { try {
const { id } = request.params const { id } = request.params;
const destination = await prisma.destinationDocker.findUnique({ where: { id } }) const destination = await prisma.destinationDocker.findUnique({ where: { id } });
const { found: isRunning } = await checkContainer({ dockerId: destination.id, container: 'coolify-proxy', remove: true }) const { found: isRunning } = await checkContainer({
dockerId: destination.id,
container: 'coolify-proxy',
remove: true
});
return { return {
isRunning isRunning
} };
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }

View File

@@ -1,6 +1,5 @@
import cuid from 'cuid'; import cuid from 'cuid';
import type { FastifyRequest } from 'fastify'; import type { FastifyRequest } from 'fastify';
import { FastifyReply } from 'fastify';
import { decrypt, encrypt, errorHandler, prisma } from '../../../../lib/common'; import { decrypt, encrypt, errorHandler, prisma } from '../../../../lib/common';
import { OnlyId } from '../../../../types'; import { OnlyId } from '../../../../types';
import { CheckGitLabOAuthId, SaveGitHubSource, SaveGitLabSource } from './types'; import { CheckGitLabOAuthId, SaveGitHubSource, SaveGitLabSource } from './types';
@@ -9,34 +8,39 @@ export async function listSources(request: FastifyRequest) {
try { try {
const teamId = request.user?.teamId; const teamId = request.user?.teamId;
const sources = await prisma.gitSource.findMany({ const sources = await prisma.gitSource.findMany({
where: { OR: [{ teams: { some: { id: teamId === "0" ? undefined : teamId } } }, { isSystemWide: true }] }, where: {
OR: [
{ teams: { some: { id: teamId === '0' ? undefined : teamId } } },
{ isSystemWide: true }
]
},
include: { teams: true, githubApp: true, gitlabApp: true } include: { teams: true, githubApp: true, gitlabApp: true }
}); });
return { return {
sources sources
} };
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function saveSource(request, reply) { export async function saveSource(request, reply) {
try { try {
const { id } = request.params const { id } = request.params;
let { name, htmlUrl, apiUrl, customPort, customUser, isSystemWide } = request.body let { name, htmlUrl, apiUrl, customPort, customUser, isSystemWide } = request.body;
if (customPort) customPort = Number(customPort) if (customPort) customPort = Number(customPort);
await prisma.gitSource.update({ await prisma.gitSource.update({
where: { id }, where: { id },
data: { name, htmlUrl, apiUrl, customPort, customUser, isSystemWide } data: { name, htmlUrl, apiUrl, customPort, customUser, isSystemWide }
}); });
return reply.code(201).send() return reply.code(201).send();
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function getSource(request: FastifyRequest<OnlyId>) { export async function getSource(request: FastifyRequest<OnlyId>) {
try { try {
const { id } = request.params const { id } = request.params;
const { teamId } = request.user const { teamId } = request.user;
const settings = await prisma.setting.findFirst({}); const settings = await prisma.setting.findFirst({});
if (id === 'new') { if (id === 'new') {
@@ -48,40 +52,54 @@ export async function getSource(request: FastifyRequest<OnlyId>) {
apiUrl: null, apiUrl: null,
organization: null, organization: null,
customPort: 22, customPort: 22,
customUser: 'git', customUser: 'git'
}, },
settings settings
} };
} }
const source = await prisma.gitSource.findFirst({ const source = await prisma.gitSource.findFirst({
where: { id, OR: [{ teams: { some: { id: teamId === "0" ? undefined : teamId } } }, { isSystemWide: true }] }, where: {
id,
OR: [
{ teams: { some: { id: teamId === '0' ? undefined : teamId } } },
{ isSystemWide: true }
]
},
include: { githubApp: true, gitlabApp: true } include: { githubApp: true, gitlabApp: true }
}); });
if (!source) { if (!source) {
throw { status: 404, message: 'Source not found.' } throw { status: 404, message: 'Source not found.' };
} }
if (source?.githubApp?.clientSecret) if (source?.githubApp?.clientSecret)
source.githubApp.clientSecret = decrypt(source.githubApp.clientSecret); source.githubApp.clientSecret = decrypt(source.githubApp.clientSecret);
if (source?.githubApp?.webhookSecret) if (source?.githubApp?.webhookSecret)
source.githubApp.webhookSecret = decrypt(source.githubApp.webhookSecret); source.githubApp.webhookSecret = decrypt(source.githubApp.webhookSecret);
if (source?.githubApp?.privateKey) source.githubApp.privateKey = decrypt(source.githubApp.privateKey); if (source?.githubApp?.privateKey)
if (source?.gitlabApp?.appSecret) source.gitlabApp.appSecret = decrypt(source.gitlabApp.appSecret); source.githubApp.privateKey = decrypt(source.githubApp.privateKey);
if (source?.gitlabApp?.appSecret)
source.gitlabApp.appSecret = decrypt(source.gitlabApp.appSecret);
return { return {
source, source,
settings settings
}; };
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function deleteSource(request) { export async function deleteSource(request) {
try { try {
const { id } = request.params const { id } = request.params;
const gitAppFound = await prisma.application.findFirst({ where: { gitSourceId: id } });
if (gitAppFound) {
throw {
status: 400,
message: 'This source is used by an application. Please remove the application first.'
};
}
const source = await prisma.gitSource.delete({ const source = await prisma.gitSource.delete({
where: { id }, where: { id },
include: { githubApp: true, gitlabApp: true } include: { githubApp: true, gitlabApp: true }
@@ -92,22 +110,21 @@ export async function deleteSource(request) {
if (source.gitlabAppId) { if (source.gitlabAppId) {
await prisma.gitlabApp.delete({ where: { id: source.gitlabAppId } }); await prisma.gitlabApp.delete({ where: { id: source.gitlabAppId } });
} }
return {} return {};
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function saveGitHubSource(request: FastifyRequest<SaveGitHubSource>) { export async function saveGitHubSource(request: FastifyRequest<SaveGitHubSource>) {
try { try {
const { teamId } = request.user const { teamId } = request.user;
const { id } = request.params const { id } = request.params;
let { name, htmlUrl, apiUrl, organization, customPort, isSystemWide } = request.body let { name, htmlUrl, apiUrl, organization, customPort, isSystemWide } = request.body;
if (customPort) customPort = Number(customPort) if (customPort) customPort = Number(customPort);
if (id === 'new') { if (id === 'new') {
const newId = cuid() const newId = cuid();
await prisma.gitSource.create({ await prisma.gitSource.create({
data: { data: {
id: newId, id: newId,
@@ -123,27 +140,48 @@ export async function saveGitHubSource(request: FastifyRequest<SaveGitHubSource>
}); });
return { return {
id: newId id: newId
};
} }
} throw { status: 500, message: 'Wrong request.' };
throw { status: 500, message: 'Wrong request.' }
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function saveGitLabSource(request: FastifyRequest<SaveGitLabSource>) { export async function saveGitLabSource(request: FastifyRequest<SaveGitLabSource>) {
try { try {
const { id } = request.params const { id } = request.params;
const { teamId } = request.user const { teamId } = request.user;
let { type, name, htmlUrl, apiUrl, oauthId, appId, appSecret, groupName, customPort, customUser } = let {
request.body type,
name,
htmlUrl,
apiUrl,
oauthId,
appId,
appSecret,
groupName,
customPort,
customUser
} = request.body;
if (oauthId) oauthId = Number(oauthId); if (oauthId) oauthId = Number(oauthId);
if (customPort) customPort = Number(customPort) if (customPort) customPort = Number(customPort);
const encryptedAppSecret = encrypt(appSecret); const encryptedAppSecret = encrypt(appSecret);
if (id === 'new') { if (id === 'new') {
const newId = cuid() const newId = cuid();
await prisma.gitSource.create({ data: { id: newId, type, apiUrl, htmlUrl, name, customPort, customUser, teams: { connect: { id: teamId } } } }); await prisma.gitSource.create({
data: {
id: newId,
type,
apiUrl,
htmlUrl,
name,
customPort,
customUser,
teams: { connect: { id: teamId } }
}
});
await prisma.gitlabApp.create({ await prisma.gitlabApp.create({
data: { data: {
teams: { connect: { id: teamId } }, teams: { connect: { id: teamId } },
@@ -157,35 +195,37 @@ export async function saveGitLabSource(request: FastifyRequest<SaveGitLabSource>
return { return {
status: 201, status: 201,
id: newId id: newId
} };
} else { } else {
await prisma.gitSource.update({ where: { id }, data: { type, apiUrl, htmlUrl, name, customPort, customUser } }); await prisma.gitSource.update({
where: { id },
data: { type, apiUrl, htmlUrl, name, customPort, customUser }
});
await prisma.gitlabApp.update({ await prisma.gitlabApp.update({
where: { id }, where: { id },
data: { data: {
appId, appId,
oauthId, oauthId,
groupName, groupName,
appSecret: encryptedAppSecret, appSecret: encryptedAppSecret
} }
}); });
} }
return { status: 201 }; return { status: 201 };
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }
export async function checkGitLabOAuthID(request: FastifyRequest<CheckGitLabOAuthId>) { export async function checkGitLabOAuthID(request: FastifyRequest<CheckGitLabOAuthId>) {
try { try {
const { oauthId } = request.body const { oauthId } = request.body;
const found = await prisma.gitlabApp.findFirst({ where: { oauthId: Number(oauthId) } }); const found = await prisma.gitlabApp.findFirst({ where: { oauthId: Number(oauthId) } });
if (found) { if (found) {
throw { status: 500, message: 'OAuthID already configured in Coolify.' } throw { status: 500, message: 'OAuthID already configured in Coolify.' };
} }
return {} return {};
} catch ({ status, message }) { } catch ({ status, message }) {
return errorHandler({ status, message }) return errorHandler({ status, message });
} }
} }

View File

@@ -543,6 +543,9 @@ export async function proxyConfiguration(request: FastifyRequest<OnlyId>, remote
const template: any = await parseAndFindServiceTemplates(service, null, true); const template: any = await parseAndFindServiceTemplates(service, null, true);
const { proxy } = template.services[oneService] || found.services[oneService]; const { proxy } = template.services[oneService] || found.services[oneService];
for (let configuration of proxy) { for (let configuration of proxy) {
if (configuration.hostPort) {
continue;
}
if (configuration.domain) { if (configuration.domain) {
const setting = serviceSetting.find( const setting = serviceSetting.find(
(a) => a.variableName === configuration.domain (a) => a.variableName === configuration.domain

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,7 @@
{ {
"name": "coolify", "name": "coolify",
"description": "An open-source & self-hostable Heroku / Netlify alternative.", "description": "An open-source & self-hostable Heroku / Netlify alternative.",
"version": "3.12.28", "version": "3.12.30",
"license": "Apache-2.0", "license": "Apache-2.0",
"repository": "github:coollabsio/coolify", "repository": "github:coollabsio/coolify",
"scripts": { "scripts": {