Start/stop deployments
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import testAuth from "../auth";
|
import testAuth from "../auth";
|
||||||
import { StatusCodes } from "http-status-codes";
|
import { StatusCodes } from "http-status-codes";
|
||||||
import { deployApp } from "@/core/deployment";
|
import { deployApp, toggleDeployment } from "@/core/deployment";
|
||||||
import { Application, Port } from "@/lib/types";
|
import { Application, Port } from "@/lib/types";
|
||||||
|
|
||||||
export async function POST(req: NextRequest): Promise<NextResponse> {
|
export async function POST(req: NextRequest): Promise<NextResponse> {
|
||||||
@@ -15,14 +15,14 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
|
|||||||
if (auth) {
|
if (auth) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ message: auth },
|
{ message: auth },
|
||||||
{ status: StatusCodes.UNAUTHORIZED }
|
{ status: StatusCodes.UNAUTHORIZED },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!name || !app) {
|
if (!name || !app) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ message: "Body missing name, appId, nodeId" },
|
{ 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,
|
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",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import {
|
|||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Plus, Play, Pause } from "lucide-react";
|
import { Plus, Play, Pause, Square } from "lucide-react";
|
||||||
import { getDeployments } from "@/lib/dockship/deploy";
|
import { getDeployments, toggleDeployment } from "@/lib/dockship/deploy";
|
||||||
import { getApps } from "@/lib/dockship/application";
|
import { getApps } from "@/lib/dockship/application";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import DeployAppDialog from "@/components/dialogs/DeployApp";
|
import DeployAppDialog from "@/components/dialogs/DeployApp";
|
||||||
@@ -39,6 +39,14 @@ export default function DeploymentsPage() {
|
|||||||
return map;
|
return map;
|
||||||
}, [apps]);
|
}, [apps]);
|
||||||
|
|
||||||
|
const changeDeploymentStatus = async (
|
||||||
|
deployId: string,
|
||||||
|
action: "start" | "stop",
|
||||||
|
) => {
|
||||||
|
console.log(`Toggling deployment ${deployId} with action ${action}`);
|
||||||
|
await toggleDeployment(deployId, action);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardLayout
|
<DashboardLayout
|
||||||
title="Deployments"
|
title="Deployments"
|
||||||
@@ -90,13 +98,22 @@ export default function DeploymentsPage() {
|
|||||||
{dep.image}
|
{dep.image}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex justify-end gap-1">
|
<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" ? (
|
{dep.status === "stopped" ? (
|
||||||
<Play className="w-3 h-3" />
|
<Play className="w-3 h-3" />
|
||||||
) : dep.status === "running" ? (
|
) : 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>
|
</Button>
|
||||||
<RemoveDialog remove={() => {}} />
|
<RemoveDialog remove={() => {}} />
|
||||||
|
|||||||
@@ -164,3 +164,20 @@ export async function deployApp(
|
|||||||
fs.rmSync(deployPath, { recursive: true, force: true });
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ export async function getDeployments(): Promise<Deployment[]> {
|
|||||||
await axios.post(`http://${n.ip}:3000/api/get-deployments`, apps, {
|
await axios.post(`http://${n.ip}:3000/api/get-deployments`, apps, {
|
||||||
headers: { Authorization: `ApiKey ${n.key}` },
|
headers: { Authorization: `ApiKey ${n.key}` },
|
||||||
})
|
})
|
||||||
).data.deployments
|
).data.deployments,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
).flat();
|
).flat();
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@ export async function deployApp(
|
|||||||
name: string,
|
name: string,
|
||||||
appId: string,
|
appId: string,
|
||||||
nodeId: string,
|
nodeId: string,
|
||||||
ports: Port[]
|
ports: Port[],
|
||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
const nodes = await getNodes();
|
const nodes = await getNodes();
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ export async function deployApp(
|
|||||||
{ name, app, ports },
|
{ name, app, ports },
|
||||||
{
|
{
|
||||||
headers: { Authorization: `ApiKey ${node.key}` },
|
headers: { Authorization: `ApiKey ${node.key}` },
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
).data.deployId;
|
).data.deployId;
|
||||||
|
|
||||||
@@ -54,3 +54,25 @@ export async function deployApp(
|
|||||||
|
|
||||||
return deployId;
|
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";
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user