summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlejandro Sirgo Rica <asirgo@soleta.eu>2024-07-16 11:41:41 +0200
committerAlejandro Sirgo Rica <asirgo@soleta.eu>2024-07-16 12:55:31 +0200
commit314a173b6cc3125190786e43158b7a60063f33bf (patch)
tree626c3d0e2820d4020e2bf4fb641320a0d5d6827d
parent5af2b3738be739796ae98ce68a3ea9162c7248bf (diff)
ogcp: show cache contents in client details
Show cache contents in client details for a more complete view of the client's state. Move the cache inspector code to its own template for reusability.
-rw-r--r--ogcp/templates/actions/cache.html147
-rw-r--r--ogcp/templates/actions/client_details.html4
-rw-r--r--ogcp/templates/cache_inspector.html152
-rw-r--r--ogcp/views.py81
4 files changed, 211 insertions, 173 deletions
diff --git a/ogcp/templates/actions/cache.html b/ogcp/templates/actions/cache.html
index 46a8699..d64aebe 100644
--- a/ogcp/templates/actions/cache.html
+++ b/ogcp/templates/actions/cache.html
@@ -54,151 +54,8 @@
{{ _('Delete') }}
</button>
</form>
-
-<br>
-
-<div class="card text-center">
- <div class="card-header">
- {{ _('Detailed cache usage') }}
- </div>
- <div class="card-body">
- <label for="cacheSelect">Choose a client:</label>
- <select id="cacheSelect" onchange="onClientSelected()">
- {% for client_ip in ip_list %}
- <option value="{{ client_ip }}">{{ client_ip }}</option>
- {% endfor %}
- </select>
-
- <ul class="list-group list-group-horizontal">
- <li class="list-group-item w-50">
- <canvas id="cacheChart" class="mb-2"></canvas>
- </li>
- <li class="list-group-item w-50">
- <p>{{ _('Images in cache:') }}</p>
- <div id="cacheList"></div>
- </li>
- </ul>
- <ul class="list-group list-group-horizontal">
- <li class="list-group-item w-50">
- {{ _('Disk size') }}
- </li>
- <li class="list-group-item w-50">
- {{ _('used') }} (%)
- </li>
- <li class="list-group-item w-50">
- {{ _('available') }} (%)
- </li>
- </ul>
- <ul class="list-group list-group-horizontal">
- <li id="totalCacheItem" class="list-group-item w-50"></li>
- <li id="usedCacheItem" class="list-group-item w-50"></li>
- <li id="freeCacheItem" class="list-group-item w-50"></li>
- </ul>
- </div>
- </div>
-
-<!-- jQuery -->
-<script src="{{ url_for('static', filename='AdminLTE/plugins/jquery/jquery.min.js') }}"></script>
-<!-- ChartJS -->
-<script src="{{ url_for('static', filename='AdminLTE/plugins/chart.js/Chart.min.js') }}"></script>
-<script>
- var cacheChartConfig = {
- type: 'doughnut',
- data: {
- labels: ['Used', 'Available'],
- datasets: [
- {
- label: 'Disk usage',
- data: [
- 0,
- 1,
- ],
- backgroundColor: [
- 'rgb(255, 99, 132)',
- 'rgb(54, 162, 235)',
- ],
- },
- ],
- },
- options: {
- responsive: true,
- plugins: {
- legend: {
- position: 'top',
- },
- title: {
- display: true,
- text: 'Chart.js Doughnut Chart'
- },
- },
- },
- };
- var cacheChart = new Chart(
- document.getElementById('cacheChart'),
- cacheChartConfig,
- );
-
- var storageData = {{ storage_data|tojson|safe }};
- var imageData = {{ images_data|tojson|safe }};
- var clientImages = {{ client_images|tojson|safe }};
-
- function onClientSelected() {
- var selectElement = document.getElementById("cacheSelect");
- var selectedOption = selectElement.options[selectElement.selectedIndex].text;
- updateChart(selectedOption);
- }
-
- function toGiB(v, decimals) {
- return (v / Math.pow(2, 30)).toFixed(decimals);
- }
-
- function updateChart(ip) {
- var totalCache = toGiB(storageData[ip].total, 3);
- var usedCache = toGiB(storageData[ip].used, 3);
- var freeCache = toGiB(storageData[ip].total - storageData[ip].used, 3)
-
- cacheChart.data.datasets[0].data = [
- usedCache,
- freeCache,
- ]
- cacheChart.update();
-
- var totalCacheItem = document.getElementById("totalCacheItem");
- totalCacheItem.innerHTML = totalCache + " GiB";
-
- var usedCacheItem = document.getElementById("usedCacheItem");
- usedCacheItem.innerHTML = usedCache + " GiB (" + Math.round((usedCache / totalCache) * 100) + "%)";
-
- var freeCacheItem = document.getElementById("freeCacheItem");
- freeCacheItem.innerHTML = freeCache + " GiB (" + Math.round((freeCache / totalCache) * 100) + "%)";
-
- var cacheList = document.getElementById("cacheList");
- cacheList.innerHTML = "";
- clientImages[ip].forEach(function(img) {
- cacheList.innerHTML += imageData[img]["name"] + " (" + (imageData[img]["size"] / Math.pow(2, 20)).toFixed(3) + " MiB)<br>";
- });
- }
-
- updateChart("{{ ip_list[0] }}");
-
- // Update pill data
- $('.badge-pill').each(function(index) {
- for (var ip in storageData) {
- if ($(this).html().includes(ip)) {
- var totalCache = storageData[ip].total;
- var usedCache = storageData[ip].used;
- var freeCache = toGiB(totalCache - usedCache, 1)
- $(this).html($(this).html() + '<br>free: ' + freeCache + ' GiB');
- break;
- }
- }
- });
-</script>
-
-{% else %}
-<div class="card text-center p-3">
- <b>{{ _('Cache is currently empty in the selected client(s)') }}</b>
-</div>
{% endif %}
+{% include 'cache_inspector.html' %}
+
{% endblock %}
diff --git a/ogcp/templates/actions/client_details.html b/ogcp/templates/actions/client_details.html
index 0362d5b..070e4d6 100644
--- a/ogcp/templates/actions/client_details.html
+++ b/ogcp/templates/actions/client_details.html
@@ -9,6 +9,8 @@
{% block nav_client_add %}active{% endblock %}
{% block content %}
+{% set ip_list = [form.ip.data] %}
+
<h2 class="mx-5 subhead-heading">{{_('Client details')}}</h2>
<div class="container mt-5">
@@ -106,4 +108,6 @@
</table>
{% endif %}
+{% include 'cache_inspector.html' %}
+
{% endblock %}
diff --git a/ogcp/templates/cache_inspector.html b/ogcp/templates/cache_inspector.html
new file mode 100644
index 0000000..42dd983
--- /dev/null
+++ b/ogcp/templates/cache_inspector.html
@@ -0,0 +1,152 @@
+{% if storage_data is defined and images_data is defined and client_images is defined and ip_list is defined %}
+
+<br>
+{% if images_data|length > 0 %}
+<div class="card text-center">
+ <div class="card-header">
+ {{ _('Detailed cache usage') }}
+ </div>
+ <div class="card-body">
+ {% if ip_list|length > 1 %}
+ <label for="cacheSelect">Choose a client:</label>
+ <select id="cacheSelect" onchange="onClientSelected()">
+ {% for client_ip in ip_list %}
+ <option value="{{ client_ip }}">{{ client_ip }}</option>
+ {% endfor %}
+ </select>
+ {% endif %}
+
+ <ul class="list-group list-group-horizontal">
+ <li class="list-group-item w-50">
+ <canvas id="cacheChart" class="mb-2"></canvas>
+ </li>
+ <li class="list-group-item w-50">
+ <p>{{ _('Images in cache:') }}</p>
+ <div id="cacheList"></div>
+ </li>
+ </ul>
+ <ul class="list-group list-group-horizontal">
+ <li class="list-group-item w-50">
+ {{ _('Disk size') }}
+ </li>
+ <li class="list-group-item w-50">
+ {{ _('used') }} (%)
+ </li>
+ <li class="list-group-item w-50">
+ {{ _('available') }} (%)
+ </li>
+ </ul>
+ <ul class="list-group list-group-horizontal">
+ <li id="totalCacheItem" class="list-group-item w-50"></li>
+ <li id="usedCacheItem" class="list-group-item w-50"></li>
+ <li id="freeCacheItem" class="list-group-item w-50"></li>
+ </ul>
+ </div>
+</div>
+
+<!-- jQuery -->
+<script src="{{ url_for('static', filename='AdminLTE/plugins/jquery/jquery.min.js') }}"></script>
+<!-- ChartJS -->
+<script src="{{ url_for('static', filename='AdminLTE/plugins/chart.js/Chart.min.js') }}"></script>
+<script>
+ var cacheChartConfig = {
+ type: 'doughnut',
+ data: {
+ labels: ['Used', 'Available'],
+ datasets: [
+ {
+ label: 'Disk usage',
+ data: [
+ 0,
+ 1,
+ ],
+ backgroundColor: [
+ 'rgb(255, 99, 132)',
+ 'rgb(54, 162, 235)',
+ ],
+ },
+ ],
+ },
+ options: {
+ responsive: true,
+ plugins: {
+ legend: {
+ position: 'top',
+ },
+ title: {
+ display: true,
+ text: 'Chart.js Doughnut Chart'
+ },
+ },
+ },
+ };
+ var cacheChart = new Chart(
+ document.getElementById('cacheChart'),
+ cacheChartConfig,
+ );
+
+ var storageData = {{ storage_data|tojson|safe }};
+ var imageData = {{ images_data|tojson|safe }};
+ var clientImages = {{ client_images|tojson|safe }};
+
+ function onClientSelected() {
+ var selectElement = document.getElementById("cacheSelect");
+ var selectedOption = selectElement.options[selectElement.selectedIndex].text;
+ updateChart(selectedOption);
+ }
+
+ function toGiB(v, decimals) {
+ return (v / Math.pow(2, 30)).toFixed(decimals);
+ }
+
+ function updateChart(ip) {
+ var totalCache = toGiB(storageData[ip].total, 3);
+ var usedCache = toGiB(storageData[ip].used, 3);
+ var freeCache = toGiB(storageData[ip].total - storageData[ip].used, 3)
+
+ cacheChart.data.datasets[0].data = [
+ usedCache,
+ freeCache,
+ ]
+ cacheChart.update();
+
+ var totalCacheItem = document.getElementById("totalCacheItem");
+ totalCacheItem.innerHTML = totalCache + " GiB";
+
+ var usedCacheItem = document.getElementById("usedCacheItem");
+ usedCacheItem.innerHTML = usedCache + " GiB (" + Math.round((usedCache / totalCache) * 100) + "%)";
+
+ var freeCacheItem = document.getElementById("freeCacheItem");
+ freeCacheItem.innerHTML = freeCache + " GiB (" + Math.round((freeCache / totalCache) * 100) + "%)";
+
+ var cacheList = document.getElementById("cacheList");
+ cacheList.innerHTML = "";
+ if (clientImages[ip]) {
+ clientImages[ip].forEach(function(img) {
+ cacheList.innerHTML += imageData[img]["name"] + " (" + (imageData[img]["size"] / Math.pow(2, 20)).toFixed(3) + " MiB)<br>";
+ });
+ }
+ }
+
+ updateChart("{{ ip_list[0] }}");
+
+ // Update pill data
+ $('.badge-pill').each(function(index) {
+ for (var ip in storageData) {
+ if ($(this).html().includes(ip)) {
+ var totalCache = storageData[ip].total;
+ var usedCache = storageData[ip].used;
+ var freeCache = toGiB(totalCache - usedCache, 1)
+ $(this).html($(this).html() + '<br>free: ' + freeCache + ' GiB');
+ break;
+ }
+ }
+ });
+</script>
+{% else %}
+<div class="card text-center p-3">
+ <b>{{ _('No cache contents') }}</b>
+</div>
+{% endif %}
+
+{% endif %} \ No newline at end of file
diff --git a/ogcp/views.py b/ogcp/views.py
index 2a6c244..2c8f650 100644
--- a/ogcp/views.py
+++ b/ogcp/views.py
@@ -354,6 +354,34 @@ def hash_password(pwd):
return pwd_hash
+def get_cache_info(clients_info, storage_data, images_data, client_images):
+ for client_info in clients_info:
+ ip = client_info['ip']
+ cache_size = int(client_info['cache_size'])
+ used_cache = 0
+ for image_info in client_info['images']:
+ image_name = image_info['name']
+ checksum = image_info['checksum']
+ used_cache += int(image_info['size'])
+ img_identifier = f'{image_name}.{checksum}'
+
+ if ip in client_images:
+ client_images[ip].append(img_identifier)
+ else:
+ client_images[ip] = [img_identifier]
+
+ if img_identifier in images_data:
+ images_data[img_identifier]['clients'].append(ip)
+ else:
+ images_data[img_identifier] = {
+ 'clients': [ip],
+ 'size': int(image_info['size']),
+ 'name': image_name,
+ 'checksum': checksum
+ }
+
+ storage_data[ip] = {'used': used_cache,
+ 'total': cache_size}
def authenticate_user(username, pwd):
for user in app.config['USERS']:
@@ -1171,9 +1199,9 @@ def action_client_cache():
if not validate_elements(ips):
return redirect(url_for('commands'))
- server = get_server_from_clients(ips_list)
form.ips.data = ' '.join(ips_list)
+ server = get_server_from_clients(ips_list)
r = server.get('/cache/list', payload={'clients': ips_list})
if not r:
return ogserver_down('commands')
@@ -1189,33 +1217,8 @@ def action_client_cache():
storage_data = {}
images_data = {}
client_images = {}
- for client_info in clients_info:
- ip = client_info['ip']
- cache_size = int(client_info['cache_size'])
- used_cache = 0
- for image_info in client_info['images']:
- image_name = image_info['name']
- checksum = image_info['checksum']
- used_cache += int(image_info['size'])
- img_identifier = f'{image_name}.{checksum}'
-
- if ip in client_images:
- client_images[ip].append(img_identifier)
- else:
- client_images[ip] = [img_identifier]
- if img_identifier in images_data:
- images_data[img_identifier]['clients'].append(ip)
- else:
- images_data[img_identifier] = {
- 'clients': [ip],
- 'size': int(image_info['size']),
- 'name': image_name,
- 'checksum': checksum
- }
-
- storage_data[ip] = {'used': used_cache,
- 'total': cache_size}
+ get_cache_info(clients_info, storage_data, images_data, client_images)
for img_identifier in images_data:
image_data = images_data[img_identifier]
@@ -1321,10 +1324,31 @@ def action_client_info():
else:
entry['image'] = ""
+ r = server.get('/cache/list', payload={'clients': [ip]})
+ if not r:
+ return ogserver_down('commands')
+ if r.status_code != requests.codes.ok:
+ return ogserver_error('commands')
+
+ clients_info = r.json()['clients']
+
+ if not clients_info:
+ flash(_('ogServer returned an empty client list'), category='error')
+ return redirect(url_for('commands'))
+
+ storage_data = {}
+ images_data = {}
+ client_images = {}
+
+ get_cache_info(clients_info, storage_data, images_data, client_images)
+
scopes, clients = get_scopes(set(ips))
return render_template('actions/client_details.html', form=form,
- parent="commands.html", scopes=scopes, setup=setup)
+ parent="commands.html", scopes=scopes, setup=setup,
+ images_data=images_data,
+ storage_data=storage_data,
+ client_images=client_images)
@app.route('/action/client/update', methods=['GET', 'POST'])
@login_required
@@ -1455,6 +1479,7 @@ def action_client_update():
entry['image'] = ""
form.submit.render_kw = {"formaction": url_for('action_client_update')}
+
return render_template('actions/client_details.html', form=form,
parent="scopes.html", scopes=scopes, setup=setup)