Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall/lib/interactions/network_menu.py
diff options
context:
space:
mode:
Diffstat (limited to 'archinstall/lib/interactions/network_menu.py')
-rw-r--r--archinstall/lib/interactions/network_menu.py159
1 files changed, 159 insertions, 0 deletions
diff --git a/archinstall/lib/interactions/network_menu.py b/archinstall/lib/interactions/network_menu.py
new file mode 100644
index 00000000..14fc5785
--- /dev/null
+++ b/archinstall/lib/interactions/network_menu.py
@@ -0,0 +1,159 @@
+from __future__ import annotations
+
+import ipaddress
+from typing import Any, Optional, TYPE_CHECKING, List, Dict
+
+from ..menu import MenuSelectionType, TextInput
+from ..models.network_configuration import NetworkConfiguration, NicType, Nic
+
+from ..networking import list_interfaces
+from ..output import FormattedOutput, warn
+from ..menu import ListManager, Menu
+
+if TYPE_CHECKING:
+ _: Any
+
+
+class ManualNetworkConfig(ListManager):
+ """
+ subclass of ListManager for the managing of network configurations
+ """
+
+ def __init__(self, prompt: str, preset: List[Nic]):
+ self._actions = [
+ str(_('Add interface')),
+ str(_('Edit interface')),
+ str(_('Delete interface'))
+ ]
+ super().__init__(prompt, preset, [self._actions[0]], self._actions[1:])
+
+ def reformat(self, data: List[Nic]) -> Dict[str, Optional[Nic]]:
+ table = FormattedOutput.as_table(data)
+ rows = table.split('\n')
+
+ # these are the header rows of the table and do not map to any User obviously
+ # we're adding 2 spaces as prefix because the menu selector '> ' will be put before
+ # the selectable rows so the header has to be aligned
+ display_data: Dict[str, Optional[Nic]] = {f' {rows[0]}': None, f' {rows[1]}': None}
+
+ for row, iface in zip(rows[2:], data):
+ row = row.replace('|', '\\|')
+ display_data[row] = iface
+
+ return display_data
+
+ def selected_action_display(self, nic: Nic) -> str:
+ return nic.iface if nic.iface else ''
+
+ def handle_action(self, action: str, entry: Optional[Nic], data: List[Nic]):
+ if action == self._actions[0]: # add
+ iface = self._select_iface(data)
+ if iface:
+ nic = Nic(iface=iface)
+ nic = self._edit_iface(nic)
+ data += [nic]
+ elif entry:
+ if action == self._actions[1]: # edit interface
+ data = [d for d in data if d.iface != entry.iface]
+ data.append(self._edit_iface(entry))
+ elif action == self._actions[2]: # delete
+ data = [d for d in data if d != entry]
+
+ return data
+
+ def _select_iface(self, data: List[Nic]) -> Optional[str]:
+ all_ifaces = list_interfaces().values()
+ existing_ifaces = [d.iface for d in data]
+ available = set(all_ifaces) - set(existing_ifaces)
+ choice = Menu(str(_('Select interface to add')), list(available), skip=True).run()
+
+ if choice.type_ == MenuSelectionType.Skip:
+ return None
+
+ return choice.single_value
+
+ def _edit_iface(self, edit_nic: Nic) -> Nic:
+ iface_name = edit_nic.iface
+ modes = ['DHCP (auto detect)', 'IP (static)']
+ default_mode = 'DHCP (auto detect)'
+
+ prompt = _('Select which mode to configure for "{}" or skip to use default mode "{}"').format(iface_name, default_mode)
+ mode = Menu(prompt, modes, default_option=default_mode, skip=False).run()
+
+ if mode.value == 'IP (static)':
+ while 1:
+ prompt = _('Enter the IP and subnet for {} (example: 192.168.0.5/24): ').format(iface_name)
+ ip = TextInput(prompt, edit_nic.ip).run().strip()
+ # Implemented new check for correct IP/subnet input
+ try:
+ ipaddress.ip_interface(ip)
+ break
+ except ValueError:
+ warn("You need to enter a valid IP in IP-config mode")
+
+ # Implemented new check for correct gateway IP address
+ gateway = None
+
+ while 1:
+ gateway = TextInput(
+ _('Enter your gateway (router) IP address or leave blank for none: '),
+ edit_nic.gateway
+ ).run().strip()
+ try:
+ if len(gateway) > 0:
+ ipaddress.ip_address(gateway)
+ break
+ except ValueError:
+ warn("You need to enter a valid gateway (router) IP address")
+
+ if edit_nic.dns:
+ display_dns = ' '.join(edit_nic.dns)
+ else:
+ display_dns = None
+ dns_input = TextInput(_('Enter your DNS servers (space separated, blank for none): '), display_dns).run().strip()
+
+ dns = []
+ if len(dns_input):
+ dns = dns_input.split(' ')
+
+ return Nic(iface=iface_name, ip=ip, gateway=gateway, dns=dns, dhcp=False)
+ else:
+ # this will contain network iface names
+ return Nic(iface=iface_name)
+
+
+def ask_to_configure_network(preset: Optional[NetworkConfiguration]) -> Optional[NetworkConfiguration]:
+ """
+ Configure the network on the newly installed system
+ """
+ options = {n.display_msg(): n for n in NicType}
+ preset_val = preset.type.display_msg() if preset else None
+ warning = str(_('Are you sure you want to reset this setting?'))
+
+ choice = Menu(
+ _('Select one network interface to configure'),
+ list(options.keys()),
+ preset_values=preset_val,
+ sort=False,
+ allow_reset=True,
+ allow_reset_warning_msg=warning
+ ).run()
+
+ match choice.type_:
+ case MenuSelectionType.Skip: return preset
+ case MenuSelectionType.Reset: return None
+ case MenuSelectionType.Selection:
+ nic_type = options[choice.single_value]
+
+ match nic_type:
+ case NicType.ISO:
+ return NetworkConfiguration(NicType.ISO)
+ case NicType.NM:
+ return NetworkConfiguration(NicType.NM)
+ case NicType.MANUAL:
+ preset_nics = preset.nics if preset else []
+ nics = ManualNetworkConfig('Configure interfaces', preset_nics).run()
+ if nics:
+ return NetworkConfiguration(NicType.MANUAL, nics)
+
+ return preset