mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-10-22 16:35:26 +00:00
00c708483e
Change restartContainer, startContainer, stopContainer, and killContainer endpoints to use service.read instead of docker.read so members with access to the compose can use container lifecycle actions.
302 lines
8.1 KiB
TypeScript
302 lines
8.1 KiB
TypeScript
import {
|
|
containerKill,
|
|
containerRemove,
|
|
containerRestart,
|
|
containerStart,
|
|
containerStop,
|
|
findServerById,
|
|
getConfig,
|
|
getContainers,
|
|
getContainersByAppLabel,
|
|
getContainersByAppNameMatch,
|
|
getServiceContainersByAppName,
|
|
getStackContainersByAppName,
|
|
uploadFileToContainer,
|
|
} from "@dokploy/server";
|
|
import { TRPCError } from "@trpc/server";
|
|
import { z } from "zod";
|
|
import { audit } from "@/server/api/utils/audit";
|
|
import { uploadFileToContainerSchema } from "@/utils/schema";
|
|
import { createTRPCRouter, withPermission } from "../trpc";
|
|
|
|
export const containerIdRegex = /^[a-zA-Z0-9.\-_]+$/;
|
|
|
|
export const dockerRouter = createTRPCRouter({
|
|
getContainers: withPermission("docker", "read")
|
|
.input(
|
|
z.object({
|
|
serverId: z.string().optional(),
|
|
}),
|
|
)
|
|
.query(async ({ input, ctx }) => {
|
|
if (input.serverId) {
|
|
const server = await findServerById(input.serverId);
|
|
if (server.organizationId !== ctx.session?.activeOrganizationId) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
return await getContainers(input.serverId);
|
|
}),
|
|
|
|
restartContainer: withPermission("service", "read")
|
|
.input(
|
|
z.object({
|
|
containerId: z
|
|
.string()
|
|
.min(1)
|
|
.regex(containerIdRegex, "Invalid container id."),
|
|
serverId: z.string().optional(),
|
|
}),
|
|
)
|
|
.mutation(async ({ input, ctx }) => {
|
|
if (input.serverId) {
|
|
const server = await findServerById(input.serverId);
|
|
if (server.organizationId !== ctx.session?.activeOrganizationId) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
await containerRestart(input.containerId, input.serverId);
|
|
await audit(ctx, {
|
|
action: "start",
|
|
resourceType: "docker",
|
|
resourceId: input.containerId,
|
|
resourceName: input.containerId,
|
|
});
|
|
}),
|
|
|
|
startContainer: withPermission("service", "read")
|
|
.input(
|
|
z.object({
|
|
containerId: z
|
|
.string()
|
|
.min(1)
|
|
.regex(containerIdRegex, "Invalid container id."),
|
|
serverId: z.string().optional(),
|
|
}),
|
|
)
|
|
.mutation(async ({ input, ctx }) => {
|
|
if (input.serverId) {
|
|
const server = await findServerById(input.serverId);
|
|
if (server.organizationId !== ctx.session?.activeOrganizationId) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
await containerStart(input.containerId, input.serverId);
|
|
await audit(ctx, {
|
|
action: "start",
|
|
resourceType: "docker",
|
|
resourceId: input.containerId,
|
|
resourceName: input.containerId,
|
|
});
|
|
}),
|
|
|
|
stopContainer: withPermission("service", "read")
|
|
.input(
|
|
z.object({
|
|
containerId: z
|
|
.string()
|
|
.min(1)
|
|
.regex(containerIdRegex, "Invalid container id."),
|
|
serverId: z.string().optional(),
|
|
}),
|
|
)
|
|
.mutation(async ({ input, ctx }) => {
|
|
if (input.serverId) {
|
|
const server = await findServerById(input.serverId);
|
|
if (server.organizationId !== ctx.session?.activeOrganizationId) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
await containerStop(input.containerId, input.serverId);
|
|
await audit(ctx, {
|
|
action: "stop",
|
|
resourceType: "docker",
|
|
resourceId: input.containerId,
|
|
resourceName: input.containerId,
|
|
});
|
|
}),
|
|
|
|
killContainer: withPermission("service", "read")
|
|
.input(
|
|
z.object({
|
|
containerId: z
|
|
.string()
|
|
.min(1)
|
|
.regex(containerIdRegex, "Invalid container id."),
|
|
serverId: z.string().optional(),
|
|
}),
|
|
)
|
|
.mutation(async ({ input, ctx }) => {
|
|
if (input.serverId) {
|
|
const server = await findServerById(input.serverId);
|
|
if (server.organizationId !== ctx.session?.activeOrganizationId) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
await containerKill(input.containerId, input.serverId);
|
|
await audit(ctx, {
|
|
action: "stop",
|
|
resourceType: "docker",
|
|
resourceId: input.containerId,
|
|
resourceName: input.containerId,
|
|
});
|
|
}),
|
|
|
|
removeContainer: withPermission("docker", "read")
|
|
.input(
|
|
z.object({
|
|
containerId: z
|
|
.string()
|
|
.min(1)
|
|
.regex(containerIdRegex, "Invalid container id."),
|
|
serverId: z.string().optional(),
|
|
}),
|
|
)
|
|
.mutation(async ({ input, ctx }) => {
|
|
if (input.serverId) {
|
|
const server = await findServerById(input.serverId);
|
|
if (server.organizationId !== ctx.session?.activeOrganizationId) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
await containerRemove(input.containerId, input.serverId);
|
|
await audit(ctx, {
|
|
action: "delete",
|
|
resourceType: "docker",
|
|
resourceId: input.containerId,
|
|
resourceName: input.containerId,
|
|
});
|
|
}),
|
|
|
|
getConfig: withPermission("docker", "read")
|
|
.input(
|
|
z.object({
|
|
containerId: z
|
|
.string()
|
|
.min(1)
|
|
.regex(containerIdRegex, "Invalid container id."),
|
|
serverId: z.string().optional(),
|
|
}),
|
|
)
|
|
.query(async ({ input, ctx }) => {
|
|
if (input.serverId) {
|
|
const server = await findServerById(input.serverId);
|
|
if (server.organizationId !== ctx.session?.activeOrganizationId) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
return await getConfig(input.containerId, input.serverId);
|
|
}),
|
|
|
|
getContainersByAppNameMatch: withPermission("service", "read")
|
|
.input(
|
|
z.object({
|
|
appType: z.enum(["stack", "docker-compose"]).optional(),
|
|
appName: z.string().min(1).regex(containerIdRegex, "Invalid app name."),
|
|
serverId: z.string().optional(),
|
|
}),
|
|
)
|
|
.query(async ({ input, ctx }) => {
|
|
if (input.serverId) {
|
|
const server = await findServerById(input.serverId);
|
|
if (server.organizationId !== ctx.session?.activeOrganizationId) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
return await getContainersByAppNameMatch(
|
|
input.appName,
|
|
input.appType,
|
|
input.serverId,
|
|
);
|
|
}),
|
|
|
|
getContainersByAppLabel: withPermission("docker", "read")
|
|
.input(
|
|
z.object({
|
|
appName: z.string().min(1).regex(containerIdRegex, "Invalid app name."),
|
|
serverId: z.string().optional(),
|
|
type: z.enum(["standalone", "swarm"]),
|
|
}),
|
|
)
|
|
.query(async ({ input, ctx }) => {
|
|
if (input.serverId) {
|
|
const server = await findServerById(input.serverId);
|
|
if (server.organizationId !== ctx.session?.activeOrganizationId) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
return await getContainersByAppLabel(
|
|
input.appName,
|
|
input.type,
|
|
input.serverId,
|
|
);
|
|
}),
|
|
|
|
getStackContainersByAppName: withPermission("docker", "read")
|
|
.input(
|
|
z.object({
|
|
appName: z.string().min(1).regex(containerIdRegex, "Invalid app name."),
|
|
serverId: z.string().optional(),
|
|
}),
|
|
)
|
|
.query(async ({ input, ctx }) => {
|
|
if (input.serverId) {
|
|
const server = await findServerById(input.serverId);
|
|
if (server.organizationId !== ctx.session?.activeOrganizationId) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
return await getStackContainersByAppName(input.appName, input.serverId);
|
|
}),
|
|
|
|
getServiceContainersByAppName: withPermission("docker", "read")
|
|
.input(
|
|
z.object({
|
|
appName: z.string().min(1).regex(containerIdRegex, "Invalid app name."),
|
|
serverId: z.string().optional(),
|
|
}),
|
|
)
|
|
.query(async ({ input, ctx }) => {
|
|
if (input.serverId) {
|
|
const server = await findServerById(input.serverId);
|
|
if (server.organizationId !== ctx.session?.activeOrganizationId) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
return await getServiceContainersByAppName(input.appName, input.serverId);
|
|
}),
|
|
|
|
uploadFileToContainer: withPermission("docker", "read")
|
|
.input(uploadFileToContainerSchema)
|
|
.mutation(async ({ input, ctx }) => {
|
|
if (input.serverId) {
|
|
const server = await findServerById(input.serverId);
|
|
if (server.organizationId !== ctx.session?.activeOrganizationId) {
|
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
}
|
|
}
|
|
|
|
const file = input.file;
|
|
if (!(file instanceof File)) {
|
|
throw new TRPCError({
|
|
code: "BAD_REQUEST",
|
|
message: "Invalid file provided",
|
|
});
|
|
}
|
|
|
|
// Convert File to Buffer
|
|
const arrayBuffer = await file.arrayBuffer();
|
|
const fileBuffer = Buffer.from(arrayBuffer);
|
|
|
|
await uploadFileToContainer(
|
|
input.containerId,
|
|
fileBuffer,
|
|
file.name,
|
|
input.destinationPath,
|
|
input.serverId || null,
|
|
);
|
|
|
|
return { success: true, message: "File uploaded successfully" };
|
|
}),
|
|
});
|