Skip to content

Commit

Permalink
Merge pull request #12 from rassi0429/develop
Browse files Browse the repository at this point in the history
v1.0.0
  • Loading branch information
rassi0429 authored Feb 16, 2025
2 parents 7dc94bd + b72b8ba commit a88730a
Show file tree
Hide file tree
Showing 8 changed files with 655 additions and 262 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/build-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Build Check

on:
pull_request:
branches: [ develop, main ] # Adjust if necessary

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 22 # Adjust Node.js version as needed

- name: Install dependencies
run: npm ci

- name: Build project
run: npm run build
24 changes: 18 additions & 6 deletions .idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

203 changes: 124 additions & 79 deletions workspaces/backend/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import express from "express";
import {parseEnvVars} from "../lib/utils.js";
import {KubeConfig, CoreV1Api, NetworkingV1Api} from '@kubernetes/client-node';
import {createPodSpec, createServiceSpec, createIngressSpec} from '../lib/k8s/index.js';
import {KubeConfig, CoreV1Api, NetworkingV1Api, AppsV1Api} from '@kubernetes/client-node';
import {
createServiceSpec,
createIngressSpec,
createNamespaceSpec,
createDeploymentSpec
} from '../lib/k8s/index.js';


const router = express.Router();
Expand All @@ -12,96 +17,136 @@ const kc = new KubeConfig();
// (1) ローカル開発で~/.kube/configを使う場合
kc.loadFromDefault()

const k8sApps = kc.makeApiClient(AppsV1Api);
const k8sCore = kc.makeApiClient(CoreV1Api);
const k8sNetApi = kc.makeApiClient(NetworkingV1Api);

// "/api"

router.get("/", (req, res) => {
res.send("Hello from API");
res.send("Hello from API");
});

