From 844bc1e7c677908063002b525f7996f0b0ea58f4 Mon Sep 17 00:00:00 2001 From: Alejandro Sirgo Rica Date: Wed, 7 Aug 2024 16:13:50 +0200 Subject: ogcp: Add /action/cache/fetch endpoint Add view to request the download of images into the client's cache. --- ogcp/forms/action_forms.py | 8 +++ ogcp/templates/actions/cache_fetch.html | 27 ++++++++++ ogcp/templates/commands.html | 2 + ogcp/views.py | 91 ++++++++++++++++++++++++++++++++- 4 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 ogcp/templates/actions/cache_fetch.html diff --git a/ogcp/forms/action_forms.py b/ogcp/forms/action_forms.py index 82958fb..496be56 100644 --- a/ogcp/forms/action_forms.py +++ b/ogcp/forms/action_forms.py @@ -110,6 +110,14 @@ class ImageRestoreForm(FlaskForm): ('UNICAST-DIRECT', 'UNICAST-DIRECT')]) restore = SubmitField(label=_l('Restore')) +class ImageFetchForm(FlaskForm): + ips = HiddenField() + image = SelectField(label=_l('Image'), choices=[]) + method = SelectField(label=_l('Method'), + choices=[('TIPTORRENT', 'TIPTORRENT'), + ('UNICAST', 'UNICAST')]) + submit = SubmitField(label=_l('Submit')) + class RepoForm(FlaskForm): server = HiddenField() repo_id = HiddenField() diff --git a/ogcp/templates/actions/cache_fetch.html b/ogcp/templates/actions/cache_fetch.html new file mode 100644 index 0000000..c04d20b --- /dev/null +++ b/ogcp/templates/actions/cache_fetch.html @@ -0,0 +1,27 @@ +{% extends 'commands.html' %} +{% import "bootstrap/wtf.html" as wtf %} +{% import "macros.html" as macros %} + +{% set sidebar_state = 'disabled' %} +{% set btn_back = true %} + +{% block nav_image %} active {% endblock %} +{% block nav_cache_fetch %} active {% endblock %} +{% block content %} + +{% set ip_list = form.ips.data.split(' ') %} +{% set ip_count = ip_list | length %} +

+ {{ _('Cache image in %(ip_count)d computer(s)', ip_count=ip_count) }} +

+ +{{ macros.cmd_selected_clients(selected_clients) }} + +{{ wtf.quick_form(form, + action=url_for('action_image_fetch'), + method='post', + button_map={'submit': 'primary'}, + extra_classes='m-5') }} + + +{% endblock %} diff --git a/ogcp/templates/commands.html b/ogcp/templates/commands.html index 6f77316..f8a32b0 100644 --- a/ogcp/templates/commands.html +++ b/ogcp/templates/commands.html @@ -76,6 +76,8 @@ {% endif %} + diff --git a/ogcp/views.py b/ogcp/views.py index 3725899..f964c1e 100644 --- a/ogcp/views.py +++ b/ogcp/views.py @@ -14,7 +14,7 @@ from ogcp.forms.action_forms import ( RoomForm, DeleteRoomForm, CenterForm, DeleteCenterForm, OgliveForm, GenericForm, SelectClientForm, ImageUpdateForm, ImportClientsForm, ServerForm, DeleteRepositoryForm, RepoForm, FolderForm, CacheForm, - ClientMoveForm, RunScriptForm, ImageConfigForm + ClientMoveForm, RunScriptForm, ImageConfigForm, ImageFetchForm ) from flask_login import ( current_user, LoginManager, @@ -1307,6 +1307,95 @@ def action_client_cache(): storage_data=storage_data, client_images=client_images) +@app.route('/action/cache/fetch', methods=['GET', 'POST']) +@login_required +def action_image_fetch(): + form = ImageFetchForm(request.form) + if request.method == 'POST': + ips = form.ips.data.split(' ') + server = get_server_from_clients(list(ips)) + + image_id = form.image.data + server = get_server_from_clients(ips) + r = server.get('/images') + if not r: + return ogserver_down('commands') + if r.status_code != requests.codes.ok: + return ogserver_error('commands') + + images_list = r.json()['images'] + image = search_image(images_list, int(image_id)) + if not image: + flash(_(f'Image to fetch was not found'), category='error') + return redirect(url_for('commands')) + + try: + repository = get_repository(image['repo_id'], server) + except ServerError: + return ogserver_down('commands') + except ServerErrorCode: + return ogserver_error('commands') + + payload = {'clients': ips, + 'repository': repository['ip'], + 'type': form.method.data, + 'image': image['name']} + + r = server.post('/cache/fetch', payload=payload) + if not r: + return ogserver_down('commands') + if r.status_code == requests.codes.ok: + flash(_('Cache fetch request sent successfully'), category='info') + else: + flash(_(f'Invalid cache fetch form'), category='error') + return redirect(url_for('commands')) + else: + params = request.args.to_dict() + ips = parse_elements(params) + center_id = int(params.get('scope-center')) + + if not validate_elements(ips): + return redirect(url_for('commands')) + + ips_list = list(ips) + form.ips.data = ' '.join(ips_list) + + server = get_server_from_clients(ips) + + try: + repo_id = get_clients_repo(server, ips) + except ServerError: + return ogserver_down('commands') + except ServerErrorCode: + return ogserver_error('commands') + + if repo_id is None: + flash(_(f'Computers have different repos assigned'), category='error') + return redirect(url_for('commands')) + try: + images = get_images_from_repo(server, repo_id) + + if not images: + flash(_(f'Computer(s) assigned to a repo with no images'), category='error') + return redirect(url_for('commands')) + + images = filter_images_allowed_in_center(server, images, center_id) + except ServerError: + return ogserver_down('commands') + except ServerErrorCode: + return ogserver_error('commands') + + sort_images(images) + + for image in images: + form.image.choices.append((image['id'], image['name'])) + + scopes, clients = get_scopes(set(ips)) + selected_clients = list(get_selected_clients(scopes['scope']).items()) + return render_template('actions/cache_fetch.html', form=form, + selected_clients=selected_clients, + scopes=scopes) + @app.route('/action/client/info', methods=['GET']) @login_required def action_client_info(): -- cgit v1.2.3-18-g5258