mirror of
https://github.com/Rainyy21/k3s-health-dashboard.git
synced 2026-10-10 23:50:20 -04:00
100 lines
3.2 KiB
Python
100 lines
3.2 KiB
Python
import time
|
|
import streamlit as st
|
|
from app import cfg
|
|
from app.cache import (
|
|
clients,
|
|
cached_nodes,
|
|
cached_pods,
|
|
cached_deployments,
|
|
cached_namespaces,
|
|
cached_node_metrics,
|
|
clear,
|
|
)
|
|
|
|
st.set_page_config(page_title=cfg.page_title, page_icon=cfg.page_icon, layout="wide")
|
|
|
|
clients()
|
|
|
|
with st.sidebar:
|
|
st.title("☸️ k3s Dashboard")
|
|
|
|
auto_refresh = st.toggle("Auto-refresh (15s)", value=False)
|
|
|
|
if st.button("🔄 Refresh now"):
|
|
clear()
|
|
st.rerun()
|
|
|
|
namespaces = ["all"] + cached_namespaces()
|
|
sel_ns = st.selectbox("Namespace", namespaces)
|
|
|
|
view = st.radio("View", ["Overview", "Nodes", "Pods", "Deployments"])
|
|
|
|
|
|
# Auto-refresh: sleep only the time remaining since the last refresh,
|
|
# not the full TTL on every rerun (which would freeze the UI on sidebar clicks).
|
|
if auto_refresh:
|
|
now = time.time()
|
|
if "last_refresh" not in st.session_state:
|
|
st.session_state.last_refresh = now
|
|
elapsed = now - st.session_state.last_refresh
|
|
remaining = cfg.cache_ttl - elapsed
|
|
if remaining <= 0:
|
|
clear()
|
|
st.session_state.last_refresh = time.time()
|
|
st.rerun()
|
|
else:
|
|
time.sleep(remaining)
|
|
st.rerun()
|
|
|
|
|
|
# ── Views ──────────────────────────────────────────────────────────────────────
|
|
|
|
if view == "Overview":
|
|
nodes = cached_nodes()
|
|
pods = cached_pods(sel_ns)
|
|
deployments = cached_deployments(sel_ns)
|
|
metrics = cached_node_metrics()
|
|
|
|
ready_nodes = sum(1 for n in nodes if n["ready"])
|
|
ready_pods = sum(1 for p in pods if p["ready"])
|
|
ready_deps = sum(1 for d in deployments if d["available"] >= d["desired"] > 0)
|
|
|
|
c1, c2, c3 = st.columns(3)
|
|
c1.metric("Nodes", f"{ready_nodes}/{len(nodes)} ready")
|
|
c2.metric("Pods", f"{ready_pods}/{len(pods)} ready")
|
|
c3.metric("Deployments", f"{ready_deps}/{len(deployments)} ready")
|
|
|
|
st.divider()
|
|
st.subheader("Nodes")
|
|
st.dataframe(nodes, use_container_width=True)
|
|
|
|
st.subheader("Pods")
|
|
st.dataframe(pods, use_container_width=True)
|
|
|
|
elif view == "Nodes":
|
|
nodes = cached_nodes()
|
|
metrics = cached_node_metrics()
|
|
|
|
st.subheader("Nodes")
|
|
for node in nodes:
|
|
m = metrics.get(node["name"], {})
|
|
with st.expander(f"{'✅' if node['ready'] else '❌'} {node['name']} — {node['roles']}"):
|
|
col1, col2, col3 = st.columns(3)
|
|
col1.metric("CPU capacity", f"{node['cpu_cap']} cores")
|
|
col2.metric("Memory capacity", f"{node['mem_cap_mi']:.0f} Mi")
|
|
col3.metric("Age", node["age"])
|
|
if m:
|
|
col1.metric("CPU usage", m["cpu_usage"])
|
|
col2.metric("Memory usage", m["memory_usage"])
|
|
st.caption(f"OS: {node['os']} Kubelet: {node['kubelet_version']}")
|
|
|
|
elif view == "Pods":
|
|
pods = cached_pods(sel_ns)
|
|
st.subheader(f"Pods — {sel_ns}")
|
|
st.dataframe(pods, use_container_width=True)
|
|
|
|
elif view == "Deployments":
|
|
deployments = cached_deployments(sel_ns)
|
|
st.subheader(f"Deployments — {sel_ns}")
|
|
st.dataframe(deployments, use_container_width=True)
|