refactor(server): add support for multi server

This commit is contained in:
Mauricio Siu
2024-09-15 01:24:55 -06:00
parent 033bf66405
commit d2c8632c4f
26 changed files with 340 additions and 244 deletions

View File

@@ -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);
};

View File

@@ -30,8 +30,6 @@ export const buildHeroku = async (
if (writeStream.writable) {
writeStream.write(data);
}
// Stream the data
console.log(data);
});
return true;
} catch (e) {

View File

@@ -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}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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) => {

View File

@@ -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};

View File

@@ -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
`,

View File

@@ -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};

View File

@@ -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};

View File

@@ -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);
}

View File

@@ -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>() => {