mirror of
https://github.com/andwati/dokploy.git
synced 2026-11-03 10:42:16 +00:00
Merge branch 'canary' into fix/docker-cleanup-clears-away-all-unused-residue
This commit is contained in:
@@ -49,7 +49,6 @@ import {
|
||||
updatePreviewDeployment,
|
||||
} from "./preview-deployment";
|
||||
import { validUniqueServerAppName } from "./project";
|
||||
import { createRollback } from "./rollbacks";
|
||||
export type Application = typeof applications.$inferSelect;
|
||||
|
||||
export const createApplication = async (
|
||||
@@ -112,6 +111,8 @@ export const findApplicationById = async (applicationId: string) => {
|
||||
gitea: true,
|
||||
server: true,
|
||||
previewDeployments: true,
|
||||
buildRegistry: true,
|
||||
rollbackRegistry: true,
|
||||
},
|
||||
});
|
||||
if (!application) {
|
||||
@@ -172,6 +173,7 @@ export const deployApplication = async ({
|
||||
descriptionLog: string;
|
||||
}) => {
|
||||
const application = await findApplicationById(applicationId);
|
||||
const serverId = application.buildServerId || application.serverId;
|
||||
|
||||
const buildLink = `${await getDokployUrl()}/dashboard/project/${application.environment.projectId}/environment/${application.environmentId}/services/application/${application.applicationId}?tab=deployments`;
|
||||
const deployment = await createDeployment({
|
||||
@@ -196,11 +198,11 @@ export const deployApplication = async ({
|
||||
command += await buildRemoteDocker(application);
|
||||
}
|
||||
|
||||
command += getBuildCommand(application);
|
||||
command += await getBuildCommand(application);
|
||||
|
||||
const commandWithLog = `(${command}) >> ${deployment.logPath} 2>&1`;
|
||||
if (application.serverId) {
|
||||
await execAsyncRemote(application.serverId, commandWithLog);
|
||||
if (serverId) {
|
||||
await execAsyncRemote(serverId, commandWithLog);
|
||||
} else {
|
||||
await execAsync(commandWithLog);
|
||||
}
|
||||
@@ -209,17 +211,6 @@ export const deployApplication = async ({
|
||||
await updateDeploymentStatus(deployment.deploymentId, "done");
|
||||
await updateApplicationStatus(applicationId, "done");
|
||||
|
||||
if (application.rollbackActive) {
|
||||
const tagImage =
|
||||
application.sourceType === "docker"
|
||||
? application.dockerImage
|
||||
: application.appName;
|
||||
await createRollback({
|
||||
appName: tagImage || "",
|
||||
deploymentId: deployment.deploymentId,
|
||||
});
|
||||
}
|
||||
|
||||
await sendBuildSuccessNotifications({
|
||||
projectName: application.environment.project.name,
|
||||
applicationName: application.name,
|
||||
@@ -240,8 +231,8 @@ export const deployApplication = async ({
|
||||
}
|
||||
|
||||
command += `echo "\nError occurred ❌, check the logs for details." >> ${deployment.logPath};`;
|
||||
if (application.serverId) {
|
||||
await execAsyncRemote(application.serverId, command);
|
||||
if (serverId) {
|
||||
await execAsyncRemote(serverId, command);
|
||||
} else {
|
||||
await execAsync(command);
|
||||
}
|
||||
@@ -285,6 +276,7 @@ export const rebuildApplication = async ({
|
||||
descriptionLog: string;
|
||||
}) => {
|
||||
const application = await findApplicationById(applicationId);
|
||||
const serverId = application.buildServerId || application.serverId;
|
||||
const buildLink = `${await getDokployUrl()}/dashboard/project/${application.environment.projectId}/environment/${application.environmentId}/services/application/${application.applicationId}?tab=deployments`;
|
||||
|
||||
const deployment = await createDeployment({
|
||||
@@ -296,10 +288,10 @@ export const rebuildApplication = async ({
|
||||
try {
|
||||
let command = "set -e;";
|
||||
// Check case for docker only
|
||||
command += getBuildCommand(application);
|
||||
command += await getBuildCommand(application);
|
||||
const commandWithLog = `(${command}) >> ${deployment.logPath} 2>&1`;
|
||||
if (application.serverId) {
|
||||
await execAsyncRemote(application.serverId, commandWithLog);
|
||||
if (serverId) {
|
||||
await execAsyncRemote(serverId, commandWithLog);
|
||||
} else {
|
||||
await execAsync(commandWithLog);
|
||||
}
|
||||
@@ -307,17 +299,6 @@ export const rebuildApplication = async ({
|
||||
await updateDeploymentStatus(deployment.deploymentId, "done");
|
||||
await updateApplicationStatus(applicationId, "done");
|
||||
|
||||
if (application.rollbackActive) {
|
||||
const tagImage =
|
||||
application.sourceType === "docker"
|
||||
? application.dockerImage
|
||||
: application.appName;
|
||||
await createRollback({
|
||||
appName: tagImage || "",
|
||||
deploymentId: deployment.deploymentId,
|
||||
});
|
||||
}
|
||||
|
||||
await sendBuildSuccessNotifications({
|
||||
projectName: application.environment.project.name,
|
||||
applicationName: application.name,
|
||||
@@ -338,8 +319,8 @@ export const rebuildApplication = async ({
|
||||
}
|
||||
|
||||
command += `echo "\nError occurred ❌, check the logs for details." >> ${deployment.logPath};`;
|
||||
if (application.serverId) {
|
||||
await execAsyncRemote(application.serverId, command);
|
||||
if (serverId) {
|
||||
await execAsyncRemote(serverId, command);
|
||||
} else {
|
||||
await execAsync(command);
|
||||
}
|
||||
@@ -420,6 +401,10 @@ export const deployPreviewApplication = async ({
|
||||
application.env = `${application.previewEnv}\nDOKPLOY_DEPLOY_URL=${previewDeployment?.domain?.host}`;
|
||||
application.buildArgs = `${application.previewBuildArgs}\nDOKPLOY_DEPLOY_URL=${previewDeployment?.domain?.host}`;
|
||||
application.buildSecrets = `${application.previewBuildSecrets}\nDOKPLOY_DEPLOY_URL=${previewDeployment?.domain?.host}`;
|
||||
application.rollbackActive = false;
|
||||
application.buildRegistry = null;
|
||||
application.rollbackRegistry = null;
|
||||
application.registry = null;
|
||||
|
||||
let command = "set -e;";
|
||||
if (application.sourceType === "github") {
|
||||
@@ -428,7 +413,7 @@ export const deployPreviewApplication = async ({
|
||||
appName: previewDeployment.appName,
|
||||
branch: previewDeployment.branch,
|
||||
});
|
||||
command += getBuildCommand(application);
|
||||
command += await getBuildCommand(application);
|
||||
|
||||
const commandWithLog = `(${command}) >> ${deployment.logPath} 2>&1`;
|
||||
if (application.serverId) {
|
||||
|
||||
@@ -78,7 +78,6 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"89.187.188.227",
|
||||
"89.187.188.228",
|
||||
"139.180.134.196",
|
||||
"89.38.96.158",
|
||||
"89.187.162.249",
|
||||
"89.187.162.242",
|
||||
"185.102.217.65",
|
||||
@@ -106,12 +105,9 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"200.25.38.69",
|
||||
"200.25.42.70",
|
||||
"200.25.36.166",
|
||||
"195.206.229.106",
|
||||
"194.242.11.186",
|
||||
"185.164.35.8",
|
||||
"94.20.154.22",
|
||||
"185.93.1.244",
|
||||
"156.59.145.154",
|
||||
"143.244.49.177",
|
||||
"138.199.46.66",
|
||||
"138.199.37.227",
|
||||
@@ -136,7 +132,6 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"84.17.59.115",
|
||||
"89.187.165.194",
|
||||
"138.199.15.193",
|
||||
"89.35.237.170",
|
||||
"37.19.216.130",
|
||||
"185.93.1.247",
|
||||
"185.93.3.244",
|
||||
@@ -150,6 +145,7 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"84.17.63.178",
|
||||
"200.25.32.131",
|
||||
"37.19.207.34",
|
||||
"37.19.207.38",
|
||||
"192.189.65.146",
|
||||
"143.244.45.177",
|
||||
"185.93.1.249",
|
||||
@@ -168,9 +164,7 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"129.227.217.178",
|
||||
"129.227.217.179",
|
||||
"200.25.69.94",
|
||||
"128.1.52.179",
|
||||
"200.25.16.103",
|
||||
"15.235.54.226",
|
||||
"102.67.138.155",
|
||||
"156.146.43.65",
|
||||
"195.181.163.203",
|
||||
@@ -278,13 +272,11 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"107.155.47.146",
|
||||
"193.201.190.174",
|
||||
"156.59.95.218",
|
||||
"213.170.143.139",
|
||||
"129.227.186.154",
|
||||
"195.238.127.98",
|
||||
"200.25.22.6",
|
||||
"204.16.244.92",
|
||||
"200.25.70.101",
|
||||
"200.25.66.100",
|
||||
"139.180.209.182",
|
||||
"103.108.231.41",
|
||||
"103.108.229.5",
|
||||
@@ -387,46 +379,13 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"38.54.5.37",
|
||||
"38.54.3.92",
|
||||
"185.165.170.74",
|
||||
"207.121.80.118",
|
||||
"207.121.46.228",
|
||||
"207.121.46.236",
|
||||
"207.121.46.244",
|
||||
"207.121.46.252",
|
||||
"216.202.235.164",
|
||||
"207.121.46.220",
|
||||
"207.121.75.132",
|
||||
"207.121.80.12",
|
||||
"207.121.80.172",
|
||||
"207.121.90.60",
|
||||
"207.121.90.68",
|
||||
"207.121.97.204",
|
||||
"207.121.90.252",
|
||||
"207.121.97.236",
|
||||
"207.121.99.12",
|
||||
"138.199.24.219",
|
||||
"185.93.2.251",
|
||||
"138.199.46.65",
|
||||
"207.121.41.196",
|
||||
"207.121.99.20",
|
||||
"207.121.99.36",
|
||||
"207.121.99.44",
|
||||
"207.121.99.52",
|
||||
"207.121.99.60",
|
||||
"207.121.23.68",
|
||||
"207.121.23.124",
|
||||
"207.121.23.244",
|
||||
"207.121.23.180",
|
||||
"207.121.23.188",
|
||||
"207.121.23.196",
|
||||
"207.121.23.204",
|
||||
"207.121.24.52",
|
||||
"207.121.24.60",
|
||||
"207.121.24.68",
|
||||
"207.121.24.76",
|
||||
"207.121.24.92",
|
||||
"207.121.24.100",
|
||||
"207.121.24.108",
|
||||
"207.121.24.116",
|
||||
"154.95.86.76",
|
||||
"5.9.99.73",
|
||||
"78.46.92.118",
|
||||
@@ -434,14 +393,52 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"78.46.156.89",
|
||||
"88.198.9.155",
|
||||
"144.76.79.22",
|
||||
"103.1.215.93",
|
||||
"103.137.12.33",
|
||||
"103.107.196.31",
|
||||
"116.90.72.155",
|
||||
"103.137.14.5",
|
||||
"116.90.75.65",
|
||||
"37.19.207.37",
|
||||
"208.83.234.224",
|
||||
"79.127.237.104",
|
||||
"79.127.243.187",
|
||||
"45.156.248.73",
|
||||
"79.127.134.225",
|
||||
"79.127.134.226",
|
||||
"79.127.134.227",
|
||||
"79.127.134.228",
|
||||
"79.127.134.229",
|
||||
"79.127.134.230",
|
||||
"79.127.134.231",
|
||||
"79.127.134.130",
|
||||
"79.127.134.131",
|
||||
"79.127.134.132",
|
||||
"79.127.134.234",
|
||||
"79.127.134.235",
|
||||
"185.111.111.154",
|
||||
"185.111.111.155",
|
||||
"185.111.111.156",
|
||||
"185.111.111.157",
|
||||
"185.111.111.158",
|
||||
"185.111.111.159",
|
||||
"185.111.111.160",
|
||||
"141.227.142.242",
|
||||
"94.128.254.166",
|
||||
"195.206.229.69",
|
||||
"200.25.86.90",
|
||||
"148.113.190.161",
|
||||
"46.151.194.242",
|
||||
"46.151.194.243",
|
||||
"212.102.40.120",
|
||||
"213.170.143.100",
|
||||
"154.93.86.71",
|
||||
"143.244.60.196",
|
||||
"143.244.60.197",
|
||||
"143.244.60.195",
|
||||
"79.127.134.129",
|
||||
"79.127.134.133",
|
||||
"152.233.22.97",
|
||||
"152.233.22.98",
|
||||
"152.233.22.100",
|
||||
"152.233.22.99",
|
||||
"152.233.22.101",
|
||||
"152.233.22.102",
|
||||
"152.233.22.103",
|
||||
"116.202.155.146",
|
||||
"116.202.193.178",
|
||||
"116.202.224.168",
|
||||
@@ -502,6 +499,12 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"103.60.15.166",
|
||||
"103.60.15.167",
|
||||
"103.60.15.168",
|
||||
"176.9.139.94",
|
||||
"148.251.129.132",
|
||||
"148.251.131.73",
|
||||
"148.251.131.74",
|
||||
"136.243.70.170",
|
||||
"148.251.131.238",
|
||||
"109.248.43.116",
|
||||
"109.248.43.117",
|
||||
"109.248.43.162",
|
||||
@@ -527,7 +530,9 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"139.180.129.216",
|
||||
"139.99.174.7",
|
||||
"89.187.169.18",
|
||||
"143.244.38.133",
|
||||
"89.187.179.7",
|
||||
"169.150.213.50",
|
||||
"143.244.62.213",
|
||||
"185.93.3.246",
|
||||
"195.181.163.198",
|
||||
@@ -535,7 +540,6 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"84.17.37.211",
|
||||
"212.102.50.54",
|
||||
"212.102.46.115",
|
||||
"143.244.38.135",
|
||||
"169.150.238.21",
|
||||
"169.150.207.51",
|
||||
"169.150.207.49",
|
||||
@@ -546,7 +550,6 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"169.150.247.139",
|
||||
"169.150.247.177",
|
||||
"169.150.247.178",
|
||||
"169.150.213.49",
|
||||
"212.102.46.119",
|
||||
"84.17.38.234",
|
||||
"84.17.38.233",
|
||||
@@ -558,7 +561,6 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"169.150.247.138",
|
||||
"169.150.247.184",
|
||||
"169.150.247.185",
|
||||
"156.146.58.83",
|
||||
"212.102.43.88",
|
||||
"89.187.169.26",
|
||||
"109.61.89.57",
|
||||
@@ -587,6 +589,17 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"138.199.4.177",
|
||||
"37.19.222.34",
|
||||
"46.151.193.85",
|
||||
"79.127.237.99",
|
||||
"212.104.158.30",
|
||||
"212.104.158.31",
|
||||
"212.104.158.32",
|
||||
"212.104.158.33",
|
||||
"212.104.158.34",
|
||||
"212.104.158.28",
|
||||
"212.104.158.29",
|
||||
"212.104.158.35",
|
||||
"212.104.158.36",
|
||||
"212.104.158.37",
|
||||
"212.104.158.17",
|
||||
"212.104.158.18",
|
||||
"212.104.158.19",
|
||||
@@ -595,12 +608,20 @@ const BUNNY_CDN_IPS = new Set([
|
||||
"212.104.158.22",
|
||||
"212.104.158.24",
|
||||
"212.104.158.26",
|
||||
"79.127.237.134",
|
||||
"89.187.184.177",
|
||||
"89.187.184.179",
|
||||
"89.187.184.173",
|
||||
"89.187.184.178",
|
||||
"89.187.184.176",
|
||||
"212.104.158.25",
|
||||
"212.104.158.27",
|
||||
"212.104.158.67",
|
||||
"212.104.158.10",
|
||||
"212.104.158.12",
|
||||
"212.104.158.64",
|
||||
"212.104.158.16",
|
||||
"212.104.158.23",
|
||||
"212.104.158.54",
|
||||
]);
|
||||
|
||||
// Arvancloud IP ranges
|
||||
|
||||
@@ -80,7 +80,7 @@ export const createDeployment = async (
|
||||
"application",
|
||||
application.serverId,
|
||||
);
|
||||
const serverId = application.serverId;
|
||||
const serverId = application.buildServerId || application.serverId;
|
||||
|
||||
const { LOGS_PATH } = paths(!!serverId);
|
||||
const formattedDateTime = format(new Date(), "yyyy-MM-dd:HH:mm:ss");
|
||||
@@ -93,6 +93,7 @@ export const createDeployment = async (
|
||||
const command = `
|
||||
mkdir -p ${LOGS_PATH}/${application.appName};
|
||||
echo "Initializing deployment" >> ${logFilePath};
|
||||
echo "Building on ${serverId ? "Build Server" : "Dokploy Server"}" >> ${logFilePath};
|
||||
`;
|
||||
|
||||
await execAsyncRemote(server.serverId, command);
|
||||
@@ -112,6 +113,9 @@ export const createDeployment = async (
|
||||
logPath: logFilePath,
|
||||
description: deployment.description || "",
|
||||
startedAt: new Date().toISOString(),
|
||||
...(application.buildServerId && {
|
||||
buildServerId: application.buildServerId,
|
||||
}),
|
||||
})
|
||||
.returning();
|
||||
if (deploymentCreate.length === 0 || !deploymentCreate[0]) {
|
||||
|
||||
@@ -19,6 +19,7 @@ export const createDomain = async (input: typeof apiCreateDomain._type) => {
|
||||
.insert(domains)
|
||||
.values({
|
||||
...input,
|
||||
host: input.host?.trim(),
|
||||
})
|
||||
.returning()
|
||||
.then((response) => response[0]);
|
||||
@@ -120,6 +121,7 @@ export const updateDomainById = async (
|
||||
.update(domains)
|
||||
.set({
|
||||
...domainData,
|
||||
...(domainData.host && { host: domainData.host.trim() }),
|
||||
})
|
||||
.where(eq(domains.domainId, domainId))
|
||||
.returning();
|
||||
|
||||
@@ -498,7 +498,7 @@ export const createNtfyNotification = async (
|
||||
.values({
|
||||
serverUrl: input.serverUrl,
|
||||
topic: input.topic,
|
||||
accessToken: input.accessToken,
|
||||
accessToken: input.accessToken ?? null,
|
||||
priority: input.priority,
|
||||
})
|
||||
.returning()
|
||||
@@ -569,7 +569,7 @@ export const updateNtfyNotification = async (
|
||||
.set({
|
||||
serverUrl: input.serverUrl,
|
||||
topic: input.topic,
|
||||
accessToken: input.accessToken,
|
||||
accessToken: input.accessToken ?? null,
|
||||
priority: input.priority,
|
||||
})
|
||||
.where(eq(ntfy.ntfyId, input.ntfyId));
|
||||
|
||||
@@ -19,7 +19,8 @@ export function getMountPath(dockerImage: string): string {
|
||||
if (versionMatch?.[1]) {
|
||||
const version = Number.parseInt(versionMatch[1], 10);
|
||||
if (version >= 18) {
|
||||
return `/var/lib/postgresql/${version}/data`;
|
||||
// PostgreSQL 18+ uses /var/lib/postgresql/{version}/docker as the default PGDATA
|
||||
return `/var/lib/postgresql/${version}/docker`;
|
||||
}
|
||||
}
|
||||
return "/var/lib/postgresql/data";
|
||||
|
||||
@@ -7,7 +7,8 @@ import {
|
||||
deployments as deploymentsSchema,
|
||||
rollbacks,
|
||||
} from "../db/schema";
|
||||
import { type ApplicationNested, getAuthConfig } from "../utils/builders";
|
||||
import type { ApplicationNested } from "../utils/builders";
|
||||
import { getRegistryTag } from "../utils/cluster/upload";
|
||||
import {
|
||||
calculateResources,
|
||||
generateBindMounts,
|
||||
@@ -22,11 +23,12 @@ import { findDeploymentById } from "./deployment";
|
||||
import type { Mount } from "./mount";
|
||||
import type { Port } from "./port";
|
||||
import type { Project } from "./project";
|
||||
import type { Registry } from "./registry";
|
||||
|
||||
export const createRollback = async (
|
||||
input: z.infer<typeof createRollbackSchema>,
|
||||
) => {
|
||||
await db.transaction(async (tx) => {
|
||||
return await db.transaction(async (tx) => {
|
||||
const { fullContext, ...other } = input;
|
||||
const rollback = await tx
|
||||
.insert(rollbacks)
|
||||
@@ -70,9 +72,11 @@ export const createRollback = async (
|
||||
})
|
||||
.where(eq(deploymentsSchema.deploymentId, rollback.deploymentId));
|
||||
|
||||
await createRollbackImage(rest, tagImage);
|
||||
const updatedRollback = await tx.query.rollbacks.findFirst({
|
||||
where: eq(rollbacks.rollbackId, rollback.rollbackId),
|
||||
});
|
||||
|
||||
return rollback;
|
||||
return updatedRollback;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -103,27 +107,6 @@ export const findRollbackById = async (rollbackId: string) => {
|
||||
return result;
|
||||
};
|
||||
|
||||
const createRollbackImage = async (
|
||||
application: ApplicationNested,
|
||||
tagImage: string,
|
||||
) => {
|
||||
const docker = await getRemoteDocker(application.serverId);
|
||||
|
||||
const appTagName =
|
||||
application.sourceType === "docker"
|
||||
? application.dockerImage
|
||||
: `${application.appName}:latest`;
|
||||
|
||||
const result = docker.getImage(appTagName || "");
|
||||
|
||||
const [repo, version] = tagImage.split(":");
|
||||
|
||||
await result.tag({
|
||||
repo,
|
||||
tag: version,
|
||||
});
|
||||
};
|
||||
|
||||
const deleteRollbackImage = async (image: string, serverId?: string | null) => {
|
||||
const command = `docker image rm ${image} --force`;
|
||||
|
||||
@@ -179,7 +162,6 @@ export const rollback = async (rollbackId: string) => {
|
||||
if (!result.fullContext) {
|
||||
throw new Error("Rollback context not found");
|
||||
}
|
||||
|
||||
// Use the full context for rollback
|
||||
await rollbackApplication(
|
||||
application.appName,
|
||||
@@ -199,6 +181,7 @@ const rollbackApplication = async (
|
||||
};
|
||||
mounts: Mount[];
|
||||
ports: Port[];
|
||||
rollbackRegistry?: Registry;
|
||||
},
|
||||
) => {
|
||||
if (!fullContext) {
|
||||
@@ -245,16 +228,24 @@ const rollbackApplication = async (
|
||||
fullContext.environment.project.env,
|
||||
);
|
||||
|
||||
// For rollback, we use the provided image instead of calculating it
|
||||
const authConfig = getAuthConfig(fullContext as ApplicationNested);
|
||||
// Build the full registry image path if rollbackRegistry is available
|
||||
// e.g., "appName:v5" -> "siumauricio/appName:v5" or "registry.com/prefix/appName:v5"
|
||||
let rollbackImage = image;
|
||||
if (fullContext.rollbackRegistry) {
|
||||
rollbackImage = getRegistryTag(fullContext.rollbackRegistry, image);
|
||||
}
|
||||
|
||||
const settings: CreateServiceOptions = {
|
||||
authconfig: authConfig,
|
||||
authconfig: {
|
||||
password: fullContext.rollbackRegistry?.password || "",
|
||||
username: fullContext.rollbackRegistry?.username || "",
|
||||
serveraddress: fullContext.rollbackRegistry?.registryUrl || "",
|
||||
},
|
||||
Name: appName,
|
||||
TaskTemplate: {
|
||||
ContainerSpec: {
|
||||
HealthCheck,
|
||||
Image: image,
|
||||
Image: rollbackImage,
|
||||
Env: envVariables,
|
||||
Mounts: [...volumesMount, ...bindsMount],
|
||||
...(command
|
||||
@@ -297,7 +288,8 @@ const rollbackApplication = async (
|
||||
ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1,
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
await docker.createService(settings);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -349,19 +349,27 @@ export const readPorts = async (
|
||||
publishedPort: number;
|
||||
protocol?: string;
|
||||
}[] = [];
|
||||
const seenPorts = new Set<string>();
|
||||
for (const key in parsedResult) {
|
||||
if (Object.hasOwn(parsedResult, key)) {
|
||||
const containerPortMapppings = parsedResult[key];
|
||||
const protocol = key.split("/")[1];
|
||||
const targetPort = Number.parseInt(key.split("/")[0] ?? "0", 10);
|
||||
|
||||
containerPortMapppings.forEach((mapping: any) => {
|
||||
ports.push({
|
||||
targetPort: targetPort,
|
||||
publishedPort: Number.parseInt(mapping.HostPort, 10),
|
||||
protocol: protocol,
|
||||
});
|
||||
});
|
||||
// Take only the first mapping to avoid duplicates (IPv4 and IPv6)
|
||||
const firstMapping = containerPortMapppings[0];
|
||||
if (firstMapping) {
|
||||
const publishedPort = Number.parseInt(firstMapping.HostPort, 10);
|
||||
const portKey = `${targetPort}-${publishedPort}-${protocol}`;
|
||||
if (!seenPorts.has(portKey)) {
|
||||
seenPorts.add(portKey);
|
||||
ports.push({
|
||||
targetPort: targetPort,
|
||||
publishedPort: publishedPort,
|
||||
protocol: protocol,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ports.filter(
|
||||
@@ -369,6 +377,28 @@ export const readPorts = async (
|
||||
);
|
||||
};
|
||||
|
||||
export const checkPortInUse = async (
|
||||
port: number,
|
||||
serverId?: string,
|
||||
): Promise<{ isInUse: boolean; conflictingContainer?: string }> => {
|
||||
try {
|
||||
const command = `docker ps -a --format '{{.Names}}' | grep -v '^dokploy-traefik$' | while read name; do docker port "$name" 2>/dev/null | grep -q ':${port}' && echo "$name" && break; done || true`;
|
||||
const { stdout } = serverId
|
||||
? await execAsyncRemote(serverId, command)
|
||||
: await execAsync(command);
|
||||
|
||||
const container = stdout.trim();
|
||||
|
||||
return {
|
||||
isInUse: !!container,
|
||||
conflictingContainer: container || undefined,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error checking port availability:", error);
|
||||
return { isInUse: false };
|
||||
}
|
||||
};
|
||||
|
||||
export const writeTraefikSetup = async (input: TraefikOptions) => {
|
||||
const resourceType = await getDockerResourceType(
|
||||
"dokploy-traefik",
|
||||
|
||||
Reference in New Issue
Block a user