mirror of
https://github.com/nicotsx/ironmount.git
synced 2025-12-10 12:10:51 +01:00
feat: display containers using the volume
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
"@ironmount/schemas": "workspace:*",
|
||||
"@scalar/hono-api-reference": "^0.9.13",
|
||||
"arktype": "^2.1.20",
|
||||
"dockerode": "^4.0.8",
|
||||
"dotenv": "^17.2.1",
|
||||
"drizzle-orm": "^0.44.4",
|
||||
"hono": "^4.9.2",
|
||||
@@ -22,6 +23,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.2.20",
|
||||
"@types/dockerode": "^3.3.44",
|
||||
"drizzle-kit": "^0.31.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { and, eq, or } from "drizzle-orm";
|
||||
import { getTasks, schedule } from "node-cron";
|
||||
import { db } from "../../db/db";
|
||||
import { logger } from "../../utils/logger";
|
||||
import { volumesTable } from "../../db/schema";
|
||||
import { schedule, getTasks } from "node-cron";
|
||||
import { logger } from "../../utils/logger";
|
||||
import { volumeService } from "../volumes/volume.service";
|
||||
|
||||
export const startup = async () => {
|
||||
@@ -18,7 +18,7 @@ export const startup = async () => {
|
||||
}
|
||||
|
||||
const existingTasks = getTasks();
|
||||
existingTasks.forEach((task) => task.destroy());
|
||||
existingTasks.forEach(async (task) => await task.destroy());
|
||||
|
||||
schedule("* * * * *", async () => {
|
||||
logger.info("Running health check for all volumes...");
|
||||
|
||||
@@ -4,16 +4,18 @@ import {
|
||||
createVolumeBody,
|
||||
createVolumeDto,
|
||||
deleteVolumeDto,
|
||||
type GetVolumeResponseDto,
|
||||
getContainersDto,
|
||||
getVolumeDto,
|
||||
type ListContainersResponseDto,
|
||||
type ListVolumesResponseDto,
|
||||
listVolumesDto,
|
||||
mountVolumeDto,
|
||||
testConnectionBody,
|
||||
testConnectionDto,
|
||||
unmountVolumeDto,
|
||||
updateVolumeBody,
|
||||
updateVolumeDto,
|
||||
mountVolumeDto,
|
||||
unmountVolumeDto,
|
||||
type GetVolumeResponseDto,
|
||||
} from "./volume.dto";
|
||||
import { volumeService } from "./volume.service";
|
||||
|
||||
@@ -70,6 +72,16 @@ export const volumeController = new Hono()
|
||||
|
||||
return c.json(response, 200);
|
||||
})
|
||||
.get("/:name/containers", getContainersDto, async (c) => {
|
||||
const { name } = c.req.param();
|
||||
const { containers } = await volumeService.getContainersUsingVolume(name);
|
||||
|
||||
const response = {
|
||||
containers,
|
||||
} satisfies ListContainersResponseDto;
|
||||
|
||||
return c.json(response, 200);
|
||||
})
|
||||
.put("/:name", updateVolumeDto, validator("json", updateVolumeBody), async (c) => {
|
||||
const { name } = c.req.param();
|
||||
const body = c.req.valid("json");
|
||||
|
||||
@@ -258,3 +258,38 @@ export const unmountVolumeDto = describeRoute({
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Get containers using a volume
|
||||
*/
|
||||
const containerSchema = type({
|
||||
id: "string",
|
||||
name: "string",
|
||||
state: "string",
|
||||
image: "string",
|
||||
});
|
||||
|
||||
export const listContainersResponse = type({
|
||||
containers: containerSchema.array(),
|
||||
});
|
||||
export type ListContainersResponseDto = typeof listContainersResponse.infer;
|
||||
|
||||
export const getContainersDto = describeRoute({
|
||||
description: "Get containers using a volume by name",
|
||||
operationId: "getContainersUsingVolume",
|
||||
validateResponse: true,
|
||||
tags: ["Volumes"],
|
||||
responses: {
|
||||
200: {
|
||||
description: "List of containers using the volume",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(listContainersResponse),
|
||||
},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: "Volume not found",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -2,17 +2,17 @@ import * as fs from "node:fs/promises";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import type { BackendConfig } from "@ironmount/schemas";
|
||||
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";
|
||||
import { createVolumeBackend } from "../backends/backend";
|
||||
import { toMessage } from "../../utils/errors";
|
||||
import { getStatFs, type StatFs } from "../../utils/mountinfo";
|
||||
import { VOLUME_MOUNT_BASE } from "../../core/constants";
|
||||
import { logger } from "../../utils/logger";
|
||||
import { createVolumeBackend } from "../backends/backend";
|
||||
|
||||
const listVolumes = async () => {
|
||||
const volumes = await db.query.volumesTable.findMany({});
|
||||
@@ -192,6 +192,37 @@ const checkHealth = async (name: string) => {
|
||||
return { status, error };
|
||||
};
|
||||
|
||||
const getContainersUsingVolume = async (name: string) => {
|
||||
const volume = await db.query.volumesTable.findFirst({
|
||||
where: eq(volumesTable.name, name),
|
||||
});
|
||||
|
||||
if (!volume) {
|
||||
throw new NotFoundError("Volume not found");
|
||||
}
|
||||
|
||||
const docker = new Docker();
|
||||
const containers = await docker.listContainers({ all: true });
|
||||
|
||||
const usingContainers = [];
|
||||
for (const info of containers) {
|
||||
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);
|
||||
if (usesVolume) {
|
||||
usingContainers.push({
|
||||
id: inspect.Id,
|
||||
name: inspect.Name,
|
||||
state: inspect.State.Status,
|
||||
image: inspect.Config.Image,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { containers: usingContainers };
|
||||
};
|
||||
|
||||
export const volumeService = {
|
||||
listVolumes,
|
||||
createVolume,
|
||||
@@ -202,4 +233,5 @@ export const volumeService = {
|
||||
testConnection,
|
||||
unmountVolume,
|
||||
checkHealth,
|
||||
getContainersUsingVolume,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user