diff options
-rw-r--r-- | ogcp/templates/actions/partition_report.html | 46 | ||||
-rw-r--r-- | ogcp/views.py | 78 |
2 files changed, 101 insertions, 23 deletions
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 %} + +<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 %} 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, |