summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlejandro Sirgo Rica <asirgo@soleta.eu>2024-08-07 16:13:50 +0200
committerAlejandro Sirgo Rica <asirgo@soleta.eu>2024-08-09 10:01:23 +0200
commit844bc1e7c677908063002b525f7996f0b0ea58f4 (patch)
tree2e31914f075e51daba1d01149b5e218a6e1ba349
parentace0c5bb46ee78b0fe6533b5d50a2dd8c04198a4 (diff)
ogcp: Add /action/cache/fetch endpoint
Add view to request the download of images into the client's cache.
-rw-r--r--ogcp/forms/action_forms.py8
-rw-r--r--ogcp/templates/actions/cache_fetch.html27
-rw-r--r--ogcp/templates/commands.html2
-rw-r--r--ogcp/views.py91
4 files changed, 127 insertions, 1 deletions
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 %}
+<h2 class="mx-5 subhead-heading">
+ {{ _('Cache image in %(ip_count)d computer(s)', ip_count=ip_count) }}
+</h2>
+
+{{ 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 %}
<input class="btn btn-light dropdown-item{% block nav_image_restore %}{% endblock %}" type="submit" value="{{ _('Restore Image') }}"
form="scopesForm" formaction="{{ url_for('action_image_restore') }}" formmethod="get">
+ <input class="btn btn-light dropdown-item{% block nav_image_fetch %}{% endblock %}" type="submit" value="{{ _('Cache image') }}"
+ form="scopesForm" formaction="{{ url_for('action_image_fetch') }}" formmethod="get">
</div>
</div>
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():