From aa32ea322dd4b71f90b28433d0f731c8d6261883 Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Sat, 27 Sep 2025 14:49:22 +0200 Subject: [PATCH] refactor: docker volume prefix --- .../app/modules/details/tabs/docker.tsx | 6 +++--- apps/client/app/routes/details.tsx | 2 ++ apps/client/app/routes/home.tsx | 2 ++ apps/server/src/index.ts | 8 ++++---- .../src/modules/driver/driver.controller.ts | 19 +++++++++---------- .../src/modules/volumes/volume.service.ts | 7 +++---- apps/server/tsconfig.json | 5 ++++- package.json | 4 ++-- 8 files changed, 29 insertions(+), 24 deletions(-) diff --git a/apps/client/app/modules/details/tabs/docker.tsx b/apps/client/app/modules/details/tabs/docker.tsx index 610f938..2cb48f6 100644 --- a/apps/client/app/modules/details/tabs/docker.tsx +++ b/apps/client/app/modules/details/tabs/docker.tsx @@ -16,17 +16,17 @@ export const DockerTabContent = ({ volume }: Props) => { services: { nginx: { image: "nginx:latest", - volumes: [`${volume.name}:/path/in/container`], + volumes: [`im-${volume.name}:/path/in/container`], }, }, volumes: { - [volume.name]: { + [`im-${volume.name}`]: { external: true, }, }, }); - const dockerRunCommand = `docker run -v ${volume.name}:/path/in/container nginx:latest`; + const dockerRunCommand = `docker run -v im-${volume.name}:/path/in/container nginx:latest`; const containersQuery = getContainersUsingVolumeOptions({ path: { name: volume.name } }); const { data: containersData, isLoading, error } = useQuery(containersQuery); diff --git a/apps/client/app/routes/details.tsx b/apps/client/app/routes/details.tsx index 4bd1de4..ca02b18 100644 --- a/apps/client/app/routes/details.tsx +++ b/apps/client/app/routes/details.tsx @@ -41,6 +41,8 @@ export default function DetailsPage({ loaderData }: Route.ComponentProps) { const { data } = useQuery({ ...getVolumeOptions({ path: { name: name ?? "" } }), initialData: loaderData, + refetchInterval: 10000, + refetchOnWindowFocus: true, }); const deleteVol = useMutation({ diff --git a/apps/client/app/routes/home.tsx b/apps/client/app/routes/home.tsx index ff443dd..a90460d 100644 --- a/apps/client/app/routes/home.tsx +++ b/apps/client/app/routes/home.tsx @@ -48,6 +48,8 @@ export default function Home({ loaderData }: Route.ComponentProps) { const { data } = useQuery({ ...listVolumesOptions(), initialData: loaderData, + refetchInterval: 10000, + refetchOnWindowFocus: true, }); const filteredVolumes = diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index d13e05c..9a57d0e 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -32,10 +32,10 @@ export const scalarDescriptor = Scalar({ const driver = new Hono().use(honoLogger()).route("/", driverController); const app = new Hono() .use(honoLogger()) - .get("*", serveStatic({ root: "./assets/frontend" })) - .get("healthcheck", (c) => c.json({ status: "ok" })) - .basePath("/api/v1") - .route("/volumes", volumeController); + .get("/healthcheck", (c) => c.json({ status: "ok" })) + .route("/api/v1/volumes", volumeController) + .get("/assets/*", serveStatic({ root: "./assets/frontend" })) + .get("*", serveStatic({ path: "./assets/frontend/index.html" })); app.get("/openapi.json", generalDescriptor(app)); app.get("/docs", scalarDescriptor); diff --git a/apps/server/src/modules/driver/driver.controller.ts b/apps/server/src/modules/driver/driver.controller.ts index b0f1303..09d3c44 100644 --- a/apps/server/src/modules/driver/driver.controller.ts +++ b/apps/server/src/modules/driver/driver.controller.ts @@ -1,6 +1,6 @@ import { Hono } from "hono"; +import { VOLUME_MOUNT_BASE } from "~/core/constants"; import { volumeService } from "../volumes/volume.service"; -import { config } from "../../core/config"; export const driverController = new Hono() .post("/VolumeDriver.Capabilities", (c) => { @@ -30,8 +30,9 @@ export const driverController = new Hono() return c.json({ Err: "Volume name is required" }, 400); } - const volumeRoot = config.volumeRootHost; - const mountpoint = `${volumeRoot}/${body.Name}/_data`; + const volumeName = body.Name.replace(/^im-/, ""); + + const mountpoint = `${VOLUME_MOUNT_BASE}/${volumeName}/_data`; return c.json({ Mountpoint: mountpoint, @@ -54,13 +55,12 @@ export const driverController = new Hono() return c.json({ Err: "Volume name is required" }, 400); } - const volumeRoot = config.volumeRootHost; - const { volume } = await volumeService.getVolume(body.Name); + const { volume } = await volumeService.getVolume(body.Name.replace(/^im-/, "")); return c.json({ Volume: { - Name: volume.name, - Mountpoint: `${volumeRoot}/${volume.name}/_data`, + Name: `im-${volume.name}`, + Mountpoint: `${VOLUME_MOUNT_BASE}/${volume.name}/_data`, Status: {}, }, Err: "", @@ -68,11 +68,10 @@ export const driverController = new Hono() }) .post("/VolumeDriver.List", async (c) => { const volumes = await volumeService.listVolumes(); - const volumeRoot = config.volumeRootHost; const res = volumes.map((volume) => ({ - Name: volume.name, - Mountpoint: `${volumeRoot}/${volume.name}/_data`, + Name: `im-${volume.name}`, + Mountpoint: `${VOLUME_MOUNT_BASE}/${volume.name}/_data`, Status: {}, })); diff --git a/apps/server/src/modules/volumes/volume.service.ts b/apps/server/src/modules/volumes/volume.service.ts index 96a5dbc..be1712a 100644 --- a/apps/server/src/modules/volumes/volume.service.ts +++ b/apps/server/src/modules/volumes/volume.service.ts @@ -6,7 +6,6 @@ import Docker from "dockerode"; import { eq } from "drizzle-orm"; import { ConflictError, InternalServerError, NotFoundError } from "http-errors-enhanced"; import slugify from "slugify"; -import { config } from "../../core/config"; import { VOLUME_MOUNT_BASE } from "../../core/constants"; import { db } from "../../db/db"; import { volumesTable } from "../../db/schema"; @@ -32,14 +31,14 @@ const createVolume = async (name: string, backendConfig: BackendConfig) => { throw new ConflictError("Volume already exists"); } - const volumePathHost = path.join(config.volumeRootHost); + const volumePathHost = path.join(VOLUME_MOUNT_BASE); const val = await db .insert(volumesTable) .values({ name: slug, config: backendConfig, - path: path.join(volumePathHost, slug), + path: path.join(volumePathHost, slug, "_data"), type: backendConfig.backend, }) .returning(); @@ -210,7 +209,7 @@ const getContainersUsingVolume = async (name: string) => { const container = docker.getContainer(info.Id); const inspect = await container.inspect(); const mounts = inspect.Mounts || []; - const usesVolume = mounts.some((mount) => mount.Type === "volume" && mount.Name === name); + const usesVolume = mounts.some((mount) => mount.Type === "volume" && mount.Name === `im-${volume.name}`); if (usesVolume) { usingContainers.push({ id: inspect.Id, diff --git a/apps/server/tsconfig.json b/apps/server/tsconfig.json index 655b76e..5c99579 100644 --- a/apps/server/tsconfig.json +++ b/apps/server/tsconfig.json @@ -13,6 +13,9 @@ "noImplicitOverride": true, "module": "preserve", "noEmit": true, - "lib": ["es2022"] + "lib": ["es2022"], + "paths": { + "~/*": ["./src/*"] + }, } } diff --git a/package.json b/package.json index e7b09f6..89f4f4b 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,8 @@ "tsc": "turbo run tsc", "build": "turbo build", "gen:api-client": "openapi-ts", - "start:dev": "docker rm ironmount && docker compose up --build ironmount-dev", - "start:prod": "docker rm ironmount && docker compose up --build ironmount-prod" + "start:dev": "docker compose down && docker compose up --build ironmount-dev", + "start:prod": "docker compose down && docker compose up --build ironmount-prod" }, "workspaces": [ "apps/*",