Skip to content

Commit ce6d595

Browse files
committed
Add backend support for pod and queue creation
Signed-off-by: Shrutim1505 <[email protected]>
1 parent 08a0f8f commit ce6d595

File tree

8 files changed

+1428
-2727
lines changed

8 files changed

+1428
-2727
lines changed

backend/src/server.js

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
import yaml from "js-yaml";
99

1010
export const app = express();
11+
app.use(express.json());
12+
1113
app.use(cors({ origin: "*" }));
1214

1315
const kc = new KubeConfig();
@@ -479,6 +481,192 @@ app.get("/api/all-pods", async (req, res) => {
479481
}
480482
});
481483

484+
// POST /api/pods - Create a pod
485+
app.post("/api/pods", async (req, res) => {
486+
let podManifest = req.body;
487+
console.log("Received pod manifest:", JSON.stringify(podManifest, null, 2));
488+
489+
try {
490+
// Defensive: check manifest shape
491+
if (
492+
!podManifest ||
493+
!podManifest.metadata ||
494+
!podManifest.metadata.name ||
495+
!podManifest.spec
496+
) {
497+
return res.status(400).json({ error: "Invalid pod manifest" });
498+
}
499+
500+
// Fix the apiVersion for regular Pods
501+
if (podManifest.apiVersion === "scheduling.volcano.sh/v1beta1") {
502+
podManifest.apiVersion = "v1";
503+
}
504+
505+
// Fix the kind
506+
if (podManifest.kind !== "Pod") {
507+
podManifest.kind = "Pod";
508+
}
509+
510+
// Validate that this is a proper Pod spec (not Queue spec)
511+
if (podManifest.spec.weight || podManifest.spec.reclaimable) {
512+
return res.status(400).json({
513+
error: "Invalid Pod spec. Use proper Pod specification with containers, not Queue fields.",
514+
});
515+
}
516+
517+
// Ensure Pod spec has required containers field
518+
if (
519+
!podManifest.spec.containers ||
520+
!Array.isArray(podManifest.spec.containers)
521+
) {
522+
return res.status(400).json({
523+
error: "Pod spec must include 'containers' array",
524+
});
525+
}
526+
527+
// Defensive: never allow "All", fallback to "default" if missing
528+
let namespace = podManifest.metadata.namespace;
529+
if (
530+
!namespace ||
531+
namespace === "All" ||
532+
typeof namespace !== "string" ||
533+
!namespace.trim()
534+
) {
535+
namespace = "default";
536+
podManifest.metadata.namespace = namespace;
537+
}
538+
539+
console.log("Creating pod in namespace:", namespace);
540+
console.log(
541+
"Final pod manifest:",
542+
JSON.stringify(podManifest, null, 2),
543+
);
544+
545+
// Use object-based syntax for consistency
546+
const response = await k8sCoreApi.createNamespacedPod({
547+
namespace: namespace,
548+
body: podManifest,
549+
});
550+
551+
res.status(201).json({
552+
message: "Pod created successfully",
553+
data: response.body,
554+
});
555+
} catch (error) {
556+
console.error("Error creating pod:", error?.body || error);
557+
let msg = "Failed to create pod";
558+
if (error?.body?.message) {
559+
msg = error.body.message;
560+
} else if (error?.message) {
561+
msg = error.message;
562+
}
563+
res.status(500).json({ error: msg });
564+
}
565+
});
566+
// POST /api/jobs - Create a job (Volcano custom job)
567+
app.post("/api/jobs", async (req, res) => {
568+
const jobManifest = req.body;
569+
try {
570+
if (
571+
!jobManifest ||
572+
!jobManifest.metadata ||
573+
!jobManifest.metadata.name ||
574+
!jobManifest.spec
575+
) {
576+
return res.status(400).json({ error: "Invalid job manifest" });
577+
}
578+
579+
const namespace = jobManifest.metadata.namespace || "default";
580+
const response = await k8sApi.createNamespacedCustomObject(
581+
"batch.volcano.sh",
582+
"v1alpha1",
583+
namespace,
584+
"jobs",
585+
jobManifest,
586+
);
587+
588+
res.status(201).json({
589+
message: "Job created successfully",
590+
data: response.body,
591+
});
592+
} catch (error) {
593+
console.error("Error creating job:", error?.body || error);
594+
let msg = "Failed to create job";
595+
if (error?.body?.message) msg = error.body.message;
596+
res.status(500).json({ error: msg });
597+
}
598+
});
599+
600+
//create a queue
601+
app.post("/api/queues", async (req, res) => {
602+
const queueManifest = req.body;
603+
604+
try {
605+
if (
606+
!queueManifest ||
607+
!queueManifest.metadata ||
608+
!queueManifest.metadata.name ||
609+
!queueManifest.spec
610+
) {
611+
return res.status(400).json({ error: "Invalid queue manifest" });
612+
}
613+
614+
// Debug the API client
615+
console.log("API client type:", typeof k8sApi);
616+
console.log(
617+
"createClusterCustomObject method exists:",
618+
typeof k8sApi.createClusterCustomObject,
619+
);
620+
621+
// Test if we can list queues first (simpler operation)
622+
console.log("Testing list operation first...");
623+
try {
624+
const listResponse = await k8sApi.listClusterCustomObject({
625+
group: "scheduling.volcano.sh",
626+
version: "v1beta1",
627+
plural: "queues",
628+
});
629+
console.log(
630+
"List operation successful, found",
631+
listResponse.items?.length || 0,
632+
"queues",
633+
);
634+
} catch (listError) {
635+
console.error("List operation failed:", listError.message);
636+
}
637+
638+
// Add timeout and more detailed logging
639+
console.log("About to call k8sApi.createClusterCustomObject...");
640+
641+
const response = await Promise.race([
642+
k8sApi.createClusterCustomObject({
643+
group: "scheduling.volcano.sh",
644+
version: "v1beta1",
645+
plural: "queues",
646+
body: queueManifest,
647+
}),
648+
new Promise((_, reject) =>
649+
setTimeout(
650+
() => reject(new Error("API call timeout after 30s")),
651+
30000,
652+
),
653+
),
654+
]);
655+
656+
console.log("API call successful, response:", response);
657+
658+
res.status(201).json({
659+
message: "Queue created successfully",
660+
data: response.body,
661+
});
662+
} catch (error) {
663+
console.error("Error creating queue:", error?.body || error);
664+
let msg = "Failed to create queue";
665+
if (error?.body?.message) msg = error.body.message;
666+
res.status(500).json({ error: msg });
667+
}
668+
});
669+
482670
app.delete("/api/queues/:name", async (req, res) => {
483671
const { name } = req.params;
484672
const queueName = name.toLowerCase();

0 commit comments

Comments
 (0)