router.post("/deploy", async (req, res) => {
const {repoUrl} = req.body;
const {envVars} = req.body;
const {host} = req.body;

const parsedEnv = parseEnvVars(envVars || '');

try {
// Pod用マニフェストを作成
const podManifest = createPodSpec(repoUrl, parsedEnv);
const serviceManifest = createServiceSpec(podManifest.metadata.name, 3000);
const ingressManifest = createIngressSpec(podManifest.metadata.name, host)

const response = await k8sCore.createNamespacedPod({namespace: 'default', body: podManifest});
const serviceResponse = await k8sCore.createNamespacedService({namespace: 'default', body: serviceManifest});
const ingressResponse = await k8sNetApi.createNamespacedIngress({namespace: 'default', body: ingressManifest})
const createdPodName = response.metadata?.name;
res.json({
message: `Pod ${createdPodName} created successfully`,
podName: createdPodName,
})
} catch (error) {
console.error('Error creating Pod:', error);
const errorMessage = (error as Error).message;
res.status(500).json({error: errorMessage});
}
const {namespace} = req.body;
const {repoUrl} = req.body;
const {envVars} = req.body;
const {host} = req.body;

const parsedEnv = parseEnvVars(envVars || '');

try {
const k8sNamespace = createNamespaceSpec(namespace, {
repositoryUrl: repoUrl.replace(/https?:\/\//, '').replace(/\//g, '_'),
deployEnvVars: envVars,
deployUser: "admin"
})
await k8sCore.createNamespace({body: k8sNamespace})

// Pod用マニフェストを作成
const deployManifest = createDeploymentSpec(repoUrl, parsedEnv, 1, namespace);
const serviceManifest = createServiceSpec(deployManifest.metadata.name, 3000, namespace);
const ingressManifest = createIngressSpec(deployManifest.metadata.name, host, namespace)


const deployment = await k8sApps.createNamespacedDeployment({namespace: namespace, body: deployManifest});
const serviceResponse = await k8sCore.createNamespacedService({namespace: namespace, body: serviceManifest});
const ingressResponse = await k8sNetApi.createNamespacedIngress({namespace: namespace, body: ingressManifest})
const createdPodName = deployment.metadata?.name;
res.json({
message: `Deployment ${createdPodName} created successfully`,
podName: createdPodName,
})
} catch (error) {
console.error('Error creating Pod:', error);
const errorMessage = (error as Error).message;
res.status(500).json({error: errorMessage});
}
})


router.get('/pods', async (req, res) => {
try {
const podsResponse = await k8sCore.listNamespacedPod({namespace: 'default'});
const serviceResponse = await k8sCore.listNamespacedService({namespace: "default"})
const ingressResponse = await k8sNetApi.listNamespacedIngress({namespace: "default"})

const pods = podsResponse.items;

res.json({
pods: pods.map(pod => ({
name: pod.metadata?.name,
status: pod.status?.phase,
service: serviceResponse.items.find(service => service.metadata?.name === pod.metadata?.name),
ingress: ingressResponse.items.find(ingress => ingress.metadata?.name === pod.metadata?.name)
}))
})
} catch (error) {
console.error('Error listing pods:', error);
const errorMessage = (error as Error).message;
res.status(500).json({error: errorMessage});
}
router.get('/namespaces', async (req, res) => {
try {
const namespacesResponse = await k8sCore.listNamespace({labelSelector: 'openKokopiManaged=true'});
res.json(namespacesResponse.items)
} catch (error) {
console.error('Error listing pods:', error);
const errorMessage = (error as Error).message;
res.status(500).json({error: errorMessage});
}
});

router.get('/pods/:name/logs', async (req, res) => {
const podName = req.params.name;
try {
// initContainerは完了後に終了するので、ログを見たいのはメインコンテナ "node-bot" の想定
const logsResponse = await k8sCore.readNamespacedPodLog({
namespace: 'default',
name: podName,
container: 'node-bot'
});
res.json({log:logsResponse});
} catch (error) {
console.error('Error fetching logs:', error);
const errorMessage = (error as Error).message;
res.status(500).json({error: errorMessage});
}
});
router.get("/namespace/:namespace/pods", async (req, res) => {
const namespace = req.params.namespace;
try {
const podsResponse = await k8sCore.listNamespacedPod({namespace: namespace});
res.json(podsResponse.items);
} catch (error) {
console.error('Error listing pods:', error);
const errorMessage = (error as Error).message;
res.status(500).json({error: errorMessage});
}
})

router.get('/pods/:name/delete', async (req, res) => {
const podName = req.params.name;
try {
await k8sCore.deleteNamespacedPod({namespace: 'default', name: podName});
await k8sCore.deleteNamespacedService({namespace: "default", name: podName})
await k8sNetApi.deleteNamespacedIngress({namespace: "default", name: podName})
res.json({message: `Pod ${podName} deleted successfully`});
} catch (error) {
console.error('Error deleting pod:', error);
const errorMessage = (error as Error).message;
res.status(500).json({error: errorMessage});
}
});
router.get("/namespace/:namespace/pod/:podname" , async (req, res) => {
const namespace = req.params.namespace;
const podName = req.params.podname;
try {
const podResponse = await k8sCore.readNamespacedPod({namespace: namespace, name: podName});
res.json(podResponse);
} catch (error) {
console.error('Error fetching pod:', error);
const errorMessage = (error as Error).message;
res.status(500).json({error: errorMessage});
}
})

router.get("/namespace/:namespace/pod/:podname/log", async (req, res) => {
const namespace = req.params.namespace;
const podName = req.params.podname;
try {
const logsResponse = await k8sCore.readNamespacedPodLog({namespace: namespace, name: podName});
res.json({log: logsResponse});
} catch (error) {
console.error('Error fetching logs:', error);
const errorMessage = (error as Error).message;
res.status(500).json({error: errorMessage});
}
})

router.get("/namespace/:namespace/services", async (req, res) => {
const namespace = req.params.namespace;
try {
const servicesResponse = await k8sCore.listNamespacedService({namespace: namespace});
res.json(servicesResponse.items);
} catch (error) {
console.error('Error listing services:', error);
const errorMessage = (error as Error).message;
res.status(500).json({error: errorMessage});
}
})

router.get("/namespace/:namespace/ingresses", async (req, res) => {
const namespace = req.params.namespace;
try {
const ingressesResponse = await k8sNetApi.listNamespacedIngress({namespace: namespace});
res.json(ingressesResponse.items);
} catch (error) {
console.error('Error listing ingresses:', error);
const errorMessage = (error as Error).message;
res.status(500).json({error: errorMessage});
}
})

router.post("/namespace/:namespace/delete", async (req, res) => {
const namespace = req.params.namespace;
try {
await k8sCore.deleteNamespace({name: namespace});
res.json({message: `Namespace ${namespace} deleted successfully`});
} catch (error) {
console.error('Error deleting namespace:', error);
const errorMessage = (error as Error).message;
res.status(500).json({error: errorMessage});
}
})

export default router;
Loading

0 comments on commit a88730a

Please sign in to comment.