mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-06 06:25:28 +02:00
refactor(server): add support for multi server
This commit is contained in:
@@ -98,14 +98,24 @@ Compose Type: ${composeType} ✅`;
|
||||
});
|
||||
|
||||
const bashCommand = `
|
||||
set -e;
|
||||
echo "${logBox}" >> ${logPath};
|
||||
${newCompose}
|
||||
${envCommand}
|
||||
cd ${projectPath} || exit 1;
|
||||
docker ${command.split(" ").join(" ")} >> ${logPath} 2>&1;
|
||||
echo "Docker Compose Deployed: ✅" >> ${logPath};
|
||||
`;
|
||||
set -e
|
||||
{
|
||||
echo "${logBox}" >> "${logPath}"
|
||||
|
||||
${newCompose}
|
||||
|
||||
${envCommand}
|
||||
|
||||
cd "${projectPath}";
|
||||
|
||||
docker ${command.split(" ").join(" ")} >> "${logPath}" 2>&1 || { echo "Error: ❌ Docker command failed" >> "${logPath}"; exit 1; }
|
||||
|
||||
echo "Docker Compose Deployed: ✅" >> "${logPath}"
|
||||
} || {
|
||||
echo "Error: ❌ Script execution failed" >> "${logPath}"
|
||||
exit 1
|
||||
}
|
||||
`;
|
||||
|
||||
return await execAsyncRemote(compose.serverId, bashCommand);
|
||||
};
|
||||
|
||||
@@ -30,8 +30,6 @@ export const buildHeroku = async (
|
||||
if (writeStream.writable) {
|
||||
writeStream.write(data);
|
||||
}
|
||||
// Stream the data
|
||||
console.log(data);
|
||||
});
|
||||
return true;
|
||||
} catch (e) {
|
||||
|
||||
@@ -94,7 +94,7 @@ export const getNixpacksCommand = (
|
||||
/* No need for any start command, since we'll use nginx later on */
|
||||
args.push("--no-error-without-start");
|
||||
}
|
||||
|
||||
console.log("args", args);
|
||||
const command = `nixpacks ${args.join(" ")}`;
|
||||
const bashCommand = `
|
||||
echo "Starting nixpacks build..." >> ${logPath};
|
||||
@@ -108,6 +108,9 @@ echo "Nixpacks build completed." >> ${logPath};
|
||||
Then, remove the container and create a static build.
|
||||
*/
|
||||
|
||||
if (publishDirectory) {
|
||||
}
|
||||
|
||||
// if (publishDirectory) {
|
||||
// bashCommand += `
|
||||
// docker create --name ${buildContainerId} ${appName}
|
||||
|
||||
@@ -137,7 +137,7 @@ export const writeDomainsToComposeRemote = async (
|
||||
domains: Domain[],
|
||||
) => {
|
||||
if (!domains.length) {
|
||||
return;
|
||||
return "";
|
||||
}
|
||||
const composeConverted = await addDomainToCompose(compose, domains);
|
||||
const path = getComposePath(compose);
|
||||
|
||||
@@ -214,9 +214,17 @@ export const startServiceRemote = async (serverId: string, appName: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const removeService = async (appName: string) => {
|
||||
export const removeService = async (
|
||||
appName: string,
|
||||
serverId?: string | null,
|
||||
) => {
|
||||
try {
|
||||
await execAsync(`docker service rm ${appName}`);
|
||||
const command = `docker service rm ${appName}`;
|
||||
if (serverId) {
|
||||
await execAsyncRemote(serverId, command);
|
||||
} else {
|
||||
await execAsync(command);
|
||||
}
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
COMPOSE_PATH,
|
||||
MONITORING_PATH,
|
||||
} from "@/server/constants";
|
||||
import { execAsync } from "../process/execAsync";
|
||||
import { execAsync, execAsyncRemote } from "../process/execAsync";
|
||||
|
||||
export const recreateDirectory = async (pathFolder: string): Promise<void> => {
|
||||
try {
|
||||
@@ -34,31 +34,54 @@ export const removeFileOrDirectory = async (path: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const removeDirectoryCode = async (appName: string) => {
|
||||
export const removeDirectoryCode = async (
|
||||
appName: string,
|
||||
serverId?: string | null,
|
||||
) => {
|
||||
const directoryPath = path.join(APPLICATIONS_PATH, appName);
|
||||
|
||||
const command = `rm -rf ${directoryPath}`;
|
||||
try {
|
||||
await execAsync(`rm -rf ${directoryPath}`);
|
||||
if (serverId) {
|
||||
await execAsyncRemote(serverId, command);
|
||||
} else {
|
||||
await execAsync(command);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error to remove ${directoryPath}: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const removeComposeDirectory = async (appName: string) => {
|
||||
export const removeComposeDirectory = async (
|
||||
appName: string,
|
||||
serverId?: string | null,
|
||||
) => {
|
||||
const directoryPath = path.join(COMPOSE_PATH, appName);
|
||||
const command = `rm -rf ${directoryPath}`;
|
||||
try {
|
||||
await execAsync(`rm -rf ${directoryPath}`);
|
||||
if (serverId) {
|
||||
await execAsyncRemote(serverId, command);
|
||||
} else {
|
||||
await execAsync(command);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error to remove ${directoryPath}: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const removeMonitoringDirectory = async (appName: string) => {
|
||||
export const removeMonitoringDirectory = async (
|
||||
appName: string,
|
||||
serverId?: string | null,
|
||||
) => {
|
||||
const directoryPath = path.join(MONITORING_PATH, appName);
|
||||
const command = `rm -rf ${directoryPath}`;
|
||||
try {
|
||||
await execAsync(`rm -rf ${directoryPath}`);
|
||||
if (serverId) {
|
||||
await execAsyncRemote(serverId, command);
|
||||
} else {
|
||||
await execAsync(command);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error to remove ${directoryPath}: ${error}`);
|
||||
throw error;
|
||||
|
||||
@@ -33,7 +33,11 @@ export const execAsyncRemote = async (
|
||||
if (code === 0) {
|
||||
resolve({ stdout, stderr });
|
||||
} else {
|
||||
reject(new Error(`Command exited with code ${code}`));
|
||||
reject(
|
||||
new Error(
|
||||
`Command exited with code ${code}. Stderr: ${stderr}, command: ${command}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
})
|
||||
.on("data", (data: string) => {
|
||||
|
||||
@@ -181,6 +181,11 @@ export const getBitbucketCloneCommand = async (
|
||||
}
|
||||
|
||||
if (!bitbucketId) {
|
||||
const command = `
|
||||
echo "Error: ❌ Bitbucket Provider not found" >> ${logPath};
|
||||
exit 1;
|
||||
`;
|
||||
await execAsyncRemote(serverId, command);
|
||||
throw new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message: "Bitbucket Provider not found",
|
||||
@@ -198,7 +203,7 @@ export const getBitbucketCloneCommand = async (
|
||||
rm -rf ${outputPath};
|
||||
mkdir -p ${outputPath};
|
||||
if ! git clone --branch ${bitbucketBranch} --depth 1 --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then
|
||||
echo "[ERROR] Fail to clone the repository ${repoclone}" >> ${logPath};
|
||||
echo "❌ [ERROR] Fail to clone the repository ${repoclone}" >> ${logPath};
|
||||
exit 1;
|
||||
fi
|
||||
echo "Cloned ${repoclone} to ${outputPath}: ✅" >> ${logPath};
|
||||
|
||||
@@ -6,7 +6,7 @@ import { TRPCError } from "@trpc/server";
|
||||
import { recreateDirectory } from "../filesystem/directory";
|
||||
import { execAsync, execAsyncRemote } from "../process/execAsync";
|
||||
import { spawnAsync } from "../process/spawnAsync";
|
||||
import { Compose } from "@/server/api/services/compose";
|
||||
import type { Compose } from "@/server/api/services/compose";
|
||||
|
||||
export const cloneGitRepository = async (
|
||||
entity: {
|
||||
@@ -108,6 +108,12 @@ export const getCustomGitCloneCommand = async (
|
||||
} = entity;
|
||||
|
||||
if (!customGitUrl || !customGitBranch) {
|
||||
const command = `
|
||||
echo "Error: ❌ Repository not found" >> ${logPath};
|
||||
exit 1;
|
||||
`;
|
||||
|
||||
await execAsyncRemote(serverId, command);
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Error: Repository not found",
|
||||
@@ -143,7 +149,7 @@ export const getCustomGitCloneCommand = async (
|
||||
|
||||
command.push(
|
||||
`if ! git clone --branch ${customGitBranch} --depth 1 --progress ${customGitUrl} ${outputPath} >> ${logPath} 2>&1; then
|
||||
echo "[ERROR] Fail to clone the repository ${customGitUrl}" >> ${logPath};
|
||||
echo "❌ [ERROR] Fail to clone the repository ${customGitUrl}" >> ${logPath};
|
||||
exit 1;
|
||||
fi
|
||||
`,
|
||||
|
||||
@@ -151,7 +151,20 @@ export const getGithubCloneCommand = async (
|
||||
) => {
|
||||
const { appName, repository, owner, branch, githubId, serverId } = entity;
|
||||
|
||||
if (!githubId || !serverId) {
|
||||
if (!serverId) {
|
||||
throw new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message: "Server not found",
|
||||
});
|
||||
}
|
||||
|
||||
if (!githubId) {
|
||||
const command = `
|
||||
echo "Error: ❌ Github Provider not found" >> ${logPath};
|
||||
exit 1;
|
||||
`;
|
||||
|
||||
await executeCommand(serverId, command);
|
||||
throw new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message: "GitHub Provider not found",
|
||||
@@ -192,7 +205,7 @@ export const getGithubCloneCommand = async (
|
||||
rm -rf ${outputPath};
|
||||
mkdir -p ${outputPath};
|
||||
if ! git clone --branch ${branch} --depth 1 --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then
|
||||
echo "[ERROR] Fallo al clonar el repositorio ${repoclone}" >> ${logPath};
|
||||
echo "❌ [ERROR] Fallo al clonar el repositorio ${repoclone}" >> ${logPath};
|
||||
exit 1;
|
||||
fi
|
||||
echo "Cloned ${repoclone} to ${outputPath}: ✅" >> ${logPath};
|
||||
|
||||
@@ -179,6 +179,12 @@ export const getGitlabCloneCommand = async (
|
||||
}
|
||||
|
||||
if (!gitlabId) {
|
||||
const command = `
|
||||
echo "Error: ❌ Gitlab Provider not found" >> ${logPath};
|
||||
exit 1;
|
||||
`;
|
||||
|
||||
await execAsyncRemote(serverId, command);
|
||||
throw new TRPCError({
|
||||
code: "NOT_FOUND",
|
||||
message: "Gitlab Provider not found",
|
||||
@@ -203,7 +209,7 @@ export const getGitlabCloneCommand = async (
|
||||
exit 1; # Exit with error code
|
||||
`;
|
||||
|
||||
await executeCommand(serverId, bashCommand);
|
||||
await execAsyncRemote(serverId, bashCommand);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -218,7 +224,7 @@ export const getGitlabCloneCommand = async (
|
||||
rm -rf ${outputPath};
|
||||
mkdir -p ${outputPath};
|
||||
if ! git clone --branch ${gitlabBranch} --depth 1 --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then
|
||||
echo "[ERROR] Fail to clone the repository ${repoclone}" >> ${logPath};
|
||||
echo "❌ [ERROR] Fail to clone the repository ${repoclone}" >> ${logPath};
|
||||
exit 1;
|
||||
fi
|
||||
echo "Cloned ${repoclone} to ${outputPath}: ✅" >> ${logPath};
|
||||
|
||||
@@ -47,9 +47,20 @@ export const createTraefikConfig = (appName: string) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const removeTraefikConfig = async (appName: string) => {
|
||||
export const removeTraefikConfig = async (
|
||||
appName: string,
|
||||
serverId?: string | null,
|
||||
) => {
|
||||
try {
|
||||
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`);
|
||||
|
||||
if (serverId) {
|
||||
await execAsyncRemote(serverId, `rm ${configPath}`);
|
||||
} else {
|
||||
if (fs.existsSync(configPath)) {
|
||||
await fs.promises.unlink(configPath);
|
||||
}
|
||||
}
|
||||
if (fs.existsSync(configPath)) {
|
||||
await fs.promises.unlink(configPath);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { dump, load } from "js-yaml";
|
||||
import type { ApplicationNested } from "../builders";
|
||||
import type { FileConfig } from "./file-types";
|
||||
import { execAsyncRemote } from "../process/execAsync";
|
||||
import { writeTraefikConfigRemote } from "./application";
|
||||
|
||||
export const addMiddleware = (config: FileConfig, middlewareName: string) => {
|
||||
if (config.http?.routers) {
|
||||
@@ -43,7 +44,7 @@ export const deleteMiddleware = (
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteAllMiddlewares = (application: ApplicationNested) => {
|
||||
export const deleteAllMiddlewares = async (application: ApplicationNested) => {
|
||||
const config = loadMiddlewares<FileConfig>();
|
||||
const { security, appName, redirects } = application;
|
||||
|
||||
@@ -60,7 +61,11 @@ export const deleteAllMiddlewares = (application: ApplicationNested) => {
|
||||
}
|
||||
}
|
||||
|
||||
writeMiddleware(config);
|
||||
if (application.serverId) {
|
||||
await writeTraefikConfigRemote(config, "middlewares", application.serverId);
|
||||
} else {
|
||||
writeMiddleware(config);
|
||||
}
|
||||
};
|
||||
|
||||
export const loadMiddlewares = <T>() => {
|
||||
|
||||
Reference in New Issue
Block a user