Merge pull request #391 from eyerrock/list-containers-with-unexposed-ports

list containers with unexposed ports
This commit is contained in:
Toby Chui 2024-11-14 20:06:31 +08:00 committed by GitHub
commit df88084375
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -2,7 +2,7 @@
<html> <html>
<head> <head>
<!-- Notes: This should be open in its original path--> <!-- Notes: This should be open in its original path-->
<meta charset="utf-8"> <meta charset="utf-8" />
<link rel="stylesheet" href="../script/semantic/semantic.min.css" /> <link rel="stylesheet" href="../script/semantic/semantic.min.css" />
<script src="../script/jquery-3.6.0.min.js"></script> <script src="../script/jquery-3.6.0.min.js"></script>
<script src="../script/semantic/semantic.min.js"></script> <script src="../script/semantic/semantic.min.js"></script>
@ -10,6 +10,19 @@
<body> <body>
<br /> <br />
<div class="ui container"> <div class="ui container">
<div class="field">
<div class="ui checkbox">
<input type="checkbox" id="showUnexposed" class="hidden" />
<label for="showUnexposed"
>Show Containers with Unexposed Ports
<br />
<small
>Please make sure Zoraxy and the target container share a
network</small
>
</label>
</div>
</div>
<div class="ui header"> <div class="ui header">
<div class="content"> <div class="content">
List of Docker Containers List of Docker Containers
@ -33,56 +46,70 @@
</div> </div>
<script> <script>
const lines = {}; let lines = {};
const linesAded = {}; let linesAdded = {};
document
.getElementById("showUnexposed")
.addEventListener("change", () => {
console.log("showUnexposed", $("#showUnexposed").is(":checked"));
$("#containersList").html('<div class="ui loader active"></div>');
$("#containersAddedList").empty();
$("#containersAddedListHeader").attr("hidden", true);
lines = {};
linesAdded = {};
getDockerContainers();
});
function getDockerContainers() { function getDockerContainers() {
const hostRequest = $.get("/api/proxy/list?type=host"); const hostRequest = $.get("/api/proxy/list?type=host");
const dockerRequest = $.get("/api/docker/containers"); const dockerRequest = $.get("/api/docker/containers");
// Wait for both requests to complete
Promise.all([hostRequest, dockerRequest]) Promise.all([hostRequest, dockerRequest])
.then(([hostData, dockerData]) => { .then(([hostData, dockerData]) => {
if ( if (!dockerData.error && !hostData.error) {
dockerData.error === undefined &&
hostData.error === undefined
) {
const { containers, network } = dockerData; const { containers, network } = dockerData;
const bridge = network.find(({ Name }) => Name === "bridge");
const { const existingTargets = new Set(
IPAM: { hostData.flatMap(({ ActiveOrigins }) =>
Config: [{ Gateway: gateway }], ActiveOrigins.map(({ OriginIpOrDomain }) => OriginIpOrDomain)
}, )
} = bridge; );
const existedDomains = hostData.reduce((acc, { ActiveOrigins }) => {
return acc.concat(ActiveOrigins.map(({ OriginIpOrDomain }) => OriginIpOrDomain));
}, []);
for (const container of containers) { for (const container of containers) {
const { const Ports = container.Ports;
Ports, const name = container.Names[0].replace(/^\//, "");
Names: [name],
} = container;
for (const portObject of Ports.filter( for (const portObject of Ports) {
({ IP: ip }) => ip === "::" || ip === '0.0.0.0' let port = portObject.PublicPort;
)) { if (!port) {
const { IP: ip, PublicPort: port } = portObject; if (!$("#showUnexposed").is(":checked")) {
continue;
}
port = portObject.PrivatePort;
}
const key = `${name}-${port}`; const key = `${name}-${port}`;
// if port is not exposed, use container's name and let docker handle the routing
// BUT this will only work if the container is on the same network as Zoraxy
const targetAddress = portObject.IP || name;
if ( if (
existedDomains.some((item) => item === `${gateway}:${port}`) && existingTargets.has(`${targetAddress}:${port}`) &&
!linesAded[key] !linesAdded[key]
) { ) {
linesAded[key] = { linesAdded[key] = {
name: name.replace(/^\//, ""), name,
ip: gateway, ip: targetAddress,
port, port,
}; };
} else if (!lines[key]) { } else if (!lines[key]) {
lines[key] = { lines[key] = {
name: name.replace(/^\//, ""), name,
ip: gateway, ip: targetAddress,
port, port,
}; };
} }
@ -92,29 +119,31 @@
for (const [key, line] of Object.entries(lines)) { for (const [key, line] of Object.entries(lines)) {
$("#containersList").append( $("#containersList").append(
`<div class="item"> `<div class="item">
<div class="right floated content"> <div class="right floated content">
<div class="ui button" onclick="addContainerItem('${key}');">Add</div> <div class="ui button" onclick="addContainerItem('${key}');">Add</div>
</div> </div>
<div class="content"> <div class="content">
<div class="header">${line.name}</div> <div class="header">${line.name}</div>
<div class="description"> <div class="description">
${line.ip}:${line.port} ${line.ip}:${line.port}
</div> </div>
</div>` </div>`
); );
} }
for (const [key, line] of Object.entries(linesAded)) {
for (const [key, line] of Object.entries(linesAdded)) {
$("#containersAddedList").append( $("#containersAddedList").append(
`<div class="item"> `<div class="item">
<div class="content"> <div class="content">
<div class="header">${line.name}</div> <div class="header">${line.name}</div>
<div class="description"> <div class="description">
${line.ip}:${line.port} ${line.ip}:${line.port}
</div> </div>
</div>` </div>`
); );
} }
Object.entries(linesAded).length &&
Object.entries(linesAdded).length &&
$("#containersAddedListHeader").removeAttr("hidden"); $("#containersAddedListHeader").removeAttr("hidden");
$("#containersList .loader").removeClass("active"); $("#containersList .loader").removeClass("active");
} else { } else {
@ -122,7 +151,11 @@
`Error loading data: ${dockerData.error || hostData.error}`, `Error loading data: ${dockerData.error || hostData.error}`,
false false
); );
$("#containersList").html(`<div class="ui basic segment"><i class="ui red times icon"></i> ${dockerData.error || hostData.error}</div>`); $("#containersList").html(
`<div class="ui basic segment"><i class="ui red times icon"></i> ${
dockerData.error || hostData.error
}</div>`
);
} }
}) })
.catch((error) => { .catch((error) => {