feat: add reload, stop and start in remote server

This commit is contained in:
Mauricio Siu
2024-09-09 23:46:24 -06:00
parent 95f75fdccb
commit 86f1bf31b8
14 changed files with 224 additions and 42 deletions

View File

@@ -7,7 +7,7 @@ import {
CardTitle,
} from "@/components/ui/card";
import { api } from "@/utils/api";
import { File } from "lucide-react";
import { File, Loader2 } from "lucide-react";
import React from "react";
import { UpdateTraefikConfig } from "./update-traefik-config";
interface Props {
@@ -15,7 +15,7 @@ interface Props {
}
export const ShowTraefikConfig = ({ applicationId }: Props) => {
const { data } = api.application.readTraefikConfig.useQuery(
const { data, isLoading } = api.application.readTraefikConfig.useQuery(
{
applicationId,
},
@@ -35,7 +35,12 @@ export const ShowTraefikConfig = ({ applicationId }: Props) => {
</div>
</CardHeader>
<CardContent className="flex flex-col gap-4">
{data === null ? (
{isLoading ? (
<span className="text-base text-muted-foreground flex flex-row gap-3 items-center justify-center min-h-[10vh]">
Loading...
<Loader2 className="animate-spin" />
</span>
) : !data ? (
<div className="flex w-full flex-col items-center justify-center gap-3 pt-10">
<File className="size-8 text-muted-foreground" />
<span className="text-base text-muted-foreground">

View File

@@ -298,11 +298,7 @@ export const AddDomain = ({
</form>
<DialogFooter>
<Button
isLoading={form.formState.isSubmitting}
form="hook-form"
type="submit"
>
<Button isLoading={isLoading} form="hook-form" type="submit">
{dictionary.submit}
</Button>
</DialogFooter>

View File

@@ -0,0 +1,18 @@
import type { NextRequest } from "next/server";
import { renderToString } from "react-dom/server";
import Page418 from "../hola"; // Importa la página 418
export const GET = async (req: NextRequest) => {
// Renderiza el componente de la página 418 como HTML
const htmlContent = renderToString(Page418());
// Devuelve la respuesta con el código de estado HTTP 418
return new Response(htmlContent, {
headers: {
"Content-Type": "text/html",
},
status: 418,
});
};
export default GET;

View File

@@ -0,0 +1,3 @@
export default function hola() {
return <div>hola</div>;
}

View File

@@ -36,6 +36,7 @@ import { serverRouter } from "./routers/server";
*
* All routers added in /api/routers should be manually added here.
*/
export const appRouter = createTRPCRouter({
admin: adminRouter,
docker: dockerRouter,

View File

@@ -27,7 +27,9 @@ import { enqueueDeploymentJob, myQueue } from "@/server/queues/queueSetup";
import {
removeService,
startService,
startServiceRemote,
stopService,
stopServiceRemote,
} from "@/server/utils/docker/utils";
import {
removeDirectoryCode,
@@ -38,6 +40,7 @@ import {
readRemoteConfig,
removeTraefikConfig,
writeConfig,
writeConfigRemote,
} from "@/server/utils/traefik/application";
import { deleteAllMiddlewares } from "@/server/utils/traefik/middleware";
import { TRPCError } from "@trpc/server";
@@ -53,7 +56,6 @@ import {
} from "../services/application";
import { removeDeployments } from "../services/deployment";
import { addNewService, checkServiceAccess } from "../services/user";
import { unzipDrop } from "@/server/utils/builders/drop";
import { uploadFileSchema } from "@/utils/schema";
@@ -97,9 +99,19 @@ export const applicationRouter = createTRPCRouter({
reload: protectedProcedure
.input(apiReloadApplication)
.mutation(async ({ input }) => {
await stopService(input.appName);
const application = await findApplicationById(input.applicationId);
if (application.serverId) {
await stopServiceRemote(application.serverId, input.appName);
} else {
await stopService(input.appName);
}
await updateApplicationStatus(input.applicationId, "idle");
await startService(input.appName);
if (application.serverId) {
await startServiceRemote(application.serverId, input.appName);
} else {
await startService(input.appName);
}
await updateApplicationStatus(input.applicationId, "done");
return true;
}),
@@ -143,7 +155,11 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication)
.mutation(async ({ input }) => {
const service = await findApplicationById(input.applicationId);
await stopService(service.appName);
if (service.serverId) {
await stopServiceRemote(service.serverId, service.appName);
} else {
await stopService(service.appName);
}
await updateApplicationStatus(input.applicationId, "idle");
return service;
@@ -153,8 +169,11 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication)
.mutation(async ({ input }) => {
const service = await findApplicationById(input.applicationId);
await startService(service.appName);
if (service.serverId) {
await startServiceRemote(service.serverId, service.appName);
} else {
await startService(service.appName);
}
await updateApplicationStatus(input.applicationId, "done");
return service;
@@ -387,7 +406,16 @@ export const applicationRouter = createTRPCRouter({
.input(z.object({ applicationId: z.string(), traefikConfig: z.string() }))
.mutation(async ({ input }) => {
const application = await findApplicationById(input.applicationId);
writeConfig(application.appName, input.traefikConfig);
if (application.serverId) {
await writeConfigRemote(
application.serverId,
application.appName,
input.traefikConfig,
);
} else {
writeConfig(application.appName, input.traefikConfig);
}
return true;
}),
readAppMonitoring: protectedProcedure

View File

@@ -12,7 +12,9 @@ import {
import {
removeService,
startService,
startServiceRemote,
stopService,
stopServiceRemote,
} from "@/server/utils/docker/utils";
import { TRPCError } from "@trpc/server";
import {
@@ -72,8 +74,11 @@ export const mariadbRouter = createTRPCRouter({
.input(apiFindOneMariaDB)
.mutation(async ({ input }) => {
const service = await findMariadbById(input.mariadbId);
await startService(service.appName);
if (service.serverId) {
await startServiceRemote(service.serverId, service.appName);
} else {
await startService(service.appName);
}
await updateMariadbById(input.mariadbId, {
applicationStatus: "done",
});
@@ -83,13 +88,18 @@ export const mariadbRouter = createTRPCRouter({
stop: protectedProcedure
.input(apiFindOneMariaDB)
.mutation(async ({ input }) => {
const mongo = await findMariadbById(input.mariadbId);
await stopService(mongo.appName);
const mariadb = await findMariadbById(input.mariadbId);
if (mariadb.serverId) {
await stopServiceRemote(mariadb.serverId, mariadb.appName);
} else {
await stopService(mariadb.appName);
}
await updateMariadbById(input.mariadbId, {
applicationStatus: "idle",
});
return mongo;
return mariadb;
}),
saveExternalPort: protectedProcedure
.input(apiSaveExternalPortMariaDB)
@@ -156,11 +166,21 @@ export const mariadbRouter = createTRPCRouter({
reload: protectedProcedure
.input(apiResetMariadb)
.mutation(async ({ input }) => {
await stopService(input.appName);
const mariadb = await findMariadbById(input.mariadbId);
if (mariadb.serverId) {
await stopServiceRemote(mariadb.serverId, mariadb.appName);
} else {
await stopService(mariadb.appName);
}
await updateMariadbById(input.mariadbId, {
applicationStatus: "idle",
});
await startService(input.appName);
if (mariadb.serverId) {
await startServiceRemote(mariadb.serverId, mariadb.appName);
} else {
await startService(mariadb.appName);
}
await updateMariadbById(input.mariadbId, {
applicationStatus: "done",
});

View File

@@ -12,7 +12,9 @@ import {
import {
removeService,
startService,
startServiceRemote,
stopService,
stopServiceRemote,
} from "@/server/utils/docker/utils";
import { TRPCError } from "@trpc/server";
import {
@@ -74,7 +76,11 @@ export const mongoRouter = createTRPCRouter({
.mutation(async ({ input }) => {
const service = await findMongoById(input.mongoId);
await startService(service.appName);
if (service.serverId) {
await startServiceRemote(service.serverId, service.appName);
} else {
await startService(service.appName);
}
await updateMongoById(input.mongoId, {
applicationStatus: "done",
});
@@ -85,7 +91,12 @@ export const mongoRouter = createTRPCRouter({
.input(apiFindOneMongo)
.mutation(async ({ input }) => {
const mongo = await findMongoById(input.mongoId);
await stopService(mongo.appName);
if (mongo.serverId) {
await stopServiceRemote(mongo.serverId, mongo.appName);
} else {
await stopService(mongo.appName);
}
await updateMongoById(input.mongoId, {
applicationStatus: "idle",
});
@@ -119,11 +130,21 @@ export const mongoRouter = createTRPCRouter({
reload: protectedProcedure
.input(apiResetMongo)
.mutation(async ({ input }) => {
await stopService(input.appName);
const mongo = await findMongoById(input.mongoId);
if (mongo.serverId) {
await stopServiceRemote(mongo.serverId, mongo.appName);
} else {
await stopService(mongo.appName);
}
await updateMongoById(input.mongoId, {
applicationStatus: "idle",
});
await startService(input.appName);
if (mongo.serverId) {
await startServiceRemote(mongo.serverId, mongo.appName);
} else {
await startService(mongo.appName);
}
await updateMongoById(input.mongoId, {
applicationStatus: "done",
});

View File

@@ -12,7 +12,9 @@ import {
import {
removeService,
startService,
startServiceRemote,
stopService,
stopServiceRemote,
} from "@/server/utils/docker/utils";
import { TRPCError } from "@trpc/server";
import { createMount } from "../services/mount";
@@ -73,7 +75,11 @@ export const mysqlRouter = createTRPCRouter({
.mutation(async ({ input }) => {
const service = await findMySqlById(input.mysqlId);
await startService(service.appName);
if (service.serverId) {
await startServiceRemote(service.serverId, service.appName);
} else {
await startService(service.appName);
}
await updateMySqlById(input.mysqlId, {
applicationStatus: "done",
});
@@ -84,7 +90,11 @@ export const mysqlRouter = createTRPCRouter({
.input(apiFindOneMySql)
.mutation(async ({ input }) => {
const mongo = await findMySqlById(input.mysqlId);
await stopService(mongo.appName);
if (mongo.serverId) {
await stopServiceRemote(mongo.serverId, mongo.appName);
} else {
await stopService(mongo.appName);
}
await updateMySqlById(input.mysqlId, {
applicationStatus: "idle",
});
@@ -118,11 +128,20 @@ export const mysqlRouter = createTRPCRouter({
reload: protectedProcedure
.input(apiResetMysql)
.mutation(async ({ input }) => {
await stopService(input.appName);
const mysql = await findMySqlById(input.mysqlId);
if (mysql.serverId) {
await stopServiceRemote(mysql.serverId, mysql.appName);
} else {
await stopService(mysql.appName);
}
await updateMySqlById(input.mysqlId, {
applicationStatus: "idle",
});
await startService(input.appName);
if (mysql.serverId) {
await startServiceRemote(mysql.serverId, mysql.appName);
} else {
await startService(mysql.appName);
}
await updateMySqlById(input.mysqlId, {
applicationStatus: "done",
});

View File

@@ -12,7 +12,9 @@ import {
import {
removeService,
startService,
startServiceRemote,
stopService,
stopServiceRemote,
} from "@/server/utils/docker/utils";
import { TRPCError } from "@trpc/server";
import { createMount } from "../services/mount";
@@ -74,7 +76,11 @@ export const postgresRouter = createTRPCRouter({
.mutation(async ({ input }) => {
const service = await findPostgresById(input.postgresId);
await startService(service.appName);
if (service.serverId) {
await startServiceRemote(service.serverId, service.appName);
} else {
await startService(service.appName);
}
await updatePostgresById(input.postgresId, {
applicationStatus: "done",
});
@@ -85,7 +91,11 @@ export const postgresRouter = createTRPCRouter({
.input(apiFindOnePostgres)
.mutation(async ({ input }) => {
const postgres = await findPostgresById(input.postgresId);
await stopService(postgres.appName);
if (postgres.serverId) {
await stopServiceRemote(postgres.serverId, postgres.appName);
} else {
await stopService(postgres.appName);
}
await updatePostgresById(input.postgresId, {
applicationStatus: "idle",
});
@@ -152,11 +162,21 @@ export const postgresRouter = createTRPCRouter({
reload: protectedProcedure
.input(apiResetPostgres)
.mutation(async ({ input }) => {
await stopService(input.appName);
const postgres = await findPostgresById(input.postgresId);
if (postgres.serverId) {
await stopServiceRemote(postgres.serverId, postgres.appName);
} else {
await stopService(postgres.appName);
}
await updatePostgresById(input.postgresId, {
applicationStatus: "idle",
});
await startService(input.appName);
if (postgres.serverId) {
await startServiceRemote(postgres.serverId, postgres.appName);
} else {
await startService(postgres.appName);
}
await updatePostgresById(input.postgresId, {
applicationStatus: "done",
});

View File

@@ -12,7 +12,9 @@ import {
import {
removeService,
startService,
startServiceRemote,
stopService,
stopServiceRemote,
} from "@/server/utils/docker/utils";
import { TRPCError } from "@trpc/server";
import { createMount } from "../services/mount";
@@ -69,7 +71,12 @@ export const redisRouter = createTRPCRouter({
.input(apiFindOneRedis)
.mutation(async ({ input }) => {
const redis = await findRedisById(input.redisId);
await startService(redis.appName);
if (redis.serverId) {
await startServiceRemote(redis.serverId, redis.appName);
} else {
await startService(redis.appName);
}
await updateRedisById(input.redisId, {
applicationStatus: "done",
});
@@ -79,11 +86,21 @@ export const redisRouter = createTRPCRouter({
reload: protectedProcedure
.input(apiResetRedis)
.mutation(async ({ input }) => {
await stopService(input.appName);
const redis = await findRedisById(input.redisId);
if (redis.serverId) {
await stopServiceRemote(redis.serverId, redis.appName);
} else {
await stopService(redis.appName);
}
await updateRedisById(input.redisId, {
applicationStatus: "idle",
});
await startService(input.appName);
if (redis.serverId) {
await startServiceRemote(redis.serverId, redis.appName);
} else {
await startService(redis.appName);
}
await updateRedisById(input.redisId, {
applicationStatus: "done",
});
@@ -93,13 +110,17 @@ export const redisRouter = createTRPCRouter({
stop: protectedProcedure
.input(apiFindOneRedis)
.mutation(async ({ input }) => {
const mongo = await findRedisById(input.redisId);
await stopService(mongo.appName);
const redis = await findRedisById(input.redisId);
if (redis.serverId) {
await stopServiceRemote(redis.serverId, redis.appName);
} else {
await stopService(redis.appName);
}
await updateRedisById(input.redisId, {
applicationStatus: "idle",
});
return mongo;
return redis;
}),
saveExternalPort: protectedProcedure
.input(apiSaveExternalPortRedis)

View File

@@ -169,7 +169,6 @@ export const deployApplication = async ({
`;
if (application.sourceType === "github") {
command += await getGithubCloneCommand(application, deployment.logPath);
console.log(application);
command += getBuildCommand(application, deployment.logPath);
} else if (application.sourceType === "gitlab") {
command += await getGitlabCloneCommand(application, deployment.logPath);

View File

@@ -5,7 +5,7 @@ import { APPLICATIONS_PATH, docker } from "@/server/constants";
import type { ContainerInfo, ResourceRequirements } from "dockerode";
import { parse } from "dotenv";
import type { ApplicationNested } from "../builders";
import { execAsync } from "../process/execAsync";
import { execAsync, execAsyncRemote } from "../process/execAsync";
import { getRemoteDocker } from "../servers/remote-docker";
interface RegistryAuth {
@@ -116,6 +116,15 @@ export const stopService = async (appName: string) => {
}
};
export const stopServiceRemote = async (serverId: string, appName: string) => {
try {
await execAsyncRemote(serverId, `docker service scale ${appName}=0 `);
} catch (error) {
console.error(error);
return error;
}
};
export const getContainerByName = (name: string): Promise<ContainerInfo> => {
const opts = {
limit: 1,
@@ -196,6 +205,15 @@ export const startService = async (appName: string) => {
}
};
export const startServiceRemote = async (serverId: string, appName: string) => {
try {
await execAsyncRemote(serverId, `docker service scale ${appName}=1 `);
} catch (error) {
console.error(error);
throw error;
}
};
export const removeService = async (appName: string) => {
try {
await execAsync(`docker service rm ${appName}`);

View File

@@ -145,6 +145,19 @@ export const writeConfig = (appName: string, traefikConfig: string) => {
}
};
export const writeConfigRemote = async (
serverId: string,
appName: string,
traefikConfig: string,
) => {
try {
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`);
await execAsyncRemote(serverId, `echo '${traefikConfig}' > ${configPath}`);
} catch (e) {
console.error("Error saving the YAML config file:", e);
}
};
export const writeTraefikConfigInPath = (
pathFile: string,
traefikConfig: string,