Start/stop deployments

This commit is contained in:
2026-02-14 14:09:58 +01:00
parent 2e8525123d
commit 8f320747ad
4 changed files with 94 additions and 12 deletions
+29 -3
View File
@@ -1,7 +1,7 @@
import { NextRequest, NextResponse } from "next/server";
import testAuth from "../auth";
import { StatusCodes } from "http-status-codes";
import { deployApp } from "@/core/deployment";
import { deployApp, toggleDeployment } from "@/core/deployment";
import { Application, Port } from "@/lib/types";
export async function POST(req: NextRequest): Promise<NextResponse> {
@@ -15,14 +15,14 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
if (auth) {
return NextResponse.json(
{ message: auth },
{ status: StatusCodes.UNAUTHORIZED }
{ status: StatusCodes.UNAUTHORIZED },
);
}
if (!name || !app) {
return NextResponse.json(
{ message: "Body missing name, appId, nodeId" },
{ status: StatusCodes.BAD_REQUEST }
{ status: StatusCodes.BAD_REQUEST },
);
}
@@ -33,3 +33,29 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
deployId,
});
}
export async function PUT(req: NextRequest): Promise<NextResponse> {
const auth = await testAuth(req);
const { deployId, action }: { deployId: string; action: "start" | "stop" } =
await req.json();
if (auth) {
return NextResponse.json(
{ message: auth },
{ status: StatusCodes.UNAUTHORIZED },
);
}
if (!deployId || !action) {
return NextResponse.json(
{ message: "Body missing deployId or action" },
{ status: StatusCodes.BAD_REQUEST },
);
}
await toggleDeployment(deployId, action);
return NextResponse.json({
message: "ok",
});
}
+22 -5
View File
@@ -10,8 +10,8 @@ import {
} from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Plus, Play, Pause } from "lucide-react";
import { getDeployments } from "@/lib/dockship/deploy";
import { Plus, Play, Pause, Square } from "lucide-react";
import { getDeployments, toggleDeployment } from "@/lib/dockship/deploy";
import { getApps } from "@/lib/dockship/application";
import { cn } from "@/lib/utils";
import DeployAppDialog from "@/components/dialogs/DeployApp";
@@ -39,6 +39,14 @@ export default function DeploymentsPage() {
return map;
}, [apps]);
const changeDeploymentStatus = async (
deployId: string,
action: "start" | "stop",
) => {
console.log(`Toggling deployment ${deployId} with action ${action}`);
await toggleDeployment(deployId, action);
};
return (
<DashboardLayout
title="Deployments"
@@ -90,13 +98,22 @@ export default function DeploymentsPage() {
{dep.image}
</p>
<div className="flex justify-end gap-1">
<Button variant="ghost" size="icon-sm">
<Button
variant="ghost"
size="icon-sm"
onClick={async () =>
await changeDeploymentStatus(
dep.container,
dep.status === "stopped" ? "start" : "stop",
)
}
>
{dep.status === "stopped" ? (
<Play className="w-3 h-3" />
) : dep.status === "running" ? (
<Pause className="w-3 h-3" />
<Square className="w-3 h-3" />
) : (
<Pause className="w-3 h-3 text-primary" />
<Square className="w-3 h-3 text-primary" />
)}
</Button>
<RemoveDialog remove={() => {}} />
+17
View File
@@ -164,3 +164,20 @@ export async function deployApp(
fs.rmSync(deployPath, { recursive: true, force: true });
}
}
export async function toggleDeployment(
containerId: string,
action: "start" | "stop",
) {
const container = docker.getContainer(containerId);
try {
if (action === "start") {
await container.start();
} else {
await container.stop();
}
} catch (err) {
console.error(`Failed to ${action} container ${containerId}:`, err);
}
}
+26 -4
View File
@@ -17,8 +17,8 @@ export async function getDeployments(): Promise<Deployment[]> {
await axios.post(`http://${n.ip}:3000/api/get-deployments`, apps, {
headers: { Authorization: `ApiKey ${n.key}` },
})
).data.deployments
)
).data.deployments,
),
)
).flat();
}
@@ -27,7 +27,7 @@ export async function deployApp(
name: string,
appId: string,
nodeId: string,
ports: Port[]
ports: Port[],
): Promise<string | undefined> {
const nodes = await getNodes();
@@ -44,7 +44,7 @@ export async function deployApp(
{ name, app, ports },
{
headers: { Authorization: `ApiKey ${node.key}` },
}
},
)
).data.deployId;
@@ -54,3 +54,25 @@ export async function deployApp(
return deployId;
}
export async function toggleDeployment(
deployId: string,
action: "start" | "stop",
) {
const nodes = await getNodes();
await Promise.all(
nodes.map(
async (node) =>
await axios.put(
`http://${node.ip}:3000/api/deploy`,
{ deployId, action },
{
headers: { Authorization: `ApiKey ${node.key}` },
},
),
),
);
return "ok";
}