From 5111733b93adb4f64c77caa6baf74aca987ce897 Mon Sep 17 00:00:00 2001 From: Alejandro Sirgo Rica Date: Thu, 4 Jul 2024 11:15:57 +0200 Subject: ogcp: use csv as new format for import clients Replace dhcpd format with the simpler csv format to configure the list of clients to import in /action/clients/import. Replace regex parsing with a simpler manual parsing. Improve error report. Example configuration: client_name1,94:c6:91:a6:25:1a,10.141.10.100 client_name2,94:c6:91:a6:25:1b,10.141.10.101 --- ogcp/forms/action_forms.py | 2 +- ogcp/views.py | 71 ++++++++++++++++++++++++++++++---------------- 2 files changed, 48 insertions(+), 25 deletions(-) diff --git a/ogcp/forms/action_forms.py b/ogcp/forms/action_forms.py index 3f4a8fc..c111940 100644 --- a/ogcp/forms/action_forms.py +++ b/ogcp/forms/action_forms.py @@ -160,7 +160,7 @@ class ImportClientsForm(FlaskForm): server = HiddenField() room = SelectField(label=_l('Room')) repo = SelectField(label=_l('Repository')) - dhcpd_conf = TextAreaField(label=_l('dhcpd configuration')) + client_conf = TextAreaField(label=_l('Client configuration')) import_btn = SubmitField(label=_l('Import')) class BootModeForm(FlaskForm): diff --git a/ogcp/views.py b/ogcp/views.py index a2c4e9d..9887d47 100644 --- a/ogcp/views.py +++ b/ogcp/views.py @@ -96,6 +96,9 @@ class ServerError(Exception): class ServerErrorCode(Exception): pass +def split_csv(s): + return re.split(r'\s*,\s*', s) + def normalize_mac(mac): return mac.replace(':', '').replace('-', '').replace('.', '').lower() @@ -1709,13 +1712,9 @@ def action_client_move(): scopes=scopes) -PLACEHOLDER_TEXT = '''host example1 { hardware ethernet 94:c6:91:a6:25:1a; fixed-address 10.141.10.100; } -host example2 { hardware ethernet 94:c6:91:a6:25:1b; fixed-address 10.141.10.101; } -host example3 { hardware ethernet 94:c6:91:a6:25:1c; fixed-address 10.141.10.102; } -host example4 { hardware ethernet 94:c6:91:a6:25:1d; fixed-address 10.141.10.103; } -host example5 { hardware ethernet 94:c6:91:a6:25:1e; fixed-address 10.141.10.104; } -host example6 { hardware ethernet 94:c6:91:a6:25:1f; fixed-address 10.141.10.105; } -...''' +PLACEHOLDER_CLIENT_IMPORT_TEXT = '''client_name1,94:c6:91:a6:25:1a,10.141.10.100 +client_name2,94:c6:91:a6:25:1b,10.141.10.101''' + @app.route('/action/clients/import', methods=['GET']) @login_required def action_clients_import_get(): @@ -1746,22 +1745,13 @@ def action_clients_import_get(): except ServerErrorCode: return ogserver_error('scopes') form.repo.choices = [(repo["id"], repo["name"]) for repo in repositories] - form.dhcpd_conf.render_kw = {'placeholder': PLACEHOLDER_TEXT} + form.client_conf.render_kw = {'placeholder': PLACEHOLDER_CLIENT_IMPORT_TEXT} scopes, _clients = get_scopes() return render_template('actions/import_clients.html', form=form, scopes=scopes) -OG_REGEX_DHCPD_CONF = (r'(?:\s*host\s*)' - r'([\w.-]*)' - r'(?:\s*{[ \n\r]*)' - r'(?:\s*hardware *ethernet *)' - r'((?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]{2}))' - r'(?:\s*;)' - r'(?:\s*fixed-address *)' - r'(\d+\.\d+\.\d+\.\d+)' - r'(?:\s*;)(?:\s*[^}]*})') OG_CLIENT_DEFAULT_BOOT = "pxe" OG_CLIENT_DEFAULT_LIVEDIR = "ogLive" OG_CLIENT_DEFAULT_MAINTENANCE = False @@ -1775,11 +1765,42 @@ OG_CLIENT_DEFAULT_REMOTE = False def action_clients_import_post(): form = ImportClientsForm(request.form) server = get_server_from_ip_port(form.server.data) - clients = re.findall(OG_REGEX_DHCPD_CONF, form.dhcpd_conf.data) + + clients = [] + for client_data in form.client_conf.data.splitlines(): + client_values = split_csv(client_data) + + if len(client_values) != 3 or any(not v for v in client_values): + flash(_('Each client requires 3 values'), category='error') + return redirect(url_for('scopes')) + + client_name = client_values[0] + + client_mac = client_values[1] + normalized_mac = normalize_mac(client_mac) + + if not is_valid_normalized_mac(normalized_mac): + flash(_(f'Invalid MAC address {client_mac}'), category='error') + return redirect(url_for("scopes")) + + client_ip = client_values[2] + + try: + ipaddress.ip_address(client_ip) + except ValueError as e: + flash(_(f'Invalid IP address {client_ip}'), category='error') + return redirect(url_for("scopes")) + + clients.append({ + 'name': client_name, + 'mac': normalized_mac, + 'ip': client_ip + }) + if not clients: - flash(_('No clients found. Check the dhcpd.conf file.'), - category='error') + flash(_('No client configuration found'), category='error') return redirect(url_for('scopes')) + payload = {'boot': OG_CLIENT_DEFAULT_BOOT, 'livedir': OG_CLIENT_DEFAULT_LIVEDIR, 'maintenance': OG_CLIENT_DEFAULT_MAINTENANCE, @@ -1789,15 +1810,17 @@ def action_clients_import_post(): 'remote': OG_CLIENT_DEFAULT_REMOTE, "repo_id": int(form.repo.data), 'room': int(form.room.data)} + for client in clients: - payload['name'] = client[0] - payload['mac'] = normalize_mac(client[1]) - payload['ip'] = client[2] + for key, value in client.items(): + payload[key] = value resp = server.post('/client/add', payload) + if resp.status_code != requests.codes.ok: - flash(_('ogServer: error adding client {}').format(client[0]), + flash(_('ogServer: error adding client {}').format(client['name']), category='error') return redirect(url_for('scopes')) + flash(_('Clients imported successfully'), category='info') return redirect(url_for('scopes')) -- cgit v1.2.3-18-g5258