summaryrefslogtreecommitdiffstats
path: root/ogcp/views.py
diff options
context:
space:
mode:
authorAlejandro Sirgo Rica <asirgo@soleta.eu>2024-05-16 12:38:28 +0200
committerAlejandro Sirgo Rica <asirgo@soleta.eu>2024-05-30 15:50:32 +0200
commit9cb3a952b4ceb3c33e8481250179023fdf5ceebb (patch)
tree6d590a2b18869a20370ae4513cbd4ad4559fb603 /ogcp/views.py
parentf896107375cc2a47a5c4eb3095c6c365d8eed98e (diff)
ogcp: add cache management page
Implement cache management through cache/list and cache/delete API REST methods. The view corresponds to the URL action/cache and contains three main parts: - Free cache available in the client's bubbles. - Image selection form to request the deletion and view the client with that image in cache. - Cache details per client to see total, used and available cache. The main usecase for the view is the removal of cache to make room for new images in clients with slow connections. Checking clients where available cache space is not enough to hold the new image and then requesting removal of specific images. The html template receives the following structures from the view: storage_data[ip] = {'used': 223452345, 'total': 2345234523452} client_images[ip] = [f'{image_name}.{image_checksum}', ...] image_data[f'{image_name}.{image_checksum}'] = { clients: ['192.168.0.1', ...], size: 34534530850, name: image_name, }
Diffstat (limited to 'ogcp/views.py')
-rw-r--r--ogcp/views.py99
1 files changed, 98 insertions, 1 deletions
diff --git a/ogcp/views.py b/ogcp/views.py
index d02359b..32beb3e 100644
--- a/ogcp/views.py
+++ b/ogcp/views.py
@@ -13,7 +13,7 @@ from ogcp.forms.action_forms import (
SessionForm, ImageRestoreForm, ImageCreateForm, SoftwareForm, BootModeForm,
RoomForm, DeleteRoomForm, CenterForm, DeleteCenterForm, OgliveForm,
GenericForm, SelectClientForm, ImageUpdateForm, ImportClientsForm,
- ServerForm, DeleteRepositoryForm, RepoForm, FolderForm
+ ServerForm, DeleteRepositoryForm, RepoForm, FolderForm, CacheForm
)
from flask_login import (
current_user, LoginManager,
@@ -1033,6 +1033,103 @@ def action_session():
selected_clients=selected_clients,
scopes=scopes, os_groups=os_groups)
+@app.route('/action/cache', methods=['GET', 'POST'])
+@login_required
+def action_client_cache():
+ form = CacheForm(request.form)
+ if request.method == 'POST':
+ ips = form.ips.data.split(' ')
+ server = get_server_from_clients(list(ips))
+
+ client_list = []
+ image_list = []
+ for entry in form.images.entries:
+ if not entry.selected.data:
+ continue
+
+ image_list.append(entry.image_name.data)
+ for client_ip in entry.clients.data.split(' '):
+ if not client_ip in client_list:
+ client_list.append(client_ip)
+
+ if not image_list:
+ flash(_(f'No selected images to delete'), category='error')
+ return redirect(url_for('commands'))
+
+ r = server.post('/cache/delete',
+ payload={'clients': client_list,
+ 'images': image_list})
+ if r.status_code == requests.codes.ok:
+ flash(_('Cache delete request sent successfully'), category='info')
+ else:
+ flash(_(f'Invalid cache delete form'), category='error')
+ return redirect(url_for('commands'))
+ else:
+ ips = parse_elements(request.args.to_dict())
+ ips_list = list(ips)
+ if not validate_elements(ips):
+ return redirect(url_for('commands'))
+
+ server = get_server_from_clients(ips_list)
+ form.ips.data = ' '.join(ips_list)
+
+ r = server.get('/cache/list', payload={'clients': ips_list})
+ 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 = {}
+ 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,
+ }
+
+ storage_data[ip] = {'used': used_cache,
+ 'total': cache_size}
+
+ for img_identifier in images_data:
+ image_data = images_data[img_identifier]
+ checkbox_entry = form.images.append_entry()
+ checkbox_entry.selected.label.text = img_identifier
+ checkbox_entry.image_name.data = image_data['name']
+ checkbox_entry.clients.data = ' '.join(image_data['clients'])
+
+ scopes, clients = get_scopes(set(ips))
+ selected_clients = list(get_selected_clients(scopes['scope']).items())
+ return render_template('actions/cache.html', form=form,
+ selected_clients=selected_clients,
+ scopes=scopes, images_data=images_data,
+ storage_data=storage_data,
+ client_images=client_images)
+
@app.route('/action/client/info', methods=['GET'])
@login_required
def action_client_info():