This is a simple web app that provides a dashboard view of users and the GPU resources they are currently utilizing.
Built as a Flask app there are three files that make up the entire project. First, the primary application file contains the following.
from flask import Flask, render_template
import subprocess
import re
from io import StringIO
import csv
import json
import pprint
pp = pprint.PrettyPrinter()
app = Flask(__name__)
def get_jupyter_pods():
pods = []
try:
process = subprocess.run(
['kubectl', 'get', 'pods', '-n', 'jhub'],
stdout=subprocess.PIPE)
pod_info = process.stdout.decode('utf-8')
pod_info_squeeze = re.sub(r' {2,}', ' ', pod_info)
f = StringIO(pod_info_squeeze)
reader = csv.DictReader(f, delimiter=' ')
for row in reader:
if 'jupyter' in row['NAME']:
pods.append(row['NAME'])
except:
return []
return pods
def get_pod_data(name):
try:
process = subprocess.run(
['kubectl', 'get', 'pod', name, '-n', 'jhub', '-o', 'json'],
stdout=subprocess.PIPE)
obj = process.stdout.decode('utf-8')
return json.loads(obj)
except:
return None
def get_pod_user(pod):
for item in pod['spec']['containers'][0]['env']:
if item['name'] == 'JUPYTERHUB_USER':
return item['value']
return None
def get_pod_image(pod):
for item in pod['spec']['containers'][0]['env']:
if item['name'] == 'JUPYTER_IMAGE':
return item['value']
return None
def get_pod_node(pod):
return pod['spec']['nodeName']
def get_pod_gpus(pod):
resource_requests = pod['spec']['containers'][0]['resources']['requests']
if 'nvidia.com/gpu' in resource_requests:
return resource_requests['nvidia.com/gpu']
else:
return None
@app.route('/')
def dashboard():
data = []
pods = get_jupyter_pods()
for pod in pods:
pod_data = get_pod_data(pod)
user = get_pod_user(pod_data)
image = get_pod_image(pod_data)
node = get_pod_node(pod_data)
gpus = get_pod_gpus(pod_data)
data.append({
'user': user,
'image': image,
'node': node,
'gpus': gpus
})
return render_template('dashboard.html', data=data)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
Code language: Python (python)
The second is a simple css style file with the following contents. It should be located in static/style.css
.
h1 {
padding: 20px;
}
table {
border-collapse: collapse;
}
div.table {
padding-left: 20px;
}
td, th {
text-align: left;
padding: 15px 10px 15px 10px;
border: 0px;
border-bottom: 1px solid #ddd;
}
th {
background-color: #444;
color: white;
}
tr:hover {
background-color: #eee;
}
Code language: CSS (css)
The final file is an html template with the following contents. It should be located in templates/dashboard.html
.
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="static/style.css">
</head>
<title>JupyterHub Dashboard</title>
<h1>JupyterHub Dashboard</h1>
<div class="table">
{% if data %}
<table>
<tr>
<th>User</th>
<th>Node</th>
<th>GPUs</th>
<th>Image</th>
</tr>
{% for item in data %}
<tr>
<td>{{ item['user'] }}</td>
<td>{{ item['node'] }}</td>
<td>{{ item['gpus'] }}</td>
<td>{{ item['image'] }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<div>No launched servers</div>
{% endif %}
</div>
</html>
Code language: HTML, XML (xml)
The web app can be run with the following command.
python dashboard-app.py
Code language: CSS (css)
Alternatively, the app can be run automatically on reboot as a service. Create the file /etc/systemd/system/jupyterhub-dashboard.service
with the following contents.
Code language: Bash (bash)[Unit] Description=Web app that displays a simple dashboard describing the utilization of JupyterHub resources. [Service] User=[username] WorkingDirectory=/path/to/app/dir ExecStart=/usr/bin/python3 /path/to/app/dashboard-app.py [Install] WantedBy=multi-user.target
Then run the following commands to enable the service.
sudo systemctl enable jupyterhub-dashboard.service
service jupyterhub-dashboard start
service jupyterhub-dashboard status
Code language: Bash (bash)