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;