From 8bf6a22db8852f8bef0d1780c8b6d3c9a5fae29c Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 21 Sep 2024 01:44:31 -0600 Subject: [PATCH] feat(multi server): add env and toggle dashboard remote --- .../settings/servers/show-servers.tsx | 47 +++++------------- .../servers/toggle-traefik-dashboard.tsx | 48 +++++++++++++++++++ .../settings/web-server/edit-traefik-env.tsx | 1 + apps/dokploy/server/api/routers/settings.ts | 39 ++++++++++----- apps/dokploy/server/api/services/docker.ts | 1 - apps/dokploy/server/setup/traefik-setup.ts | 16 +++++-- .../server/utils/servers/remote-docker.ts | 2 +- 7 files changed, 102 insertions(+), 52 deletions(-) create mode 100644 apps/dokploy/components/dashboard/settings/servers/toggle-traefik-dashboard.tsx diff --git a/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx b/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx index 9f7499c79..4afdaf76f 100644 --- a/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx @@ -29,14 +29,13 @@ import { SetupServer } from "./setup-server"; import { UpdateServer } from "./update-server"; import { ShowTraefikFileSystemModal } from "./show-traefik-file-system-modal"; import { ShowModalLogs } from "../web-server/show-modal-logs"; +import { ToggleTraefikDashboard } from "./toggle-traefik-dashboard"; +import { EditTraefikEnv } from "../web-server/edit-traefik-env"; export const ShowServers = () => { const { data, refetch } = api.server.all.useQuery(); const { mutateAsync } = api.server.remove.useMutation(); const { data: sshKeys } = api.sshKey.all.useQuery(); - const { mutateAsync: toggleDashboard, isLoading: toggleDashboardIsLoading } = - api.settings.toggleDashboard.useMutation(); - const { mutateAsync: cleanDockerBuilder, isLoading: cleanDockerBuilderIsLoading, @@ -63,9 +62,6 @@ export const ShowServers = () => { const { mutateAsync: cleanAll, isLoading: cleanAllIsLoading } = api.settings.cleanAll.useMutation(); - const { data: haveTraefikDashboardPortEnabled, refetch: refetchDashboard } = - api.settings.haveTraefikDashboardPortEnabled.useQuery(); - return (
@@ -226,35 +222,18 @@ export const ShowServers = () => { > Watch logs + + e.preventDefault()} + className="w-full cursor-pointer space-x-3" + > + Modify Env + + + - {/* { - await toggleDashboard({ - enableDashboard: - !haveTraefikDashboardPortEnabled, - serverId: server.serverId, - }) - .then(async () => { - toast.success( - `${haveTraefikDashboardPortEnabled ? "Disabled" : "Enabled"} Dashboard`, - ); - refetchDashboard(); - }) - .catch(() => { - toast.error( - `${haveTraefikDashboardPortEnabled ? "Disabled" : "Enabled"} Dashboard`, - ); - }); - }} - className="w-full cursor-pointer space-x-3" - > - - {haveTraefikDashboardPortEnabled - ? "Disable" - : "Enable"}{" "} - Dashboard - - */} Storage diff --git a/apps/dokploy/components/dashboard/settings/servers/toggle-traefik-dashboard.tsx b/apps/dokploy/components/dashboard/settings/servers/toggle-traefik-dashboard.tsx new file mode 100644 index 000000000..86a3d7672 --- /dev/null +++ b/apps/dokploy/components/dashboard/settings/servers/toggle-traefik-dashboard.tsx @@ -0,0 +1,48 @@ +import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; +import { api } from "@/utils/api"; +import { toast } from "sonner"; + +interface Props { + serverId: string; +} +export const ToggleTraefikDashboard = ({ serverId }: Props) => { + const { mutateAsync: toggleDashboard, isLoading: toggleDashboardIsLoading } = + api.settings.toggleDashboard.useMutation(); + const { data: haveTraefikDashboardPortEnabled, refetch: refetchDashboard } = + api.settings.haveTraefikDashboardPortEnabled.useQuery( + { + serverId, + }, + { + enabled: !!serverId, + }, + ); + return ( + <> + { + await toggleDashboard({ + enableDashboard: !haveTraefikDashboardPortEnabled, + serverId: serverId, + }) + .then(async () => { + toast.success( + `${haveTraefikDashboardPortEnabled ? "Disabled" : "Enabled"} Dashboard`, + ); + refetchDashboard(); + }) + .catch(() => { + toast.error( + `${haveTraefikDashboardPortEnabled ? "Disabled" : "Enabled"} Dashboard`, + ); + }); + }} + className="w-full cursor-pointer space-x-3" + > + + {haveTraefikDashboardPortEnabled ? "Disable" : "Enable"} Dashboard + + + + ); +}; diff --git a/apps/dokploy/components/dashboard/settings/web-server/edit-traefik-env.tsx b/apps/dokploy/components/dashboard/settings/web-server/edit-traefik-env.tsx index 7fc4166bb..645eda903 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/edit-traefik-env.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/edit-traefik-env.tsx @@ -65,6 +65,7 @@ export const EditTraefikEnv = ({ children, serverId }: Props) => { const onSubmit = async (data: Schema) => { await mutateAsync({ env: data.env, + serverId, }) .then(async () => { toast.success("Traefik Env Updated"); diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts index 878882b90..08f046984 100644 --- a/apps/dokploy/server/api/routers/settings.ts +++ b/apps/dokploy/server/api/routers/settings.ts @@ -88,6 +88,7 @@ export const settingsRouter = createTRPCRouter({ .mutation(async ({ input }) => { await initializeTraefik({ enableDashboard: input.enableDashboard, + serverId: input.serverId, }); return true; }), @@ -357,6 +358,7 @@ export const settingsRouter = createTRPCRouter({ if (input?.serverId) { const result = await execAsyncRemote(input.serverId, command); + console.log(result); return result.stdout.trim(); } const result = await execAsync(command); @@ -369,25 +371,38 @@ export const settingsRouter = createTRPCRouter({ const envs = prepareEnvironmentVariables(input.env); await initializeTraefik({ env: envs, + serverId: input.serverId, }); return true; }), - haveTraefikDashboardPortEnabled: adminProcedure.query(async () => { - const { stdout } = await execAsync( - "docker service inspect --format='{{json .Endpoint.Ports}}' dokploy-traefik", - ); + haveTraefikDashboardPortEnabled: adminProcedure + .input(apiStorage) + .query(async ({ input }) => { + const command = `docker service inspect --format='{{json .Endpoint.Ports}}' dokploy-traefik`; - const parsed: any[] = JSON.parse(stdout.trim()); - - for (const port of parsed) { - if (port.PublishedPort === 8080) { - return true; + let stdout = ""; + if (input?.serverId) { + const result = await execAsyncRemote(input.serverId, command); + stdout = result.stdout; + } else { + const result = await execAsync( + "docker service inspect --format='{{json .Endpoint.Ports}}' dokploy-traefik", + ); + stdout = result.stdout; } - } - return false; - }), + const parsed: any[] = JSON.parse(stdout.trim()); + console.log(parsed); + + for (const port of parsed) { + if (port.PublishedPort === 8080) { + return true; + } + } + + return false; + }), readStatsLogs: adminProcedure.input(apiReadStatsLogs).query(({ input }) => { const rawConfig = readMonitoringConfig(); diff --git a/apps/dokploy/server/api/services/docker.ts b/apps/dokploy/server/api/services/docker.ts index ba142ef87..09451efb6 100644 --- a/apps/dokploy/server/api/services/docker.ts +++ b/apps/dokploy/server/api/services/docker.ts @@ -135,7 +135,6 @@ export const getContainersByAppLabel = async ( let stderr = ""; const command = `docker ps --filter "label=com.docker.swarm.service.name=${appName}" --format 'CONTAINER ID : {{.ID}} | Name: {{.Names}} | State: {{.State}}'`; - console.log(command); if (serverId) { const result = await execAsyncRemote(serverId, command); stdout = result.stdout; diff --git a/apps/dokploy/server/setup/traefik-setup.ts b/apps/dokploy/server/setup/traefik-setup.ts index b5dc9f907..7d0a25e1f 100644 --- a/apps/dokploy/server/setup/traefik-setup.ts +++ b/apps/dokploy/server/setup/traefik-setup.ts @@ -2,10 +2,11 @@ import { chmodSync, existsSync, mkdirSync, writeFileSync } from "node:fs"; import path from "node:path"; import type { ContainerTaskSpec, CreateServiceOptions } from "dockerode"; import { dump } from "js-yaml"; -import { docker, paths } from "../constants"; -import { pullImage } from "../utils/docker/utils"; +import { paths } from "../constants"; +import { pullImage, pullRemoteImage } from "../utils/docker/utils"; import type { FileConfig } from "../utils/traefik/file-types"; import type { MainTraefikConfig } from "../utils/traefik/types"; +import { getRemoteDocker } from "../utils/servers/remote-docker"; const TRAEFIK_SSL_PORT = Number.parseInt(process.env.TRAEFIK_SSL_PORT ?? "", 10) || 443; @@ -14,13 +15,15 @@ const TRAEFIK_PORT = Number.parseInt(process.env.TRAEFIK_PORT ?? "", 10) || 80; interface TraefikOptions { enableDashboard?: boolean; env?: string[]; + serverId?: string; } export const initializeTraefik = async ({ enableDashboard = false, env, + serverId, }: TraefikOptions = {}) => { - const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(); + const { MAIN_TRAEFIK_PATH, DYNAMIC_TRAEFIK_PATH } = paths(!!serverId); const imageName = "traefik:v3.1.2"; const containerName = "dokploy-traefik"; const settings: CreateServiceOptions = { @@ -84,8 +87,13 @@ export const initializeTraefik = async ({ ], }, }; + const docker = await getRemoteDocker(serverId); try { - await pullImage(imageName); + if (serverId) { + await pullRemoteImage(imageName, serverId); + } else { + await pullImage(imageName); + } const service = docker.getService(containerName); const inspect = await service.inspect(); diff --git a/apps/dokploy/server/utils/servers/remote-docker.ts b/apps/dokploy/server/utils/servers/remote-docker.ts index cd608f5b2..f7704b687 100644 --- a/apps/dokploy/server/utils/servers/remote-docker.ts +++ b/apps/dokploy/server/utils/servers/remote-docker.ts @@ -3,7 +3,7 @@ import { docker } from "@/server/constants"; import Dockerode from "dockerode"; import { readSSHKey } from "../filesystem/ssh"; -export const getRemoteDocker = async (serverId: string | null) => { +export const getRemoteDocker = async (serverId?: string | null) => { if (!serverId) return docker; const server = await findServerById(serverId); if (!server.sshKeyId) return docker;