From 07d70a0a916b3c7ede34671603c1e964a1c7bf30 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 19:11:22 +0000 Subject: Added a simple INI handler, and a helper function under Installer().configure_nic() to help with nic configuration. Supports a crude DHCP configuration and a minimal static IP handler. --- .gitignore | 2 ++ archinstall/lib/installer.py | 19 +++++++++++++++++++ archinstall/lib/systemd.py | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 archinstall/lib/systemd.py diff --git a/.gitignore b/.gitignore index 5c83c4aa..955e7784 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ SAFETY_LOCK **/**.pkg.*.xz **/**archinstall-*.tar.gz **/**.zst +**/**.network +**/**.target diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 775de50a..c233a876 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -6,6 +6,7 @@ from .general import * from .user_interaction import * from .profiles import Profile from .mirrors import * +from .systemd import Networkd from .output import log, LOG_LEVELS from .storage import storage @@ -149,6 +150,24 @@ class Installer(): def arch_chroot(self, cmd, *args, **kwargs): return self.run_command(cmd) + def configure_nic(self, nic, dhcp=True, ip=None, gateway=None, dns=None, *args, **kwargs): + if dhcp: + conf = Networkd(Match={"Name": nic}, Network={"DHCP": "yes"}) + else: + assert ip + + network = {"Address": ip} + if gateway: + network["Gateway"] = gateway + if dns: + assert type(dns) == list + network["DNS"] = dns + + conf = Networkd(Match={"Name": nic}, Network=network) + + with open(f"{self.mountpoint}/etc/systemd/network/10-{nic}.network", "a") as netconf: + netconf.write(str(conf)) + def minimal_installation(self): ## Add nessecary packages if encrypting the drive ## (encrypted partitions default to btrfs for now, so we need btrfs-progs) diff --git a/archinstall/lib/systemd.py b/archinstall/lib/systemd.py new file mode 100644 index 00000000..edd75098 --- /dev/null +++ b/archinstall/lib/systemd.py @@ -0,0 +1,40 @@ +class Ini(): + def __init__(self, *args, **kwargs): + """ + Limited INI handler for now. + Supports multiple keywords through dictionary list items. + """ + self.kwargs = kwargs + + def __str__(self): + result = '' + first_row_done = False + for top_level in self.kwargs: + if first_row_done: + result += f"\n[{top_level}]\n" + else: + result += f"[{top_level}]\n" + first_row_done = True + + for key, val in self.kwargs[top_level].items(): + if type(val) == list: + for item in val: + result += f"{key}={item}\n" + else: + result += f"{key}={val}\n" + + return result + +class Systemd(Ini): + def __init__(self, *args, **kwargs): + """ + Placeholder class to do systemd specific setups. + """ + super(Systemd, self).__init__(*args, **kwargs) + +class Networkd(Systemd): + def __init__(self, *args, **kwargs): + """ + Placeholder class to do systemd-network specific setups. + """ + super(Networkd, self).__init__(*args, **kwargs) \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 72fb912b6b1593a9eea690be88034bd96dd3dcd9 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 20:13:26 +0000 Subject: Adding network support (questions) to guided.py according to #65. Previous commit added the functionality to configure the nic inside the installation. --- examples/guided.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/examples/guided.py b/examples/guided.py index c0fcd97b..a69cc622 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -49,6 +49,9 @@ def perform_installation(device, boot_partition, language, mirrors): installation.set_keyboard_language(language) installation.add_bootloader() + if archinstall.storage['_guided']['network']: + archinstall.configure_nic(**archinstall.storage['_guided']['network']) + if len(archinstall.storage['_guided']['packages']) and archinstall.storage['_guided']['packages'][0] != '': installation.add_additional_packages(archinstall.storage['_guided']['packages']) @@ -180,6 +183,33 @@ while 1: except archinstall.RequirementError as e: print(e) +# Optionally configure one network interface. +while 1: + interfaces = archinstall.list_interfaces() + archinstall.storage['_guided']['network'] = None + + nic = generic_select(interfaces, "Select one network interface to configure (leave blank to skip): ") + if nic: + mode = generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") + if mode == 'IP (static)': + while 1: + ip = input(f"Enter the IP and subnet for {nic} (example: 192.168.0.5/24): ").strip() + if ip: + break + else: + ArchInstall.log( + "You need to enter a valid IP in IP-config mode.", + level=archinstall.LOG_LEVELS.Warning, + bg='black', + fg='red' + ) + + gateway = input('Enter your gateway (router) IP address or leave blank for none: ').strip() + dns = input('Enter your DNS servers (space separated, blank for none): ').strip().split(' ') + + archinstall.storage['_guided']['network'] = {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns} + else: + archinstall.storage['_guided']['network'] = {'nic': nic} print() print('This is your chosen configuration:') -- cgit v1.2.3-54-g00ecf From be2dd2b3cdaa54421ddb71093b604ad39d702afa Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 20:15:58 +0000 Subject: Fix for generic_select() call. --- examples/guided.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index a69cc622..51ebeeef 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -188,9 +188,9 @@ while 1: interfaces = archinstall.list_interfaces() archinstall.storage['_guided']['network'] = None - nic = generic_select(interfaces, "Select one network interface to configure (leave blank to skip): ") + nic = archinstall.generic_select(interfaces, "Select one network interface to configure (leave blank to skip): ") if nic: - mode = generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") + mode = archinstall.generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") if mode == 'IP (static)': while 1: ip = input(f"Enter the IP and subnet for {nic} (example: 192.168.0.5/24): ").strip() -- cgit v1.2.3-54-g00ecf From abfeeb8dd0cadadbe38310e96a61e31088652d82 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 20:17:48 +0000 Subject: Asking user for interface-names rather than MAC address. Should probably print the current IP if any, which would make it easier to identify --- examples/guided.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 51ebeeef..4edc593e 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -185,10 +185,10 @@ while 1: # Optionally configure one network interface. while 1: - interfaces = archinstall.list_interfaces() + interfaces = archinstall.list_interfaces() # {MAC: Ifname} archinstall.storage['_guided']['network'] = None - nic = archinstall.generic_select(interfaces, "Select one network interface to configure (leave blank to skip): ") + nic = archinstall.generic_select(interfaces.values(), "Select one network interface to configure (leave blank to skip): ") if nic: mode = archinstall.generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") if mode == 'IP (static)': -- cgit v1.2.3-54-g00ecf From b3bcf54a2cb915b8dd9f59d6a85a5ea45f61fd96 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 20:20:46 +0000 Subject: Fixed generic_select() to accept (and break on) empty selects. --- archinstall/lib/user_interaction.py | 4 ++- examples/guided.py | 53 +++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 29dfaed2..fdbabe96 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -24,7 +24,9 @@ def generic_select(options, input_text="Select one of the above by index or abso print(f"{index}: {option}") selected_option = input(input_text) - if selected_option.isdigit(): + if len(selected_option.strip()) <= 0: + return None + elif selected_option.isdigit(): selected_option = options[int(selected_option)] elif selected_option in options: pass # We gave a correct absolute value diff --git a/examples/guided.py b/examples/guided.py index 4edc593e..039296c8 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -184,32 +184,33 @@ while 1: print(e) # Optionally configure one network interface. -while 1: - interfaces = archinstall.list_interfaces() # {MAC: Ifname} - archinstall.storage['_guided']['network'] = None - - nic = archinstall.generic_select(interfaces.values(), "Select one network interface to configure (leave blank to skip): ") - if nic: - mode = archinstall.generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") - if mode == 'IP (static)': - while 1: - ip = input(f"Enter the IP and subnet for {nic} (example: 192.168.0.5/24): ").strip() - if ip: - break - else: - ArchInstall.log( - "You need to enter a valid IP in IP-config mode.", - level=archinstall.LOG_LEVELS.Warning, - bg='black', - fg='red' - ) - - gateway = input('Enter your gateway (router) IP address or leave blank for none: ').strip() - dns = input('Enter your DNS servers (space separated, blank for none): ').strip().split(' ') - - archinstall.storage['_guided']['network'] = {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns} - else: - archinstall.storage['_guided']['network'] = {'nic': nic} +#while 1: +interfaces = archinstall.list_interfaces() # {MAC: Ifname} +archinstall.storage['_guided']['network'] = None + +nic = archinstall.generic_select(interfaces.values(), "Select one network interface to configure (leave blank to skip): ") +if nic: + mode = archinstall.generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") + if mode == 'IP (static)': + while 1: + ip = input(f"Enter the IP and subnet for {nic} (example: 192.168.0.5/24): ").strip() + if ip: + break + else: + ArchInstall.log( + "You need to enter a valid IP in IP-config mode.", + level=archinstall.LOG_LEVELS.Warning, + bg='black', + fg='red' + ) + + gateway = input('Enter your gateway (router) IP address or leave blank for none: ').strip() + dns = input('Enter your DNS servers (space separated, blank for none): ').strip().split(' ') + + archinstall.storage['_guided']['network'] = {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns} + else: + archinstall.storage['_guided']['network'] = {'nic': nic} + print() print('This is your chosen configuration:') -- cgit v1.2.3-54-g00ecf From 7288df57b7803fb6ca08ae40aa8a1d7ac683c7c4 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 20:23:13 +0000 Subject: Fixed DNS logic, since DNS might become [""]. --- examples/guided.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 039296c8..ba1a5ac2 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -204,8 +204,11 @@ if nic: fg='red' ) - gateway = input('Enter your gateway (router) IP address or leave blank for none: ').strip() - dns = input('Enter your DNS servers (space separated, blank for none): ').strip().split(' ') + if gateway = input('Enter your gateway (router) IP address or leave blank for none: ').strip() + + dns = None + if len(dns := input('Enter your DNS servers (space separated, blank for none): ').strip()): + dns = dns.split(' ') archinstall.storage['_guided']['network'] = {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns} else: -- cgit v1.2.3-54-g00ecf From 065da563fb7e45d9bf90562ee6af522ce6014808 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 20:23:50 +0000 Subject: configure_nic() is on the installation, not a generic function. --- examples/guided.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index ba1a5ac2..2f22bf6a 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -50,7 +50,7 @@ def perform_installation(device, boot_partition, language, mirrors): installation.add_bootloader() if archinstall.storage['_guided']['network']: - archinstall.configure_nic(**archinstall.storage['_guided']['network']) + installation.configure_nic(**archinstall.storage['_guided']['network']) if len(archinstall.storage['_guided']['packages']) and archinstall.storage['_guided']['packages'][0] != '': installation.add_additional_packages(archinstall.storage['_guided']['packages']) -- cgit v1.2.3-54-g00ecf From 092f2d3240697418185b210f3050d2de53ac2a20 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 20:25:01 +0000 Subject: Revert gateway to None if the string is zero-len. --- examples/guided.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index 2f22bf6a..84045b83 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -204,7 +204,8 @@ if nic: fg='red' ) - if gateway = input('Enter your gateway (router) IP address or leave blank for none: ').strip() + if not len(gateway := input('Enter your gateway (router) IP address or leave blank for none: ').strip()): + gateway = None dns = None if len(dns := input('Enter your DNS servers (space separated, blank for none): ').strip()): -- cgit v1.2.3-54-g00ecf From cb6ab2c28ba9ae2088ae3f6a32720159469d550e Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 20:26:21 +0000 Subject: Logical issue with how I stripped the response. It overrode the None but never reverted it back. --- examples/guided.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 84045b83..f1dff059 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -208,8 +208,8 @@ if nic: gateway = None dns = None - if len(dns := input('Enter your DNS servers (space separated, blank for none): ').strip()): - dns = dns.split(' ') + if len(dns_input := input('Enter your DNS servers (space separated, blank for none): ').strip()): + dns = dns_input.split(' ') archinstall.storage['_guided']['network'] = {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns} else: -- cgit v1.2.3-54-g00ecf From 9ad56f3462f8de25e8cae8905a5b04e228aef071 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 20:28:51 +0000 Subject: Created a default package entry in the _guided storage. --- examples/guided.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index f1dff059..9c5f083e 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -52,7 +52,7 @@ def perform_installation(device, boot_partition, language, mirrors): if archinstall.storage['_guided']['network']: installation.configure_nic(**archinstall.storage['_guided']['network']) - if len(archinstall.storage['_guided']['packages']) and archinstall.storage['_guided']['packages'][0] != '': + if archinstall.storage['_guided']['packages'] and archinstall.storage['_guided']['packages'][0] != '': installation.add_additional_packages(archinstall.storage['_guided']['packages']) if 'profile' in archinstall.storage['_guided'] and len(profile := archinstall.storage['_guided']['profile']['path'].strip()): @@ -170,6 +170,7 @@ while 1: break # Additional packages (with some light weight error handling for invalid package names) +archinstall.storage['_guided']['packages'] = None while 1: packages = [package for package in input('Additional packages aside from base (space separated): ').split(' ') if len(package)] -- cgit v1.2.3-54-g00ecf From a9099cbb466ef3db0e44779b0f9108674632e4c4 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 20:37:36 +0000 Subject: Added key error correction again by creating default value. Should do this for all of them really. --- examples/guided.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 9c5f083e..95b5d173 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -58,14 +58,15 @@ def perform_installation(device, boot_partition, language, mirrors): if 'profile' in archinstall.storage['_guided'] and len(profile := archinstall.storage['_guided']['profile']['path'].strip()): installation.install_profile(profile) - for user in archinstall.storage['_guided']['users']: - password = users[user] + if archinstall.storage['_guided']['users']: + for user in archinstall.storage['_guided']['users']: + password = users[user] - sudo = False - if 'root_pw' not in archinstall.storage['_guided_hidden'] or len(archinstall.storage['_guided_hidden']['root_pw'].strip()) == 0: - sudo = True + sudo = False + if 'root_pw' not in archinstall.storage['_guided_hidden'] or len(archinstall.storage['_guided_hidden']['root_pw'].strip()) == 0: + sudo = True - installation.user_create(user, password, sudo=sudo) + installation.user_create(user, password, sudo=sudo) if 'root_pw' in archinstall.storage['_guided_hidden'] and archinstall.storage['_guided_hidden']['root_pw']: installation.user_set_pw('root', archinstall.storage['_guided_hidden']['root_pw']) @@ -124,6 +125,7 @@ new_user_text = 'Any additional users to install (leave blank for no users): ' if len(root_pw.strip()) == 0: new_user_text = 'Create a super-user with sudo privileges: ' +archinstall.storage['_guided']['users'] = None while 1: new_user = input(new_user_text) if len(new_user.strip()) == 0: -- cgit v1.2.3-54-g00ecf From 72f9c07e439eb2dac0bfc385db4b465fb9c44b7a Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 20:44:05 +0000 Subject: Forgot to enable systemd-networkd service. --- examples/guided.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/guided.py b/examples/guided.py index 95b5d173..6c8f59c8 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -51,6 +51,7 @@ def perform_installation(device, boot_partition, language, mirrors): if archinstall.storage['_guided']['network']: installation.configure_nic(**archinstall.storage['_guided']['network']) + installation.enable_service('systemd-networkd') if archinstall.storage['_guided']['packages'] and archinstall.storage['_guided']['packages'][0] != '': installation.add_additional_packages(archinstall.storage['_guided']['packages']) -- cgit v1.2.3-54-g00ecf From f6460b8634d2ac3bbdec5e7dc542b07ac1badea5 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 22:11:13 +0000 Subject: Fixed a bug where no locale generated a hang because loadkeys needs at least one option in set_keyboard_language() --- examples/guided.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 6c8f59c8..8378fc6b 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -82,8 +82,8 @@ archinstall.sys_command(f'cryptsetup close /dev/mapper/luksloop', suppress_error will we continue with the actual installation steps. """ -keyboard_language = archinstall.select_language(archinstall.list_keyboard_languages()) -archinstall.set_keyboard_language(keyboard_language) +if len(keyboard_language := archinstall.select_language(archinstall.list_keyboard_languages()).strip()): + archinstall.set_keyboard_language(keyboard_language) # Create a storage structure for all our information. # We'll print this right before the user gets informed about the formatting timer. -- cgit v1.2.3-54-g00ecf From b00f307a287ef7ef32d5c9988d79cf60d09c26ae Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 22:18:22 +0000 Subject: Added minor error handling in installer.set_keyboard_language() --- archinstall/lib/installer.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index c233a876..543f2ca3 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -292,7 +292,8 @@ class Installer(): pass def set_keyboard_language(self, language): - with open(f'{self.mountpoint}/etc/vconsole.conf', 'w') as vconsole: - vconsole.write(f'KEYMAP={language}\n') - vconsole.write(f'FONT=lat9w-16\n') + if len(language.strip()): + with open(f'{self.mountpoint}/etc/vconsole.conf', 'w') as vconsole: + vconsole.write(f'KEYMAP={language}\n') + vconsole.write(f'FONT=lat9w-16\n') return True \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 4dd20ae4d4abeed916c0d1271a637dcb3c80b9a6 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 11 Nov 2020 22:23:26 +0000 Subject: Fixed default-variable setup bug. --- examples/guided.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index 8378fc6b..69162244 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -135,7 +135,7 @@ while 1: continue break - if 'users' not in archinstall.storage['_guided']: + if not archinstall.storage['_guided']['users']: archinstall.storage['_guided']['users'] = [] archinstall.storage['_guided']['users'].append(new_user) -- cgit v1.2.3-54-g00ecf