From d00e437b8d76bc32732643a92f0ea32fbe0b7901 Mon Sep 17 00:00:00 2001 From: Alejandro Sirgo Rica Date: Thu, 29 Aug 2024 11:55:52 +0200 Subject: ogcp: add support for multi-disk partition and format Add support for selecting different disks in the disk inspector. Add disk_inspector.html as a template to show the disk contents of a client. The view can define the variable readonly_disk_inspector to make the view non editable. Use disk_inspector.html in the following views: - client details - partition and format Update code to obtain the partitions of a client to better fit the requirements of disk_inspector.html Remove code to setup the SetupForm as the contents of the disks are now dynamically loaded through javascript. --- ogcp/views.py | 192 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 104 insertions(+), 88 deletions(-) (limited to 'ogcp/views.py') diff --git a/ogcp/views.py b/ogcp/views.py index 86006ba..579a43f 100644 --- a/ogcp/views.py +++ b/ogcp/views.py @@ -158,6 +158,26 @@ def parse_elements(checkboxes_dict): elements.update(elements_list.split(' ')) return elements +def client_setup_add_image_names(server, setup_data): + r = server.get('/images') + if not r: + raise ServerError + if r.status_code != requests.codes.ok: + raise ServerErrorCode + + images = r.json()['images'] + + for disk, partitions in setup_data.items(): + for p in partitions: + if images and p['image'] != 0: + image = next((img for img in images if img['id'] == p['image']), None) + if image: + p['image'] = image['name'] + else: + p['image'] = "" + else: + p['image'] = "" + def get_client_setup(ip): server = get_server_from_clients([ip]) @@ -175,6 +195,7 @@ def get_client_setup(ip): if r.status_code != requests.codes.ok: raise ServerErrorCode db_partitions = r.json()['partitions'] + res = {} for partition in db_partitions: if partition['partition'] == 0: partition['code'] = PART_SCHEME_CODES.get(partition['code'], 'MSDOS') @@ -183,7 +204,20 @@ def get_client_setup(ip): partition['filesystem'] = FS_CODES.get(partition['filesystem'], 'EMPTY') - return db_partitions + disk = partition.get('disk') + if disk in res: + res[disk].append(partition) + else: + res[disk] = [partition] + + return res + +@app.route('/client/setup', methods=['GET']) +@login_required +def get_client_setup_json(): + ip = parse_elements(request.args.to_dict()) + setup = get_client_setup(ip) + return jsonify(setup) def get_clients(state_filter=None): responses = multi_request('get', '/clients') @@ -642,6 +676,33 @@ def action_wol(): return redirect(url_for('commands')) +def get_common_disk_data(ips): + disk_data = {} + + for ip in ips: + setup_data = get_client_setup(ip) + + for disk, partitions in setup_data.items(): + for p in partitions: + if p.get('partition') != 0: + continue + if disk in disk_data: + disk_data[disk]['common_size'] = min(disk_data[disk]['common_size'], p.get('size')) + disk_data[disk]['inventory'].setdefault(p.get('size'), []).append(ip) + else: + disk_data[disk] = { + 'common_size': p.get('size'), + 'excluded': [], + 'inventory': {p.get('size'): [ip]} + } + break + + for disk_id in disk_data: + if disk_id not in setup_data: + disk_data[disk_id]['excluded'].append(ip) + + return disk_data + @app.route('/action/setup/select', methods=['GET']) @login_required def action_setup_select(): @@ -671,10 +732,13 @@ def action_setup_select(): client_choices.append((ip, f"{client_name} ({ip})")) form.selected_client.choices = client_choices + common_disk_data = get_common_disk_data(ips) + scopes, unused = get_scopes(ips) selected_clients = list(get_selected_clients(scopes['scope']).items()) return render_template('actions/select_client.html', + common_disk_data=common_disk_data, selected_clients=selected_clients, form=form, scopes=scopes) @@ -685,9 +749,6 @@ def action_setup_show(): args = request.args.copy() disk_size = None - default_disk = 1 - selected_disk = int(args.pop('disk', default_disk)) - if args.get('ip'): ips = {args['ip']} ips_str = base_client = args['ip'] @@ -696,59 +757,37 @@ def action_setup_show(): ips = set(args['ips'].split(' ')) base_client = args['selected_client'] - for ip in ips: - try: - setup_data = get_client_setup(ip) - except ServerError: - return ogserver_down('commands') - except ServerErrorCode: - return ogserver_error('commands') - - filtered_partitions = [p for p in setup_data - if p.get('disk') == selected_disk] - if not filtered_partitions: - continue - - if ip == base_client: - target_partitions = filtered_partitions - - client_disk_size = filtered_partitions[0]['size'] // 1024 - if disk_size: - disk_size = min(disk_size, client_disk_size) - else: - disk_size = client_disk_size + try: + setup_data = get_client_setup(base_client) + except ServerError: + return ogserver_down('commands') + except ServerErrorCode: + return ogserver_error('commands') - if not target_partitions: + if not setup_data: flash(_('Partition information is not available. Boot client in ogLive mode to obtain it'), category='error') return redirect(url_for('commands')) - disk_partition = 0 - disks = [d.get('disk') for d in target_partitions - if d.get('partition') == disk_partition] + selected_disk = 1 + common_disk_data = get_common_disk_data(ips) + + # Use common disk size + for disk in setup_data: + setup_data[disk][0]['size'] = common_disk_data[disk]['common_size'] form = SetupForm() form.ips.data = ips_str + + form.disk.choices = [(disk, disk) for disk in setup_data] form.disk.data = selected_disk # If partition table is empty, set MSDOS - form.disk_type.data = target_partitions[0]['code'] or 1 - - # Make form.partition length equal to (target_partitions - 1) length - diff = len(target_partitions) - 1 - len(form.partitions) - [form.partitions.append_entry() for unused in range(diff)] + form.disk_type.data = setup_data[selected_disk][0]['code'] or 1 - for partition, db_part in zip(form.partitions, target_partitions[1:]): - partition.partition.data = str(db_part['partition']) - partition.part_type.data = db_part['code'] - partition.fs.data = db_part['filesystem'] - partition.size.data = db_part['size'] // 1024 scopes, _clients = get_scopes(ips) return render_template('actions/setup.html', selected_disk=selected_disk, - disks=disks, - form=form, - disk_size=disk_size, - ips=ips_str, - base_client=base_client, + setup_data=setup_data, + disk_form=form, scopes=scopes) @app.route('/action/setup', methods=['POST']) @@ -1461,34 +1500,19 @@ def action_client_info(): form.submit.render_kw = {"style": "visibility:hidden;"} - r = server.get('/images') - if not r: - return ogserver_down('commands') - if r.status_code != requests.codes.ok: - return ogserver_error('commands') - - images = r.json()['images'] - ip = list(ips)[0] try: - setup = get_client_setup(ip) + setup_data = get_client_setup(ip) + client_setup_add_image_names(server, setup_data) except ServerError: return ogserver_down('commands') except ServerErrorCode: return ogserver_error('commands') - if setup and setup[0].get('code') == 'MSDOS': - setup[0]['code'] = 'MBR' - - for entry in setup: - if images and entry['image'] != 0: - image = next((img for img in images if img['id'] == entry['image']), None) - if image: - entry['image'] = image['name'] - else: - entry['image'] = "" - else: - entry['image'] = "" + disk_form = SetupForm() + selected_disk = 1 + disk_form.disk.choices = [(disk, disk) for disk in setup_data] + disk_form.disk.data = selected_disk r = server.get('/cache/list', payload={'clients': [ip]}) if not r: @@ -1511,7 +1535,10 @@ def action_client_info(): scopes, clients = get_scopes(set(ips)) return render_template('actions/client_details.html', form=form, - parent="commands.html", scopes=scopes, setup=setup, + parent="commands.html", scopes=scopes, + setup_data=setup_data, + disk_form=disk_form, + selected_disk=selected_disk, images_data=images_data, storage_data=storage_data, client_images=client_images) @@ -1620,36 +1647,25 @@ def action_client_update(): if db_client['repo_id'] != repo["id"]]) ip = list(ips)[0] try: - setup = get_client_setup(ip) + setup_data = get_client_setup(ip) + client_setup_add_image_names(server, setup_data) except ServerError: return ogserver_down('scopes') except ServerErrorCode: return ogserver_error('scopes') - if setup and setup[0].get('code') == 'MSDOS': - setup[0]['code'] = 'MBR' - - r = server.get('/images') - if not r: - return ogserver_down('scopes') - if r.status_code != requests.codes.ok: - return ogserver_error('scopes') - - images = r.json()['images'] - for entry in setup: - if images and entry['image'] != 0: - image = next((img for img in images if img['id'] == entry['image']), None) - if image: - entry['image'] = image['name'] - else: - entry['image'] = "" - else: - entry['image'] = "" + disk_form = SetupForm() + selected_disk = 1 + disk_form.disk.choices = [(disk, disk) for disk in setup_data] + disk_form.disk.data = selected_disk form.submit.render_kw = {"formaction": url_for('action_client_update')} return render_template('actions/client_details.html', form=form, - parent="scopes.html", scopes=scopes, setup=setup) + setup_data=setup_data, + disk_form=disk_form, + selected_disk=selected_disk, + parent="scopes.html", scopes=scopes) def find_folder(folder_id, scopes): scopes = deque([scopes['scope']]) @@ -3048,7 +3064,7 @@ def repo_addr_is_valid(form): if invalid_ips: res = False flash(_(f'The following addresses are invalid: {" ".join(invalid_ips)}'), category='error') - + if ip_count > 16: res = False flash(_('More than 16 addresses is not supported'), category='error') -- cgit v1.2.3-18-g5258