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.pyCode 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 statusCode language: Bash (bash)