summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlejandro Sirgo Rica <asirgo@soleta.eu>2024-05-14 14:44:37 +0200
committerAlejandro Sirgo Rica <asirgo@soleta.eu>2024-05-16 12:17:21 +0200
commit8e60e95df6138566ebdf93a7ff74f2badcd98a86 (patch)
tree9ed9485a4a51e799cc0974307ee4664e1b88310a
parent7daf4c9ae11f74e6c0179cf300d2393728e0329e (diff)
make the boot OS form work over multiple clients
Enable working over multiple clients even if their OS configuration is different to greatly improve the user's workflow. Group clients with the same configuration under the same checkbox in the form. Report clients excluded from the boot instruction due to not matching OS configuration.
-rw-r--r--ogcp/forms/action_forms.py1
-rw-r--r--ogcp/templates/actions/session.html37
-rw-r--r--ogcp/views.py60
3 files changed, 79 insertions, 19 deletions
diff --git a/ogcp/forms/action_forms.py b/ogcp/forms/action_forms.py
index 94388c8..46081b5 100644
--- a/ogcp/forms/action_forms.py
+++ b/ogcp/forms/action_forms.py
@@ -86,7 +86,6 @@ class SoftwareForm(FlaskForm):
class SessionForm(FlaskForm):
ips = HiddenField()
os = RadioField(label=_l('Session'), choices=[])
- run = SubmitField(label=_l('Run'))
class ImageRestoreForm(FlaskForm):
ips = HiddenField()
diff --git a/ogcp/templates/actions/session.html b/ogcp/templates/actions/session.html
index 1e16a03..56865fb 100644
--- a/ogcp/templates/actions/session.html
+++ b/ogcp/templates/actions/session.html
@@ -16,10 +16,37 @@
{{ macros.cmd_selected_clients(selected_clients) }}
-{{ wtf.quick_form(form,
- action=url_for('action_session'),
- method='post',
- button_map={'run': 'primary'},
- extra_classes='mx-5') }}
+<p>
+{% if os_groups|length > 1 %}
+The selected clients have different installed OS:
+{% endif %}
+</p>
+
+<form class="form-inline" method="POST" id="sessionForm">
+ <table class="table table-hover">
+ <thead class="thead-light">
+ <tr>
+ <th>{{ _('Operating System') }}</th>
+ <th>{{ _('Clients') }}</th>
+ </tr>
+ </thead>
+
+ <tbody data-target="partitons-fieldset" id="partitionsTable" class="text-left">
+ {{ form.hidden_tag() }}
+ {% for os_choice in form.os %}
+ <tr data-toggle="fieldset-entry">
+ <td class="radio-container">
+ {{ os_choice(class_="form-control") }}
+ <b>{{ os_choice.label.text }}</b>
+ </td>
+ <td>{{ ', '.join(os_groups[os_choice.data]) }}</td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ <button class="btn btn-success" form="sessionForm">
+ {{ _('Boot') }}
+ </button>
+</form>
{% endblock %}
diff --git a/ogcp/views.py b/ogcp/views.py
index a5d5e2e..056c3e5 100644
--- a/ogcp/views.py
+++ b/ogcp/views.py
@@ -647,6 +647,7 @@ def action_setup_modify():
for partition in form.partitions:
if partition.part_type.data == 'CACHE':
cache_count += 1
+
if cache_count == 0:
flash(_(f'Missing cache partition'), category='error')
return redirect(url_for('commands'))
@@ -957,23 +958,47 @@ def action_session():
form = SessionForm(request.form)
if request.method == 'POST':
ips = form.ips.data.split(' ')
- disk, partition = form.os.data.split(' ')
-
+ disk, partition, os_name = form.os.data.split(' ', 2)
server = get_server_from_clients(list(ips))
- r = server.post('/session', payload={'clients': ips,
+
+ r = server.get('/session', payload={'clients': ips})
+ if not r:
+ return ogserver_down('commands')
+ if r.status_code != requests.codes.ok:
+ return ogserver_error('commands')
+
+ sessions = r.json()['sessions']
+ if not sessions:
+ flash(_('ogServer returned an empty session list'),
+ category='error')
+ return redirect(url_for('commands'))
+
+ valid_ips = []
+ excluded_ips = []
+ for os, ip in zip(sessions, ips):
+ if os['disk'] == int(disk) and os['partition'] == int(partition) and os['name'] == os_name:
+ valid_ips.append(ip)
+ else:
+ excluded_ips.append(ip)
+
+ r = server.post('/session', payload={'clients': valid_ips,
'disk': str(disk),
'partition': str(partition)})
if r.status_code == requests.codes.ok:
+ if excluded_ips:
+ flash('The following clients didn\'t match the boot configuration: ' + str(excluded_ips))
return redirect(url_for('commands'))
return make_response("400 Bad Request", 400)
else:
ips = parse_elements(request.args.to_dict())
- if not validate_elements(ips, max_len=1):
+ ips_list = list(ips)
+ if not validate_elements(ips):
return redirect(url_for('commands'))
- server = get_server_from_clients(list(ips))
- form.ips.data = ' '.join(ips)
- r = server.get('/session', payload={'client': list(ips)})
+ server = get_server_from_clients(ips_list)
+ form.ips.data = ' '.join(ips_list)
+
+ r = server.get('/session', payload={'clients': ips_list})
if not r:
return ogserver_down('commands')
if r.status_code != requests.codes.ok:
@@ -982,18 +1007,27 @@ def action_session():
sessions = r.json()['sessions']
if not sessions:
flash(_('ogServer returned an empty session list'),
- category='error')
+ category='error')
return redirect(url_for('commands'))
- for os in sessions:
- choice = (f"{os['disk']} {os['partition']}",
- f"OS: {os['name']} (Disk:{os['disk']}, Partition:{os['partition']})")
- form.os.choices.append(choice)
+ os_groups = {}
+ for os, ip in zip(sessions, ips_list):
+ item_key = f"{os['disk']} {os['partition']} {os['name']}"
+
+ if item_key in os_groups:
+ os_groups[item_key].append(ip)
+ else:
+ os_groups[item_key] = [ip]
+
+ choice = (item_key,
+ f"{os['name']} (Disk:{os['disk']}, Partition:{os['partition']})")
+ form.os.choices.append(choice)
+
scopes, clients = get_scopes(set(ips))
selected_clients = list(get_selected_clients(scopes['scope']).items())
return render_template('actions/session.html', form=form,
selected_clients=selected_clients,
- scopes=scopes)
+ scopes=scopes, os_groups=os_groups)
@app.route('/action/client/info', methods=['GET'])
@login_required