diff --git a/src/app/api/applications/route.ts b/src/app/api/applications/route.ts index 4c7d444..e72fd43 100644 --- a/src/app/api/applications/route.ts +++ b/src/app/api/applications/route.ts @@ -1,7 +1,7 @@ import { NextRequest, NextResponse } from "next/server"; import testAuth from "../auth"; import { StatusCodes } from "http-status-codes"; -import { getApplications } from "@/core/server/application"; +import { deployNewApp, getApplications } from "@/core/server/application"; export async function GET(req: NextRequest): Promise { const auth = await testAuth(req); @@ -20,3 +20,30 @@ export async function GET(req: NextRequest): Promise { applications, }); } + +export async function POST(req: NextRequest): Promise { + const auth = await testAuth(req); + const { name, repo, nodeId }: { name: string; repo: string; nodeId: string } = + await req.json(); + + if (auth) { + return NextResponse.json( + { message: auth }, + { status: StatusCodes.UNAUTHORIZED } + ); + } + + if ((!name && !repo) || !nodeId) { + return NextResponse.json( + { message: "Body missing name, repo, nodeId" }, + { status: StatusCodes.BAD_REQUEST } + ); + } + + const res = await deployNewApp(name, repo, nodeId); + + return NextResponse.json({ + message: "ok", + ...res, + }); +} diff --git a/src/core/application.ts b/src/core/application.ts index 9139abd..664ebf8 100644 --- a/src/core/application.ts +++ b/src/core/application.ts @@ -1,77 +1,28 @@ "use server"; import { verifySession } from "./auth/session"; -import { randomUUID } from "crypto"; -import fs from "fs/promises"; -import path from "path"; -import { exec } from "child_process"; -import util from "util"; import { getNodes } from "./node"; import axios from "axios"; import { Application } from "@/lib/types"; -const execAsync = util.promisify(exec); - -const DATA_DIR = path.join(process.cwd(), "data", "apps"); - export async function deployNewApp(name: string, repo: string, nodeId: string) { if (await verifySession()) { throw new Error("Unauthorized"); } - // Create app ID - const appId = `app_${randomUUID()}`; - const appDir = path.join(DATA_DIR, appId); - const repoDir = path.join(appDir, "repo"); + const nodes = await getNodes(); - // Create directories - await fs.mkdir(repoDir, { recursive: true }); + const targetNode = nodes.find((node) => node.node_id === nodeId); - // Write app.json - const appConfig = { - id: appId, - name, - repo, - nodeId, - createdAt: new Date().toISOString(), - }; - - await fs.writeFile( - path.join(appDir, "app.json"), - JSON.stringify(appConfig, null, 2) - ); - - // Clone repository - try { - await execAsync(`git clone ${repo} ${repoDir}`); - } catch (err) { - throw new Error("Failed to clone repository"); - } - - // Validate Dockerfile - const dockerfilePath = path.join(repoDir, "Dockerfile"); - - try { - await fs.access(dockerfilePath); - } catch { - throw new Error("Dockerfile not found in repository root"); - } - - const imageTag = `dockship/${appId}:latest`; - - try { - await execAsync(`docker build -t ${imageTag} .`, { - cwd: repoDir, - }); - } catch { - throw new Error("Docker build failed"); - } - - return { - success: true, - appId, - image: imageTag, - }; + return await ( + await axios.post( + `http://${targetNode?.ip}:3000/api/applications`, + { name, repo, nodeId }, + { + headers: { Authorization: `ApiKey ${targetNode?.key}` }, + } + ) + ).data.applications; } export async function getApplications(): Promise { diff --git a/src/core/server/application.ts b/src/core/server/application.ts index 61b39ab..f2db803 100644 --- a/src/core/server/application.ts +++ b/src/core/server/application.ts @@ -1,9 +1,17 @@ "use server"; -import { Application } from "@/lib/types"; import Docker from "dockerode"; +import { randomUUID } from "crypto"; +import fs from "fs/promises"; +import path from "path"; +import { exec } from "child_process"; +import util from "util"; +import axios from "axios"; +import { Application } from "@/lib/types"; const docker = new Docker(); +const execAsync = util.promisify(exec); +const DATA_DIR = path.join(process.cwd(), "data", "apps"); export async function getApplications(): Promise { const images = await docker.listImages(); @@ -54,3 +62,59 @@ export async function getApplications(): Promise { return apps; } + +export async function deployNewApp(name: string, repo: string, nodeId: string) { + // Create app ID + const appId = `app_${randomUUID()}`; + const appDir = path.join(DATA_DIR, appId); + const repoDir = path.join(appDir, "repo"); + + // Create directories + await fs.mkdir(repoDir, { recursive: true }); + + // Write app.json + const appConfig = { + id: appId, + name, + repo, + nodeId, + createdAt: new Date().toISOString(), + }; + + await fs.writeFile( + path.join(appDir, "app.json"), + JSON.stringify(appConfig, null, 2) + ); + + // Clone repository + try { + await execAsync(`git clone ${repo} ${repoDir}`); + } catch (err) { + throw new Error("Failed to clone repository"); + } + + // Validate Dockerfile + const dockerfilePath = path.join(repoDir, "Dockerfile"); + + try { + await fs.access(dockerfilePath); + } catch { + throw new Error("Dockerfile not found in repository root"); + } + + const imageTag = `dockship/${appId}:latest`; + + try { + await execAsync(`docker build -t ${imageTag} .`, { + cwd: repoDir, + }); + } catch { + throw new Error("Docker build failed"); + } + + return { + success: true, + appId, + image: imageTag, + }; +}