Infra API
This commit is contained in:
parent
75357d31a2
commit
f70bcb53f8
1
.gitignore
vendored
1
.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:
|
positions:
|
||||||
|
/var/log/acroUpdaterTools.log: "16567"
|
||||||
/var/log/alf.log: "0"
|
/var/log/alf.log: "0"
|
||||||
/var/log/fsck_apfs.log: "23880"
|
/var/log/fsck_apfs.log: "23880"
|
||||||
/var/log/fsck_apfs_error.log: "676"
|
/var/log/fsck_apfs_error.log: "676"
|
||||||
/var/log/fsck_hfs.log: "4044"
|
/var/log/fsck_hfs.log: "4044"
|
||||||
/var/log/install.log: "3800109"
|
/var/log/install.log: "3856377"
|
||||||
/var/log/shutdown_monitor.log: "1971"
|
/var/log/shutdown_monitor.log: "1971"
|
||||||
/var/log/system.log: "6132"
|
/var/log/system.log: "6579"
|
||||||
/var/log/wifi.log: "1107090"
|
/var/log/wifi.log: "1164834"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
positions:
|
positions:
|
||||||
|
/var/log/acroUpdaterTools.log: "16567"
|
||||||
/var/log/alf.log: "0"
|
/var/log/alf.log: "0"
|
||||||
/var/log/fsck_apfs.log: "23880"
|
/var/log/fsck_apfs.log: "23880"
|
||||||
/var/log/fsck_apfs_error.log: "676"
|
/var/log/fsck_apfs_error.log: "676"
|
||||||
/var/log/fsck_hfs.log: "4044"
|
/var/log/fsck_hfs.log: "4044"
|
||||||
/var/log/install.log: "3800109"
|
/var/log/install.log: "3856377"
|
||||||
/var/log/shutdown_monitor.log: "1971"
|
/var/log/shutdown_monitor.log: "1971"
|
||||||
/var/log/system.log: "6132"
|
/var/log/system.log: "6579"
|
||||||
/var/log/wifi.log: "1107090"
|
/var/log/wifi.log: "1164834"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue