ogcp: add view to identify clients setup diferences before restore

Add view to provide information before a restore operation where
the selected clients have a not uniform partition setup.

Show the view if only clients with not partition valid for a
restore operation are selected.
master
Alejandro Sirgo Rica 2024-09-30 10:02:00 +02:00
parent d6a896628f
commit 6af4330016
2 changed files with 106 additions and 28 deletions

View File

@ -0,0 +1,46 @@
{% extends 'commands.html' %}
{% import "bootstrap/wtf.html" as wtf %}
{% import "macros.html" as macros %}
{% set sidebar_state = 'disabled' %}
{% set btn_back = true %}
{% block content %}
<h2 class="mx-5 subhead-heading">
{{ _('Partition scheme mismatch') }}
</h2>
{{ macros.cmd_selected_clients(selected_clients) }}
</br>
<div class="container mx-5">
<b>{{ _('Cannot proceed with this command, selected clients have non-uniform or valid partition scheme') }}</b>
</div>
<table class="table table-bordered table-hover">
<thead class="text-center">
<tr>
<th style="min-width: 15em;">{{ _('Partitions') }}</th>
<th>{{ _('Clients') }}</th>
</tr>
</thead>
<tbody>
{% for idx in range(part_data | length) %}
<tr>
<td>
{% for disk_id, part_id, part_type, fs_type, part_size in part_data.get_partition_setup(idx) %}
<div>Part {{ part_id }} | {{ fs_type }} | {{ (part_size / 1024) | int}} MiB</div>
{% else %}
{{ _('Empty') }}
{% endfor %}
</td>
<td>
{% for ip in part_data.get_clients(idx) %}<div class="card d-inline-block" style="padding: 5px; margin: 3px;">{{ ip }}</div>{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@ -982,13 +982,47 @@ def image_fits_in_cache(server, clients_info, image):
return True
class PartitionCollection:
def __init__(self):
self.partition_list = []
self.clients = []
self.empty_scheme = False
def __len__(self):
return len(self.partition_list)
def has_empty_scheme(self):
return self.empty_scheme
def register_partition_setup(self, partitions, client):
idx = None
self.empty_scheme = self.empty_scheme or not partitions
for index, p in enumerate(self.partition_list):
if p == partitions:
idx = index
self.clients[idx].append(client)
break
else:
idx = len(self.partition_list)
self.partition_list.append(partitions)
self.clients.append([client])
return idx
def get_partition_setup(self, idx):
return self.partition_list[idx]
def get_clients(self, idx):
return self.clients[idx]
@app.route('/action/image/restore', methods=['GET', 'POST'])
@login_required
def action_image_restore():
form = ImageRestoreForm(request.form)
if request.method == 'POST':
ips = form.ips.data.split(' ')
disk, partition, part_code, part_size, has_cache = form.partition.data.split(' ')
disk, partition, part_size, has_cache = form.partition.data.split(' ')
requires_cache = form.method.data == 'TIPTORRENT' or form.method.data == 'UNICAST'
if has_cache == 'False' and requires_cache:
@ -1080,11 +1114,10 @@ def action_image_restore():
for image in images:
form.image.choices.append((image['id'], image['name']))
reference_patitioning = []
empty_clients = []
invalid_part_types = get_invalid_image_partition_types()
part_collection = PartitionCollection()
for ip in ips:
r = server.get('/client/setup', payload={'client': [ip]})
if not r:
@ -1113,37 +1146,36 @@ def action_image_restore():
continue
filesystem = partition['filesystem']
fs_type = FS_CODES.get(filesystem, 'UNKNOWN')
part_size = partition['size']
choice_value = (disk_id, part_id, part_code, filesystem, part_size)
parts.append(choice_value)
parts.append((disk_id, part_id, part_type, fs_type, part_size))
if not parts:
empty_clients.append(ip)
part_collection.register_partition_setup(parts, ip)
if empty_clients:
continue
if not reference_patitioning: # Use first computer as reference part setup conf
reference_patitioning = [part for part in parts]
elif reference_patitioning != parts:
flash(_(f'Computers have different partition setup'), category='error')
return redirect(url_for('commands'))
if empty_clients:
flash(_(f'The following clients have not partitions: {" ".join(empty_clients)}'), category='error')
return redirect(url_for('commands'))
for disk_id, part_id, part_code, filesystem, part_size in reference_patitioning:
form.partition.choices.append(
(f"{disk_id} {part_id} {part_code} {part_size} {has_cache}",
f"Disk {disk_id} | Partition {part_id} "
f"| {PART_TYPE_CODES.get(part_code, 'UNKNOWN')} "
f"{FS_CODES.get(filesystem, 'UNKNOWN')}")
)
scopes, clients = get_scopes(set(ips))
selected_clients = list(get_selected_clients(scopes['scope']).items())
if len(part_collection) > 1 or part_collection.has_empty_scheme():
return render_template('actions/partition_report.html',
selected_clients=selected_clients,
part_data=part_collection,
scopes=scopes)
reference_patitioning = part_collection.get_partition_setup(0)
if not reference_patitioning:
flash(_(f'No valid partition found'), category='error')
return redirect(url_for('commands'))
for disk_id, part_id, part_type, fs_type, part_size in reference_patitioning:
form.partition.choices.append(
(f"{disk_id} {part_id} {part_size} {has_cache}",
f"Disk {disk_id} | Partition {part_id} "
f"| {part_type} "
f"{fs_type}")
)
return render_template('actions/image_restore.html', form=form,
selected_clients=selected_clients,
scopes=scopes)