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>
|