From 477b5b120e120766d789a691fce60cec843aff43 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 22 Apr 2022 21:24:12 +1000 Subject: Support for multiple network interfaces (#1052) * Support for multiple network interfaces * Fix mypy * Fix flake8 Co-authored-by: Daniel Girtler --- archinstall/lib/models/network_configuration.py | 220 ++++++++++++++---------- 1 file changed, 127 insertions(+), 93 deletions(-) (limited to 'archinstall/lib/models/network_configuration.py') diff --git a/archinstall/lib/models/network_configuration.py b/archinstall/lib/models/network_configuration.py index eb4c25ee..16136177 100644 --- a/archinstall/lib/models/network_configuration.py +++ b/archinstall/lib/models/network_configuration.py @@ -2,7 +2,12 @@ from __future__ import annotations from dataclasses import dataclass from enum import Enum -from typing import List, Optional, Dict +from typing import List, Optional, Dict, Union, Any, TYPE_CHECKING + +from ..output import log + +if TYPE_CHECKING: + _: Any class NicType(str, Enum): @@ -14,11 +19,11 @@ class NicType(str, Enum): @dataclass class NetworkConfiguration: type: NicType - iface: str = None - ip: str = None + iface: Optional[str] = None + ip: Optional[str] = None dhcp: bool = True - gateway: str = None - dns: List[str] = None + gateway: Optional[str] = None + dns: Union[None, List[str]] = None def __str__(self): if self.is_iso(): @@ -37,63 +42,6 @@ class NetworkConfiguration: def json(self): return self.__dict__ - @classmethod - def parse_arguments(cls, config: Union[str,Dict[str, str]]) -> Optional["NetworkConfiguration"]: - from ... import log - - nic_type = config.get('type', None) - - if not nic_type: - # old style definitions - if isinstance(config,str): # is a ISO network - return NetworkConfiguration(NicType.ISO) - elif config.get('NetworkManager'): # is a network manager configuration - return NetworkConfiguration(NicType.NM) - elif 'ip' in config: - return NetworkConfiguration( - NicType.MANUAL, - iface=config.get('nic', ''), - ip=config.get('ip'), - gateway=config.get('gateway', ''), - dns=config.get('dns', []), - dhcp=False - ) - elif 'nic' in config: - return NetworkConfiguration( - NicType.MANUAL, - iface=config.get('nic', ''), - dhcp=True - ) - else: # not recognized - return None - - try: - type = NicType(nic_type) - except ValueError: - options = [e.value for e in NicType] - log(_('Unknown nic type: {}. Possible values are {}').format(nic_type, options), fg='red') - exit(1) - - if type == NicType.MANUAL: - if config.get('dhcp', False) or not any([config.get(v) for v in ['ip', 'gateway', 'dns']]): - return NetworkConfiguration(type, iface=config.get('iface', '')) - - ip = config.get('ip', '') - if not ip: - log('Manual nic configuration with no auto DHCP requires an IP address', fg='red') - exit(1) - - return NetworkConfiguration( - type, - iface=config.get('iface', ''), - ip=ip, - gateway=config.get('gateway', ''), - dns=config.get('dns', []), - dhcp=False - ) - else: - return NetworkConfiguration(type) - def is_iso(self) -> bool: return self.type == NicType.ISO @@ -103,37 +51,123 @@ class NetworkConfiguration: def is_manual(self) -> bool: return self.type == NicType.MANUAL - def config_installer(self, installation: 'Installer'): - # If user selected to copy the current ISO network configuration - # Perform a copy of the config - if self.is_iso(): - installation.copy_iso_network_config(enable_services=True) # Sources the ISO network configuration to the install medium. - elif self.is_network_manager(): - installation.add_additional_packages("networkmanager") - installation.enable_service('NetworkManager.service') - # Otherwise, if a interface was selected, configure that interface - elif self.is_manual(): - installation.configure_nic(self) + +class NetworkConfigurationHandler: + def __init__(self, config: Union[None, NetworkConfiguration, List[NetworkConfiguration]] = None): + self._configuration = config + + @property + def configuration(self): + return self._configuration + + def config_installer(self, installation: Any): + if self._configuration is None: + return + + if isinstance(self._configuration, list): + for config in self._configuration: + installation.configure_nic(config) + installation.enable_service('systemd-networkd') installation.enable_service('systemd-resolved') - - def get(self, key :str, default_value :Any = None) -> Any: - result = self.__getitem__(key) - if result is None: - return default_value - else: - return result - - def __getitem__(self, key :str) -> Any: - if key == 'type': - return self.type - elif key == 'iface': - return self.iface - elif key == 'gateway': - return self.gateway - elif key == 'dns': - return self.dns - elif key == 'dhcp': - return self.dhcp else: - raise KeyError(f"key {key} not available at NetworkConfiguration") + # If user selected to copy the current ISO network configuration + # Perform a copy of the config + if self._configuration.is_iso(): + installation.copy_iso_network_config( + enable_services=True) # Sources the ISO network configuration to the install medium. + elif self._configuration.is_network_manager(): + installation.add_additional_packages("networkmanager") + installation.enable_service('NetworkManager.service') + + def _backwards_compability_config(self, config: Union[str,Dict[str, str]]) -> Union[List[NetworkConfiguration], NetworkConfiguration, None]: + def get(config: Dict[str, str], key: str) -> List[str]: + if (value := config.get(key, None)) is not None: + return [value] + return [] + + if isinstance(config, str): # is a ISO network + return NetworkConfiguration(NicType.ISO) + elif config.get('NetworkManager'): # is a network manager configuration + return NetworkConfiguration(NicType.NM) + elif 'ip' in config: + return [NetworkConfiguration( + NicType.MANUAL, + iface=config.get('nic', ''), + ip=config.get('ip'), + gateway=config.get('gateway', ''), + dns=get(config, 'dns'), + dhcp=False + )] + elif 'nic' in config: + return [NetworkConfiguration( + NicType.MANUAL, + iface=config.get('nic', ''), + dhcp=True + )] + else: # not recognized + return None + + def _parse_manual_config(self, config: Dict[str, Any]) -> Union[None, List[NetworkConfiguration]]: + manual_configs: List = config.get('config', []) + + if not manual_configs: + return None + + if not isinstance(manual_configs, list): + log(_('Manual configuration setting must be a list')) + exit(1) + + configurations = [] + + for manual_config in manual_configs: + iface = manual_config.get('iface', None) + + if iface is None: + log(_('No iface specified for manual configuration')) + exit(1) + + if manual_config.get('dhcp', False) or not any([manual_config.get(v, '') for v in ['ip', 'gateway', 'dns']]): + configurations.append( + NetworkConfiguration(NicType.MANUAL, iface=iface) + ) + else: + ip = config.get('ip', '') + if not ip: + log(_('Manual nic configuration with no auto DHCP requires an IP address'), fg='red') + exit(1) + + configurations.append( + NetworkConfiguration( + NicType.MANUAL, + iface=iface, + ip=ip, + gateway=config.get('gateway', ''), + dns=config.get('dns', []), + dhcp=False + ) + ) + + return configurations + + def parse_arguments(self, config: Any): + nic_type = config.get('type', None) + + if not nic_type: + # old style definitions + network_config = self._backwards_compability_config(config) + if network_config: + return network_config + return None + + try: + type_ = NicType(nic_type) + except ValueError: + options = [e.value for e in NicType] + log(_('Unknown nic type: {}. Possible values are {}').format(nic_type, options), fg='red') + exit(1) + + if type_ != NicType.MANUAL: + self._configuration = NetworkConfiguration(type_) + else: # manual configuration settings + self._configuration = self._parse_manual_config(config) -- cgit v1.2.3-54-g00ecf