chipling commited on
Commit
a2ec119
verified
1 Parent(s): 94046ac

Upload 24 files

Browse files
Files changed (3) hide show
  1. app.py +15 -60
  2. project.zip +3 -0
  3. templates/dashboard.html +22 -23
app.py CHANGED
@@ -1,9 +1,7 @@
1
- from fastapi import FastAPI, Request
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, deployed_projects
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
- # --- Endpoints ---
27
- @app.get("/", response_class=HTMLResponse)
28
- async def dashboard(request: Request):
29
- """Serves the main dashboard page."""
30
- return templates.TemplateResponse("dashboard.html", {"request": request})
31
-
32
- @app.get("/projects")
33
- def get_projects():
34
- """Returns a list of all deployed projects with their status and URL."""
35
-
36
- # Create a list of projects from the deployed_projects dictionary
37
- projects_list = []
38
- for project_id, details in deployed_projects.items():
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>Public URL: <a href="${proj.public_url}" target="_blank">${proj.public_url}</a></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.container_name}')">馃洃 Stop</button>
56
- <button onclick="startProject('${proj.container_name}')">鈻讹笍 Start</button>
57
- <button onclick="pauseProject('${proj.container_name}')">鈴革笍 Pause</button>
58
- <button onclick="toggleLogs('${proj.container_name}')">馃摐 View Logs</button>
59
  </div>
60
- <pre id="log-${proj.container_name}" style="display:none"></pre>
61
  `;
62
 
63
  container.appendChild(card);
64
  });
65
  }
66
 
67
- async function stopProject(containerName) {
68
- await fetch(`/controls/stop/${containerName}`);
69
  fetchProjects();
70
  }
71
 
72
- async function startProject(containerName) {
73
- await fetch(`/controls/start/${containerName}`);
74
- fetchProjects();
75
  }
76
 
77
- async function pauseProject(containerName) {
78
- await fetch(`/controls/pause/${containerName}`);
79
- fetchProjects();
80
  }
81
 
82
- function toggleLogs(containerName) {
83
- const pre = document.getElementById(`log-${containerName}`);
84
  if (pre.style.display === 'none') {
85
  pre.style.display = 'block';
86
- fetchLogs(containerName, pre);
87
  } else {
88
  pre.style.display = 'none';
89
  }
90
  }
91
 
92
- async function fetchLogs(containerName, target) {
93
- const res = await fetch(`/logs/fetch/${containerName}`);
94
- const logs = await res.text();
95
- target.innerHTML = logs;
 
 
 
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>