improve orchestrator, docker settings, and ui layouts
This commit is contained in:
@ -22,7 +22,7 @@ spec:
|
||||
image: ishaan1013/sandbox:latest
|
||||
ports:
|
||||
- containerPort: 4000
|
||||
- containerPort: 3000
|
||||
- containerPort: 8000
|
||||
volumeMounts:
|
||||
- name: workspace-volume
|
||||
mountPath: /workspace
|
||||
@ -54,8 +54,8 @@ spec:
|
||||
targetPort: 4000
|
||||
- protocol: TCP
|
||||
name: user
|
||||
port: 3000
|
||||
targetPort: 3000
|
||||
port: 8000
|
||||
targetPort: 8000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
@ -83,4 +83,4 @@ spec:
|
||||
service:
|
||||
name: <SANDBOX>
|
||||
port:
|
||||
number: 3000
|
||||
number: 8000
|
||||
|
@ -19,9 +19,12 @@ app.use(express.json())
|
||||
dotenv.config()
|
||||
|
||||
const corsOptions = {
|
||||
origin: ['http://localhost:3000', 'https://s.ishaand.com', 'http://localhost:4000'],
|
||||
origin: ['http://localhost:3000', 'https://s.ishaand.com', 'http://localhost:4000', /\.ws\.ishaand\.com$/],
|
||||
}
|
||||
|
||||
// app.use(cors(corsOptions))
|
||||
app.use(cors())
|
||||
|
||||
const kubeconfig = new KubeConfig()
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
kubeconfig.loadFromOptions({
|
||||
@ -110,25 +113,26 @@ const dataSchema = z.object({
|
||||
sandboxId: z.string(),
|
||||
})
|
||||
|
||||
const namespace = "sandbox"
|
||||
const namespace = "ingress-nginx"
|
||||
|
||||
app.get("/test", cors(), async (req, res) => {
|
||||
app.post("/test", async (req, res) => {
|
||||
res.status(200).send({ message: "Orchestrator is up and running." })
|
||||
})
|
||||
|
||||
app.get("/test/cors", cors(corsOptions), async (req, res) => {
|
||||
res.status(200).send({ message: "With CORS, Orchestrator is up and running." })
|
||||
})
|
||||
|
||||
app.post("/start", cors(corsOptions), async (req, res) => {
|
||||
app.post("/start", async (req, res) => {
|
||||
const { sandboxId } = dataSchema.parse(req.body)
|
||||
|
||||
try {
|
||||
|
||||
console.log("Creating resources for sandbox", sandboxId)
|
||||
|
||||
const kubeManifests = readAndParseKubeYaml(
|
||||
path.join(__dirname, "../service.yaml"),
|
||||
sandboxId
|
||||
)
|
||||
|
||||
console.log("Successfully read and parsed kube yaml")
|
||||
|
||||
async function resourceExists(api: any, getMethod: string, name: string) {
|
||||
try {
|
||||
await api[getMethod](namespace, name)
|
||||
@ -139,44 +143,57 @@ app.post("/start", cors(corsOptions), async (req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
kubeManifests.forEach(async (manifest) => {
|
||||
const promises = kubeManifests.map(async (manifest) => {
|
||||
const { kind, metadata: { name } } = manifest
|
||||
|
||||
if (kind === "Deployment")
|
||||
if (!(await resourceExists(appsV1Api, 'readNamespacedDeployment', name))) {
|
||||
await appsV1Api.createNamespacedDeployment(namespace, manifest)
|
||||
console.log("Made deploymnet")
|
||||
} else {
|
||||
return res.status(200).send({ message: "Resource deployment already exists." })
|
||||
}
|
||||
else if (kind === "Service")
|
||||
if (!(await resourceExists(coreV1Api, 'readNamespacedService', name))) {
|
||||
await coreV1Api.createNamespacedService(namespace, manifest)
|
||||
console.log("Made service")
|
||||
} else {
|
||||
return res.status(200).send({ message: "Resource service already exists." })
|
||||
}
|
||||
else if (kind === "Ingress")
|
||||
if (!(await resourceExists(networkingV1Api, 'readNamespacedIngress', name))) {
|
||||
await networkingV1Api.createNamespacedIngress(namespace, manifest)
|
||||
console.log("Made ingress")
|
||||
} else {
|
||||
return res.status(200).send({ message: "Resource ingress already exists." })
|
||||
}
|
||||
})
|
||||
|
||||
await Promise.all(promises)
|
||||
|
||||
console.log("All done!")
|
||||
res.status(200).send({ message: "Resources created." })
|
||||
} catch (error) {
|
||||
console.log("Failed to create resources", error)
|
||||
} catch (error: any) {
|
||||
const body = error.response.body
|
||||
console.log("Failed to create resources", body)
|
||||
|
||||
if (body.code === 409) {
|
||||
return res.status(200).send({ message: "Resource already exists." })
|
||||
}
|
||||
res.status(500).send({ message: "Failed to create resources." })
|
||||
}
|
||||
})
|
||||
|
||||
app.post("/stop", cors(corsOptions), async (req, res) => {
|
||||
app.post("/stop", async (req, res) => {
|
||||
const { sandboxId } = dataSchema.parse(req.body)
|
||||
console.log("Deleting resources for sandbox", sandboxId)
|
||||
|
||||
try {
|
||||
const kubeManifests = readAndParseKubeYaml(
|
||||
path.join(__dirname, "../service.yaml"),
|
||||
sandboxId
|
||||
)
|
||||
kubeManifests.forEach(async (manifest) => {
|
||||
const promises = kubeManifests.map(async (manifest) => {
|
||||
if (manifest.kind === "Deployment")
|
||||
await appsV1Api.deleteNamespacedDeployment(
|
||||
manifest.metadata?.name || "",
|
||||
@ -193,6 +210,9 @@ app.post("/stop", cors(corsOptions), async (req, res) => {
|
||||
namespace
|
||||
)
|
||||
})
|
||||
|
||||
await Promise.all(promises)
|
||||
|
||||
res.status(200).send({ message: "Resources deleted." })
|
||||
} catch (error) {
|
||||
console.log("Failed to delete resources", error)
|
||||
|
@ -1,2 +1,3 @@
|
||||
.env
|
||||
node_modules
|
||||
projects
|
@ -1,8 +1,10 @@
|
||||
ARG CF_API_TOKEN
|
||||
ARG CF_USER_ID
|
||||
|
||||
FROM node:20
|
||||
|
||||
# Security: Drop all capabilities
|
||||
USER root
|
||||
RUN apt-get update && apt-get install -y libcap2-bin
|
||||
RUN setcap cap_net_bind_service=+ep /usr/local/bin/node
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
COPY package*.json ./
|
||||
@ -13,8 +15,15 @@ COPY . .
|
||||
|
||||
RUN npm run build
|
||||
|
||||
# Security: Create non-root user and assign ownership
|
||||
RUN useradd -m myuser
|
||||
RUN mkdir projects && chown -R myuser:myuser projects
|
||||
USER myuser
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ARG CF_API_TOKEN
|
||||
ARG CF_USER_ID
|
||||
ENV CF_API_TOKEN=$CF_API_TOKEN
|
||||
ENV CF_USER_ID=$CF_USER_ID
|
||||
|
||||
|
@ -435,15 +435,16 @@ io.on("connection", async (socket) => {
|
||||
clearTimeout(inactivityTimeout)
|
||||
};
|
||||
if (sockets.length === 0) {
|
||||
console.log("STARTING TIMER")
|
||||
inactivityTimeout = setTimeout(() => {
|
||||
io.fetchSockets().then(sockets => {
|
||||
io.fetchSockets().then(async (sockets) => {
|
||||
if (sockets.length === 0) {
|
||||
// close server
|
||||
console.log("Closing server due to inactivity.");
|
||||
stopServer(data.sandboxId, data.userId)
|
||||
// const res = await stopServer(data.sandboxId, data.userId)
|
||||
}
|
||||
});
|
||||
}, 60000);
|
||||
}, 20000);
|
||||
}
|
||||
|
||||
})
|
||||
|
@ -198,7 +198,7 @@ ${code}`,
|
||||
}
|
||||
|
||||
export const stopServer = async (sandboxId: string, userId: string) => {
|
||||
await fetch("http://localhost:4001/stop", {
|
||||
const res = await fetch("http://localhost:4001/stop", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
@ -208,4 +208,7 @@ export const stopServer = async (sandboxId: string, userId: string) => {
|
||||
userId
|
||||
}),
|
||||
})
|
||||
const data = await res.json()
|
||||
|
||||
return data
|
||||
}
|
@ -55,6 +55,9 @@ import react from '@vitejs/plugin-react'
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
port: 8000,
|
||||
},
|
||||
})
|
||||
`,
|
||||
},
|
||||
|
Reference in New Issue
Block a user