Upload 24 files
Browse files- app.py +15 -60
- project.zip +3 -0
- templates/dashboard.html +22 -23
app.py
CHANGED
|
@@ -1,9 +1,7 @@
|
|
| 1 |
-
from fastapi import FastAPI
|
| 2 |
-
from fastapi.responses import HTMLResponse
|
| 3 |
-
from fastapi.templating import Jinja2Templates
|
| 4 |
import docker
|
| 5 |
import dotenv
|
| 6 |
-
from routers.deploy import router as deploy_router
|
| 7 |
from routers.controls import router as controls_router
|
| 8 |
from routers.logs import router as logs_router
|
| 9 |
|
|
@@ -11,67 +9,24 @@ from routers.logs import router as logs_router
|
|
| 11 |
dotenv.load_dotenv()
|
| 12 |
|
| 13 |
app = FastAPI()
|
| 14 |
-
|
| 15 |
-
# --- Templating ---
|
| 16 |
-
templates = Jinja2Templates(directory="templates")
|
| 17 |
-
|
| 18 |
-
# --- Routers ---
|
| 19 |
app.include_router(controls_router, prefix="/controls")
|
| 20 |
app.include_router(logs_router, prefix="/logs")
|
| 21 |
app.include_router(deploy_router, prefix="/deploy")
|
| 22 |
|
| 23 |
-
# --- Docker Client ---
|
| 24 |
client = docker.from_env()
|
| 25 |
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
container_name = details.get("container_name", "N/A")
|
| 40 |
-
public_url = details.get("public_url", "#")
|
| 41 |
-
local_url = "#"
|
| 42 |
-
|
| 43 |
-
if container_name != "N/A":
|
| 44 |
-
try:
|
| 45 |
-
container = client.containers.get(container_name)
|
| 46 |
-
port_bindings = client.api.inspect_container(container.id)['NetworkSettings']['Ports']
|
| 47 |
-
if '8080/tcp' in port_bindings and port_bindings['8080/tcp'] is not None:
|
| 48 |
-
host_port = port_bindings['8080/tcp'][0]['HostPort']
|
| 49 |
-
# Get the local IP address of the machine
|
| 50 |
-
import socket
|
| 51 |
-
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
| 52 |
-
try:
|
| 53 |
-
# Doesn't matter if the host is reachable
|
| 54 |
-
s.connect(('10.255.255.255', 1))
|
| 55 |
-
host_ip = s.getsockname()[0]
|
| 56 |
-
except Exception:
|
| 57 |
-
host_ip = '127.0.0.1' # Fallback to localhost
|
| 58 |
-
finally:
|
| 59 |
-
s.close()
|
| 60 |
-
local_url = f"http://{host_ip}:{host_port}"
|
| 61 |
-
except docker.errors.NotFound:
|
| 62 |
-
print(f"Container {container_name} not found for project {project_id}.")
|
| 63 |
-
except Exception as e:
|
| 64 |
-
print(f"Error getting local URL for container {container_name}: {e}")
|
| 65 |
-
|
| 66 |
-
projects_list.append({
|
| 67 |
-
"id": project_id,
|
| 68 |
-
"name": details.get("app_name", "N/A"),
|
| 69 |
-
"status": details.get("status", "Unknown"),
|
| 70 |
-
"public_url": public_url,
|
| 71 |
-
"local_url": local_url,
|
| 72 |
-
"container_name": container_name
|
| 73 |
-
})
|
| 74 |
-
|
| 75 |
-
return projects_list
|
| 76 |
|
| 77 |
|
|
|
|
| 1 |
+
from fastapi import FastAPI
|
|
|
|
|
|
|
| 2 |
import docker
|
| 3 |
import dotenv
|
| 4 |
+
from routers.deploy import router as deploy_router
|
| 5 |
from routers.controls import router as controls_router
|
| 6 |
from routers.logs import router as logs_router
|
| 7 |
|
|
|
|
| 9 |
dotenv.load_dotenv()
|
| 10 |
|
| 11 |
app = FastAPI()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
app.include_router(controls_router, prefix="/controls")
|
| 13 |
app.include_router(logs_router, prefix="/logs")
|
| 14 |
app.include_router(deploy_router, prefix="/deploy")
|
| 15 |
|
|
|
|
| 16 |
client = docker.from_env()
|
| 17 |
|
| 18 |
+
@app.get("/")
|
| 19 |
+
def dashboard():
|
| 20 |
+
containers = client.containers.list(all=True)
|
| 21 |
+
container_list = [
|
| 22 |
+
{
|
| 23 |
+
"id": container.id,
|
| 24 |
+
"name": container.name,
|
| 25 |
+
"status": container.status,
|
| 26 |
+
"image": container.image.tags
|
| 27 |
+
}
|
| 28 |
+
for container in containers
|
| 29 |
+
]
|
| 30 |
+
return {"containers": container_list}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
|
| 32 |
|
project.zip
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b5470cebe77d2a9c10b64850108e237040fac72c4519aa8a28e54bfc24fc64d6
|
| 3 |
+
size 2498
|
templates/dashboard.html
CHANGED
|
@@ -49,54 +49,53 @@
|
|
| 49 |
card.innerHTML = `
|
| 50 |
<h3>${proj.name}</h3>
|
| 51 |
<p>Status: <b>${proj.status}</b></p>
|
| 52 |
-
<p>
|
| 53 |
-
<p>Local URL: <a href="${proj.local_url}" target="_blank">${proj.local_url}</a></p>
|
| 54 |
<div class="buttons">
|
| 55 |
-
<button onclick="stopProject('${proj.
|
| 56 |
-
<button onclick="startProject('${proj.
|
| 57 |
-
<button onclick="pauseProject('${proj.
|
| 58 |
-
<button onclick="toggleLogs('${proj.
|
| 59 |
</div>
|
| 60 |
-
<pre id="log-${proj.
|
| 61 |
`;
|
| 62 |
|
| 63 |
container.appendChild(card);
|
| 64 |
});
|
| 65 |
}
|
| 66 |
|
| 67 |
-
async function stopProject(
|
| 68 |
-
await fetch(`/
|
| 69 |
fetchProjects();
|
| 70 |
}
|
| 71 |
|
| 72 |
-
async function startProject(
|
| 73 |
-
|
| 74 |
-
fetchProjects();
|
| 75 |
}
|
| 76 |
|
| 77 |
-
async function pauseProject(
|
| 78 |
-
|
| 79 |
-
fetchProjects();
|
| 80 |
}
|
| 81 |
|
| 82 |
-
function toggleLogs(
|
| 83 |
-
const pre = document.getElementById(`log-${
|
| 84 |
if (pre.style.display === 'none') {
|
| 85 |
pre.style.display = 'block';
|
| 86 |
-
|
| 87 |
} else {
|
| 88 |
pre.style.display = 'none';
|
| 89 |
}
|
| 90 |
}
|
| 91 |
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
target.
|
|
|
|
|
|
|
|
|
|
| 96 |
}
|
| 97 |
|
| 98 |
fetchProjects();
|
| 99 |
-
setInterval(fetchProjects, 5000); // Refresh every 5 seconds
|
| 100 |
</script>
|
| 101 |
</body>
|
| 102 |
</html>
|
|
|
|
| 49 |
card.innerHTML = `
|
| 50 |
<h3>${proj.name}</h3>
|
| 51 |
<p>Status: <b>${proj.status}</b></p>
|
| 52 |
+
<p>URL: <a href="${proj.url}" target="_blank">${proj.url}</a></p>
|
|
|
|
| 53 |
<div class="buttons">
|
| 54 |
+
<button onclick="stopProject('${proj.name}')">馃洃 Stop</button>
|
| 55 |
+
<button onclick="startProject('${proj.name}')">鈻讹笍 Start</button>
|
| 56 |
+
<button onclick="pauseProject('${proj.name}')">鈴革笍 Pause</button>
|
| 57 |
+
<button onclick="toggleLogs('${proj.name}')">馃摐 View Logs</button>
|
| 58 |
</div>
|
| 59 |
+
<pre id="log-${proj.name}" style="display:none"></pre>
|
| 60 |
`;
|
| 61 |
|
| 62 |
container.appendChild(card);
|
| 63 |
});
|
| 64 |
}
|
| 65 |
|
| 66 |
+
async function stopProject(name) {
|
| 67 |
+
await fetch(`/stop/${name}`, { method: 'POST' });
|
| 68 |
fetchProjects();
|
| 69 |
}
|
| 70 |
|
| 71 |
+
async function startProject(name) {
|
| 72 |
+
alert('Start functionality is not implemented via FastAPI yet.');
|
|
|
|
| 73 |
}
|
| 74 |
|
| 75 |
+
async function pauseProject(name) {
|
| 76 |
+
alert('Pause functionality is not implemented via FastAPI yet.');
|
|
|
|
| 77 |
}
|
| 78 |
|
| 79 |
+
function toggleLogs(name) {
|
| 80 |
+
const pre = document.getElementById(`log-${name}`);
|
| 81 |
if (pre.style.display === 'none') {
|
| 82 |
pre.style.display = 'block';
|
| 83 |
+
streamLogs(name, pre);
|
| 84 |
} else {
|
| 85 |
pre.style.display = 'none';
|
| 86 |
}
|
| 87 |
}
|
| 88 |
|
| 89 |
+
function streamLogs(name, target) {
|
| 90 |
+
const evtSrc = new EventSource(`/logs/${name}`);
|
| 91 |
+
evtSrc.onmessage = function (event) {
|
| 92 |
+
target.textContent += event.data + "\n";
|
| 93 |
+
target.scrollTop = target.scrollHeight;
|
| 94 |
+
};
|
| 95 |
+
evtSrc.onerror = () => evtSrc.close();
|
| 96 |
}
|
| 97 |
|
| 98 |
fetchProjects();
|
|
|
|
| 99 |
</script>
|
| 100 |
</body>
|
| 101 |
</html>
|