Infra API
This commit is contained in:
parent
75357d31a2
commit
f70bcb53f8
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1 +1,2 @@
|
|||
.env
|
||||
.env
|
||||
node_modules
|
||||
5
infra-api/Dockerfile
Normal file
5
infra-api/Dockerfile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
FROM node:18-alpine
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN npm install
|
||||
CMD ["node", "server.js"]
|
||||
18
infra-api/docker-compose.yml
Normal file
18
infra-api/docker-compose.yml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
version: '3.8'
|
||||
|
||||
services:
|
||||
infra-api:
|
||||
image: node:18
|
||||
container_name: infra-api
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- ./:/app
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
command: >
|
||||
sh -c "npm install && node server.js"
|
||||
ports:
|
||||
- "8686:8686"
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
network_mode: ${USE_HOST_NETWORK}
|
||||
0
infra-api/output/generateNginx.js
Normal file
0
infra-api/output/generateNginx.js
Normal file
0
infra-api/output/generatePihole.js
Normal file
0
infra-api/output/generatePihole.js
Normal file
1444
infra-api/package-lock.json
generated
Normal file
1444
infra-api/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
6
infra-api/package.json
Normal file
6
infra-api/package.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"dockerode": "^4.0.6",
|
||||
"express": "^5.1.0"
|
||||
}
|
||||
}
|
||||
53
infra-api/routes/domains.js
Normal file
53
infra-api/routes/domains.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { getContainerData } = require('../utils/dockerInspector');
|
||||
const os = require('os');
|
||||
|
||||
router.get('/', async (req, res) => {
|
||||
try {
|
||||
const containers = await getContainerData();
|
||||
const hostInterfaces = os.networkInterfaces();
|
||||
const ip =
|
||||
hostInterfaces.en0?.find(i => i.family === 'IPv4')?.address ||
|
||||
hostInterfaces.eth0?.find(i => i.family === 'IPv4')?.address ||
|
||||
'127.0.0.1';
|
||||
|
||||
const rows = containers
|
||||
.map(c => {
|
||||
const [host, container] = c.name.split('-', 2);
|
||||
if (!host || !container) return null;
|
||||
|
||||
const safeContainer = container.replace(/_/g, '');
|
||||
const safeHost = host.replace(/_/g, '');
|
||||
const hasPorts = c.ports && c.ports.length > 0;
|
||||
const url = hasPorts ? `${ip}:${c.ports[0]}` : null;
|
||||
const domain = `${safeContainer}.${safeHost}.bray.io`;
|
||||
|
||||
if (!url) return null;
|
||||
|
||||
return {
|
||||
name: safeContainer,
|
||||
url,
|
||||
domain,
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
// Create a pretty text table
|
||||
const header = `NAME | URL | DOMAIN`;
|
||||
const divider = `--------------------|------------------------|-----------------------------`;
|
||||
const lines = rows.map(row =>
|
||||
`${row.name.padEnd(20)}| ${row.url.padEnd(24)}| ${row.domain}`
|
||||
);
|
||||
|
||||
const output = [header, divider, ...lines].join('\n');
|
||||
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
res.send(output);
|
||||
} catch (err) {
|
||||
console.error('Error building domain list:', err);
|
||||
res.status(500).send('Failed to generate domain mappings');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
27
infra-api/server.js
Normal file
27
infra-api/server.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
const express = require('express');
|
||||
const os = require('os');
|
||||
const { getContainerData } = require('./utils/dockerInspector');
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 8686;
|
||||
const hostname = os.hostname().toLowerCase(); // used in domain mapping
|
||||
|
||||
// Endpoint to list all containers and their info
|
||||
app.get('/containers', async (req, res) => {
|
||||
try {
|
||||
const containers = await getContainerData();
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.send(JSON.stringify(containers, null, 2)); // Pretty print JSON
|
||||
} catch (err) {
|
||||
console.error('Error fetching containers:', err);
|
||||
res.status(500).send('Internal Server Error');
|
||||
}
|
||||
});
|
||||
|
||||
const domainRoutes = require('./routes/domains');
|
||||
app.use('/domains', domainRoutes);
|
||||
|
||||
// Start server
|
||||
app.listen(8686, '0.0.0.0', () => {
|
||||
console.log('Infra API listening at http://localhost:8686');
|
||||
});
|
||||
69
infra-api/utils/dockerInspector.js
Normal file
69
infra-api/utils/dockerInspector.js
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
const Docker = require('dockerode');
|
||||
const os = require('os');
|
||||
|
||||
const docker = new Docker();
|
||||
|
||||
// Helper to detect the host IP (e.g. 192.168.x.x)
|
||||
function getHostIP() {
|
||||
const interfaces = os.networkInterfaces();
|
||||
for (const iface of Object.values(interfaces)) {
|
||||
for (const net of iface) {
|
||||
if (net.family === 'IPv4' && !net.internal && net.address.startsWith('192.')) {
|
||||
return net.address;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 'localhost'; // Fallback
|
||||
}
|
||||
|
||||
async function getContainerData() {
|
||||
const containers = await docker.listContainers({ all: true });
|
||||
const hostname = os.hostname();
|
||||
const hostIp = getHostIP();
|
||||
|
||||
const output = [];
|
||||
|
||||
for (const containerInfo of containers) {
|
||||
const container = docker.getContainer(containerInfo.Id);
|
||||
const inspect = await container.inspect();
|
||||
|
||||
const rawName = inspect.Name || containerInfo.Names?.[0] || '';
|
||||
const name = rawName.replace(/^\//, '');
|
||||
|
||||
const networks = inspect.NetworkSettings.Networks || {};
|
||||
let staticIP = null;
|
||||
|
||||
// Try to find a meaningful internal Docker-assigned static IP
|
||||
for (const netName in networks) {
|
||||
const ip = networks[netName].IPAddress;
|
||||
if (ip && (ip.startsWith('192.') || ip.startsWith('10.'))) {
|
||||
staticIP = ip;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const rawPorts = Object.values(inspect.NetworkSettings.Ports || {})
|
||||
.flat()
|
||||
.filter(Boolean);
|
||||
const ports = rawPorts.map(p => p.HostPort);
|
||||
|
||||
// Prefer static IP if available, fallback to host IP
|
||||
let url = '(none)';
|
||||
if (ports.length > 0) {
|
||||
const accessIP = staticIP || hostIp;
|
||||
url = `http://${accessIP}:${ports[0]}`;
|
||||
}
|
||||
|
||||
output.push({
|
||||
name,
|
||||
ip: staticIP || 'N/A',
|
||||
ports,
|
||||
hostname,
|
||||
url,
|
||||
});
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
module.exports = { getContainerData };
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
positions:
|
||||
/var/log/acroUpdaterTools.log: "16567"
|
||||
/var/log/alf.log: "0"
|
||||
/var/log/fsck_apfs.log: "23880"
|
||||
/var/log/fsck_apfs_error.log: "676"
|
||||
/var/log/fsck_hfs.log: "4044"
|
||||
/var/log/install.log: "3800109"
|
||||
/var/log/install.log: "3856377"
|
||||
/var/log/shutdown_monitor.log: "1971"
|
||||
/var/log/system.log: "6132"
|
||||
/var/log/wifi.log: "1107090"
|
||||
/var/log/system.log: "6579"
|
||||
/var/log/wifi.log: "1164834"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
positions:
|
||||
/var/log/acroUpdaterTools.log: "16567"
|
||||
/var/log/alf.log: "0"
|
||||
/var/log/fsck_apfs.log: "23880"
|
||||
/var/log/fsck_apfs_error.log: "676"
|
||||
/var/log/fsck_hfs.log: "4044"
|
||||
/var/log/install.log: "3800109"
|
||||
/var/log/install.log: "3856377"
|
||||
/var/log/shutdown_monitor.log: "1971"
|
||||
/var/log/system.log: "6132"
|
||||
/var/log/wifi.log: "1107090"
|
||||
/var/log/system.log: "6579"
|
||||
/var/log/wifi.log: "1164834"
|
||||
|
|
|
|||
Loading…
Reference in a new issue