From 6af4330016f2e70abd79f08b73bf54aa85f8e591 Mon Sep 17 00:00:00 2001 From: Alejandro Sirgo Rica Date: Mon, 30 Sep 2024 10:02:00 +0200 Subject: 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. --- ogcp/templates/actions/partition_report.html | 46 ++++++++++++++++ ogcp/views.py | 78 ++++++++++++++++++++-------- 2 files changed, 101 insertions(+), 23 deletions(-) create mode 100644 ogcp/templates/actions/partition_report.html diff --git a/ogcp/templates/actions/partition_report.html b/ogcp/templates/actions/partition_report.html new file mode 100644 index 0000000..80a241e --- /dev/null +++ b/ogcp/templates/actions/partition_report.html @@ -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 %} + +

+ {{ _('Partition scheme mismatch') }} +

+ +{{ macros.cmd_selected_clients(selected_clients) }} +
+ +
+ {{ _('Cannot proceed with this command, selected clients have non-uniform or valid partition scheme') }} +
+ + + + + + + + + + {% for idx in range(part_data | length) %} + + + + + {% endfor %} + +
{{ _('Partitions') }}{{ _('Clients') }}
+ {% for disk_id, part_id, part_type, fs_type, part_size in part_data.get_partition_setup(idx) %} +
Part {{ part_id }} | {{ fs_type }} | {{ (part_size / 1024) | int}} MiB
+ {% else %} + {{ _('Empty') }} + {% endfor %} +
+ {% for ip in part_data.get_clients(idx) %}
{{ ip }}
{% endfor %} +
+ +{% endblock %} diff --git a/ogcp/views.py b/ogcp/views.py index 300bb04..899a3a9 100644 --- a/ogcp/views.py +++ b/ogcp/views.py @@ -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,36 +1146,35 @@ 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 + scopes, clients = get_scopes(set(ips)) + selected_clients = list(get_selected_clients(scopes['scope']).items()) - 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 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 empty_clients: - flash(_(f'The following clients have not partitions: {" ".join(empty_clients)}'), category='error') + if not reference_patitioning: + flash(_(f'No valid partition found'), category='error') return redirect(url_for('commands')) - for disk_id, part_id, part_code, filesystem, part_size in reference_patitioning: + for disk_id, part_id, part_type, fs_type, part_size in reference_patitioning: form.partition.choices.append( - (f"{disk_id} {part_id} {part_code} {part_size} {has_cache}", + (f"{disk_id} {part_id} {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')}") + f"| {part_type} " + f"{fs_type}") ) - scopes, clients = get_scopes(set(ips)) - selected_clients = list(get_selected_clients(scopes['scope']).items()) return render_template('actions/image_restore.html', form=form, selected_clients=selected_clients, -- cgit v1.2.3-18-g5258