summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ogcp/templates/actions/partition_report.html46
-rw-r--r--ogcp/views.py78
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,