const http = require('http'); const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); const PORT = 5000; const HTML_FILE = path.join(__dirname, 'Krates.dc.html'); const SUPPORT_FILE = path.join(__dirname, 'support.js'); const MIME_TYPES = { '.html': 'text/html', '.js': 'application/javascript', '.css': 'text/css', '.json': 'application/json', '.svg': 'image/svg+xml', '.png': 'image/png', '.jpg': 'image/jpeg', '.ico': 'image/x-icon', '.wasm': 'application/wasm' }; function getMimeType(filePath) { const ext = path.extname(filePath).toLowerCase(); return MIME_TYPES[ext] || 'application/octet-stream'; } async function fetchClusterData() { try { const namespaces = JSON.parse(execSync('kubectl get namespaces -o json').toString()); const nodes = JSON.parse(execSync('kubectl get nodes -o json').toString()); const pods = JSON.parse(execSync('kubectl get pods --all-namespaces -o json').toString()); return { namespaces: namespaces.items.map(ns => ({ name: ns.metadata.name, status: ns.status.phase, age: ns.metadata.creationTimestamp })), nodes: nodes.items.map(node => ({ name: node.metadata.name, status: node.status.conditions.find(c => c.type === 'Ready').status, role: Object.keys(node.metadata.labels || {}).filter(k => k.includes('node-role') || k === 'control-plane').join(', ') || 'worker', version: node.status.nodeInfo.kubeletVersion })), podCount: pods.items.length, podsByNamespace: {} }; } catch (error) { console.error('Error fetching cluster data:', error.message); return null; } } function createServer() { const server = http.createServer(async (req, res) => { const url = new URL(req.url, `http://${req.headers.host}`); const filePath = url.pathname === '/' ? HTML_FILE : path.join(__dirname, url.pathname); if (url.pathname === '/health') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ status: 'ok', cluster: 'covert-gpt-cluster' })); return; } if (url.pathname === '/api/cluster') { const data = await fetchClusterData(); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(data || { error: 'Failed to fetch cluster data' })); return; } if (url.pathname === '/api/pods') { try { const { execSync } = require('child_process'); const pods = JSON.parse(execSync('kubectl get pods --all-namespaces -o json', { maxBuffer: 1024 * 1024 * 10 }).toString()); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(pods)); } catch (error) { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: error.message })); } return; } if (url.pathname === '/api/namespaces') { try { const namespaces = JSON.parse(execSync('kubectl get namespaces -o json').toString()); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(namespaces)); } catch (error) { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: error.message })); } return; } if (url.pathname === '/api/nodes') { try { const nodes = JSON.parse(execSync('kubectl get nodes -o json').toString()); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(nodes)); } catch (error) { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: error.message })); } return; } if (url.pathname === '/api/pod/logs' && req.method === 'POST') { let body = ''; req.on('data', chunk => { body += chunk; }); req.on('end', () => { try { const { namespace, pod, container } = JSON.parse(body); let cmd = `kubectl logs ${pod} -n ${namespace}`; if (container) cmd += ` -c ${container}`; const logs = execSync(cmd).toString(); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ logs })); } catch (error) { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: error.message })); } }); return; } if (!filePath.startsWith(__dirname)) { res.writeHead(404); res.end('Not found'); return; } if (!fs.existsSync(filePath)) { res.writeHead(404); res.end('Not found'); return; } const mimeType = getMimeType(filePath); const content = fs.readFileSync(filePath); res.writeHead(200, { 'Content-Type': mimeType }); res.end(content); }); return server; } async function start() { console.log('Starting Krates server...'); const server = createServer(); server.listen(PORT, () => { console.log(`Krates server running at http://localhost:${PORT}`); console.log(`Health check: http://localhost:${PORT}/health`); console.log(`Cluster API: http://localhost:${PORT}/api/cluster`); }); server.on('error', (error) => { console.error(`Server error: ${error.message}`); process.exit(1); }); } start();