feat(system): Docker container management via Unix socket
This commit is contained in:
parent
89771a2380
commit
910a906600
1 changed files with 101 additions and 0 deletions
101
services/mam-api/src/routes/system.js
Normal file
101
services/mam-api/src/routes/system.js
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
import express from 'express';
|
||||
import http from 'node:http';
|
||||
import { requireAuth } from '../middleware/auth.js';
|
||||
|
||||
const router = express.Router();
|
||||
router.use(requireAuth);
|
||||
|
||||
const DOCKER_SOCKET = '/var/run/docker.sock';
|
||||
const COMPOSE_PROJECT = (process.env.DOCKER_NETWORK || 'wild-dragon_wild-dragon').split('_')[0];
|
||||
|
||||
function dockerGet(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = http.request(
|
||||
{ socketPath: DOCKER_SOCKET, path, method: 'GET' },
|
||||
(res) => {
|
||||
let data = '';
|
||||
res.on('data', chunk => { data += chunk; });
|
||||
res.on('end', () => {
|
||||
try { resolve({ status: res.statusCode, body: JSON.parse(data) }); }
|
||||
catch { resolve({ status: res.statusCode, body: data }); }
|
||||
});
|
||||
}
|
||||
);
|
||||
req.on('error', reject);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
function dockerPost(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = http.request(
|
||||
{ socketPath: DOCKER_SOCKET, path, method: 'POST', headers: { 'Content-Length': '0' } },
|
||||
(res) => {
|
||||
res.resume();
|
||||
res.on('end', () => resolve({ status: res.statusCode }));
|
||||
}
|
||||
);
|
||||
req.on('error', reject);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// GET /containers – list containers for this compose project
|
||||
router.get('/containers', async (req, res, next) => {
|
||||
try {
|
||||
const r = await dockerGet('/containers/json?all=1');
|
||||
if (r.status !== 200) return res.status(502).json({ error: 'Docker API error', code: r.status });
|
||||
|
||||
const containers = r.body
|
||||
.filter(c => {
|
||||
const labels = c.Labels || {};
|
||||
// Match by compose project label; fall back to network name
|
||||
if (labels['com.docker.compose.project'] === COMPOSE_PROJECT) return true;
|
||||
return Object.keys(c.NetworkSettings?.Networks || {}).some(n => n.includes(COMPOSE_PROJECT));
|
||||
})
|
||||
.map(c => ({
|
||||
id: c.Id.slice(0, 12),
|
||||
name: (c.Names[0] || '').replace(/^\//, ''),
|
||||
image: c.Image,
|
||||
state: c.State,
|
||||
status: c.Status,
|
||||
created: c.Created,
|
||||
service: (c.Labels || {})['com.docker.compose.service'] || '',
|
||||
ports: (c.Ports || [])
|
||||
.filter(p => p.PublicPort)
|
||||
.map(p => `${p.PublicPort}:${p.PrivatePort}/${p.Type}`)
|
||||
.join(', '),
|
||||
}));
|
||||
|
||||
res.json(containers);
|
||||
} catch (err) { next(err); }
|
||||
});
|
||||
|
||||
// POST /containers/:id/restart
|
||||
router.post('/containers/:id/restart', async (req, res, next) => {
|
||||
try {
|
||||
const r = await dockerPost(`/containers/${req.params.id}/restart`);
|
||||
if (r.status !== 204) return res.status(502).json({ error: 'Failed to restart', code: r.status });
|
||||
res.json({ ok: true });
|
||||
} catch (err) { next(err); }
|
||||
});
|
||||
|
||||
// POST /containers/:id/stop
|
||||
router.post('/containers/:id/stop', async (req, res, next) => {
|
||||
try {
|
||||
const r = await dockerPost(`/containers/${req.params.id}/stop`);
|
||||
if (r.status !== 204 && r.status !== 304) return res.status(502).json({ error: 'Failed to stop', code: r.status });
|
||||
res.json({ ok: true });
|
||||
} catch (err) { next(err); }
|
||||
});
|
||||
|
||||
// POST /containers/:id/start
|
||||
router.post('/containers/:id/start', async (req, res, next) => {
|
||||
try {
|
||||
const r = await dockerPost(`/containers/${req.params.id}/start`);
|
||||
if (r.status !== 204 && r.status !== 304) return res.status(502).json({ error: 'Failed to start', code: r.status });
|
||||
res.json({ ok: true });
|
||||
} catch (err) { next(err); }
|
||||
});
|
||||
|
||||
export default router;
|
||||
Loading…
Reference in a new issue