Skip to content

Commit

Permalink
add node status stream
Browse files Browse the repository at this point in the history
  • Loading branch information
tobru committed Aug 28, 2024
1 parent 3d59021 commit c996475
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 4 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,19 @@ The web application is a Flask application and uses [htmx](https://htmx.org/) wi
By issuing an authenticated `GET` request to the `/chaos` endpoint, a random Pod in the configured namespace gets deleted.

On startup, an autostart command in the Wayfire configuration tries to connect to the Podstatus web application.
Once this is successfull, a full-screen Chromium kiosk session is started, displaying the Podstatus web application.
Once this is successful, a full-screen Chromium kiosk session is started, displaying the Podstatus web application.

During development, the app can be started with (make sure to install dependencies with Poetry first):

```
FLASK_APP="podstatus/app.py" PYTHONPATH="podstatus" flask run --reload
```

And in production, the idea is that it runs with gunicorn:

```
GUNICORN_WORKERS=1 PYTHONPATH=./podstatus GUNICORN_BIND='0.0.0.0:8000' gunicorn -k gevent podstatus.app:app
```

#### The Red Button

Expand Down
27 changes: 26 additions & 1 deletion podstatus/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def chaos():
logging.error(f"Failed to list pods in namespace {namespace} because {e}")
return jsonify({"message": "Failed to list pods"}), 500

@app.route("/stream")
@app.route("/stream_pods")
def stream():
def watch_pods():
w = watch.Watch()
Expand All @@ -126,6 +126,31 @@ def watch_pods():

return Response(watch_pods(), content_type="text/event-stream")

@app.route("/stream_nodes")
def stream_nodes():
def watch_nodes():
w = watch.Watch()
try:
for event in w.stream(v1.list_node, timeout_seconds=0):
node = event["object"]
node_name = node.metadata.name
node_status = "Unknown"

for condition in node.status.conditions:
if condition.type == "Ready":
node_status = (
"KubeletReady"
if condition.status == "True"
else "NotReady"
)
break

yield f'data: {{"name": "{node_name}", "status": "{node_status}"}}\n\n'
except Exception as e:
logging.error(f"Error watching nodes: {e}")

return Response(watch_nodes(), content_type="text/event-stream")

@app.route("/shutdown", methods=["POST"])
def shutdown():
handle_shutdown(signal.SIGTERM, None)
Expand Down
39 changes: 37 additions & 2 deletions podstatus/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@ <h1>Status of Pods</h1>
Loading...
</div>

<h1>Status of Nodes</h1>
<div id="node-status">
Loading...
</div>

<script>
document.addEventListener('DOMContentLoaded', function () {
// Pod status stream
setTimeout(function () {
const eventSource = new EventSource("/stream");
const eventSource = new EventSource("/stream_pods");
let firstEvent = true;

eventSource.onmessage = function (event) {
Expand Down Expand Up @@ -37,10 +43,39 @@ <h1>Status of Pods</h1>
podStatusValue === 'Pending' ? '#f39c12' : '#e74c3c';
};
}, 1000); // Delay of 1 second before initializing SSE connection

// Node status stream
setTimeout(function () {
const eventSourceNodes = new EventSource("/stream_nodes");
let firstEventNodes = true;

eventSourceNodes.onmessage = function (event) {
const data = JSON.parse(event.data.replaceAll("'", '"'));
const nodeName = data.name;
const nodeStatusValue = data.status;

if (firstEventNodes) {
document.getElementById('node-status').innerHTML = '';
firstEventNodes = false;
}

let nodeElement = document.getElementById(nodeName);
if (!nodeElement) {
nodeElement = document.createElement('div');
nodeElement.id = nodeName;
nodeElement.className = 'node';
document.getElementById('node-status').appendChild(nodeElement);
}

nodeElement.innerHTML = `<strong>${nodeName}</strong>: ${nodeStatusValue}`;
nodeElement.style.backgroundColor = nodeStatusValue === 'KubeletReady' ? '#00bc8c' : '#e74c3c';
};
}, 1000); // Delay of 1 second before initializing SSE connection
});
</script>
<style>
.pod {
.pod,
.node {
padding: 10px;
margin: 5px;
border: 1px solid #ccc;
Expand Down

0 comments on commit c996475

Please sign in to comment.