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.
master
Alejandro Sirgo Rica 2024-05-14 14:44:37 +02:00
parent 7daf4c9ae1
commit 8e60e95df6
3 changed files with 87 additions and 27 deletions

View File

@ -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()

View File

@ -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 %}

View File

@ -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,10 @@ 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,
'disk': str(disk),
'partition': str(partition)})
if r.status_code == requests.codes.ok:
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):
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)})
r = server.get('/session', payload={'clients': ips})
if not r:
return ogserver_down('commands')
if r.status_code != requests.codes.ok:
@ -982,18 +970,64 @@ 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)
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())
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('/session', payload={'clients': ips_list})
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'))
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