Rework network config (#1001)
* Update network configuration * Rework network configuration * Update documentation * Fix flake8 * Update Co-authored-by: Daniel Girtler <girtler.daniel@gmail.com> Co-authored-by: Anton Hvornum <anton.feeds@gmail.com>
This commit is contained in:
parent
fa87d85708
commit
537b9cab03
3
.flake8
3
.flake8
|
|
@ -6,5 +6,4 @@ max-complexity = 40
|
|||
max-line-length = 236
|
||||
show-source = True
|
||||
statistics = True
|
||||
per-file-ignores = __init__.py:F401,F403,F405 simple_menu.py:C901,W503 guided.py:C901
|
||||
builtins = _
|
||||
per-file-ignores = __init__.py:F401,F403,F405 simple_menu.py:C901,W503 guided.py:C901 network_configuration.py:F821
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ def parse_unspecified_argument_list(unknowns :list, multiple :bool = False, erro
|
|||
print(f" We ignore the entry {element} as it isn't related to any argument")
|
||||
return config
|
||||
|
||||
def get_arguments():
|
||||
def get_arguments() -> Dict[str, Any]:
|
||||
""" The handling of parameters from the command line
|
||||
Is done on following steps:
|
||||
0) we create a dict to store the arguments and their values
|
||||
|
|
@ -203,13 +203,8 @@ def load_config():
|
|||
storage['gfx_driver_packages'] = AVAILABLE_GFX_DRIVERS.get(arguments.get('gfx_driver', None), None)
|
||||
if arguments.get('servers', None) is not None:
|
||||
storage['_selected_servers'] = arguments.get('servers', None)
|
||||
if nic_config := arguments.get('nic', {}):
|
||||
if isinstance(nic_config,str) or nic_config.get('nic', '') == 'Copy ISO network configuration to installation':
|
||||
arguments['nic'] = {'type': 'iso_config'}
|
||||
elif 'NetworkManager' in nic_config:
|
||||
arguments['nic'] = {'type': 'network_manager', 'NetworkManager': True}
|
||||
else:
|
||||
arguments['nic'] = {k if k != 'nic' else 'type': v for k, v in nic_config.items()}
|
||||
if arguments.get('nic', None) is not None:
|
||||
arguments['nic'] = NetworkConfiguration.parse_arguments(arguments.get('nic'))
|
||||
|
||||
def post_process_arguments(arguments):
|
||||
storage['arguments'] = arguments
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ __packages__ = ["base", "base-devel", "linux-firmware", "linux", "linux-lts", "l
|
|||
__accessibility_packages__ = ["brltty", "espeakup", "alsa-utils"]
|
||||
|
||||
from .pacman import run_pacman
|
||||
from .models.network_configuration import NetworkConfiguration
|
||||
|
||||
|
||||
class InstallationFile:
|
||||
|
|
@ -479,37 +480,35 @@ class Installer:
|
|||
def drop_to_shell(self) -> None:
|
||||
subprocess.check_call(f"/usr/bin/arch-chroot {self.target}", shell=True)
|
||||
|
||||
def configure_nic(self,
|
||||
nic :str,
|
||||
dhcp :bool = True,
|
||||
ip :Optional[str] = None,
|
||||
gateway :Optional[str] = None,
|
||||
dns :Optional[str] = None,
|
||||
*args :str,
|
||||
**kwargs :str
|
||||
) -> None:
|
||||
def configure_nic(self, network_config: NetworkConfiguration) -> None:
|
||||
from .systemd import Networkd
|
||||
|
||||
if dhcp:
|
||||
conf = Networkd(Match={"Name": nic}, Network={"DHCP": "yes"})
|
||||
if network_config.dhcp:
|
||||
conf = Networkd(Match={"Name": network_config.iface}, Network={"DHCP": "yes"})
|
||||
else:
|
||||
assert ip
|
||||
network = {"Address": network_config.ip}
|
||||
if network_config.gateway:
|
||||
network["Gateway"] = network_config.gateway
|
||||
if network_config.dns:
|
||||
dns = network_config.dns
|
||||
network["DNS"] = dns if isinstance(dns, list) else [dns]
|
||||
|
||||
network = {"Address": ip}
|
||||
if gateway:
|
||||
network["Gateway"] = gateway
|
||||
if dns:
|
||||
assert type(dns) == list
|
||||
network["DNS"] = dns
|
||||
|
||||
conf = Networkd(Match={"Name": nic}, Network=network)
|
||||
conf = Networkd(Match={"Name": network_config.iface}, Network=network)
|
||||
|
||||
for plugin in plugins.values():
|
||||
if hasattr(plugin, 'on_configure_nic'):
|
||||
if (new_conf := plugin.on_configure_nic(nic, dhcp, ip, gateway, dns)):
|
||||
new_conf = plugin.on_configure_nic(
|
||||
network_config.iface,
|
||||
network_config.dhcp,
|
||||
network_config.ip,
|
||||
network_config.gateway,
|
||||
network_config.dns
|
||||
)
|
||||
|
||||
if new_conf:
|
||||
conf = new_conf
|
||||
|
||||
with open(f"{self.target}/etc/systemd/network/10-{nic}.network", "a") as netconf:
|
||||
with open(f"{self.target}/etc/systemd/network/10-{network_config.iface}.network", "a") as netconf:
|
||||
netconf.write(str(conf))
|
||||
|
||||
def copy_iso_network_config(self, enable_services :bool = False) -> bool:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from typing import List, Optional, Dict
|
||||
|
||||
from ... import log
|
||||
|
||||
|
||||
class NicType(str, Enum):
|
||||
ISO = "iso"
|
||||
NM = "nm"
|
||||
MANUAL = "manual"
|
||||
|
||||
|
||||
@dataclass
|
||||
class NetworkConfiguration:
|
||||
type: NicType
|
||||
iface: str = None
|
||||
ip: str = None
|
||||
dhcp: bool = True
|
||||
gateway: str = None
|
||||
dns: List[str] = None
|
||||
|
||||
def __str__(self):
|
||||
if self.is_iso():
|
||||
return "Copy ISO configuration"
|
||||
elif self.is_network_manager():
|
||||
return "Use NetworkManager"
|
||||
elif self.is_manual():
|
||||
if self.dhcp:
|
||||
return f'iface={self.iface}, dhcp=auto'
|
||||
else:
|
||||
return f'iface={self.iface}, ip={self.ip}, dhcp=staticIp, gateway={self.gateway}, dns={self.dns}'
|
||||
else:
|
||||
return 'Unknown type'
|
||||
|
||||
# for json serialization when calling json.dumps(...) on this class
|
||||
def json(self):
|
||||
return self.__dict__
|
||||
|
||||
@classmethod
|
||||
def parse_arguments(cls, config: Dict[str, str]) -> Optional["NetworkConfiguration"]:
|
||||
nic_type = config.get('type', None)
|
||||
|
||||
if not nic_type:
|
||||
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
|
||||
|
||||
def is_network_manager(self) -> bool:
|
||||
return self.type == NicType.NM
|
||||
|
||||
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)
|
||||
installation.enable_service('systemd-networkd')
|
||||
installation.enable_service('systemd-resolved')
|
||||
|
|
@ -14,6 +14,7 @@ from typing import List, Any, Optional, Dict, Union, TYPE_CHECKING
|
|||
|
||||
# https://stackoverflow.com/a/39757388/929999
|
||||
from .menu.text_input import TextInput
|
||||
from .models.network_configuration import NetworkConfiguration, NicType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .disk.partition import Partition
|
||||
|
|
@ -450,11 +451,12 @@ def ask_additional_packages_to_install(pre_set_packages :List[str] = []) -> List
|
|||
return packages
|
||||
|
||||
|
||||
def ask_to_configure_network(preset :Dict[str, Any] = {}) -> Dict[str, Any]:
|
||||
# Optionally configure one network interface.
|
||||
# while 1:
|
||||
# {MAC: Ifname}
|
||||
def ask_to_configure_network(preset :Dict[str, Any] = {}) -> Optional[NetworkConfiguration]:
|
||||
"""
|
||||
Configure the network on the newly installed system
|
||||
"""
|
||||
interfaces = {
|
||||
'none': str(_('No network configuration')),
|
||||
'iso_config': str(_('Copy ISO network configuration to installation')),
|
||||
'network_manager': str(_('Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)')),
|
||||
**list_interfaces()
|
||||
|
|
@ -473,17 +475,17 @@ def ask_to_configure_network(preset :Dict[str, Any] = {}) -> Dict[str, Any]:
|
|||
except ValueError:
|
||||
pass
|
||||
|
||||
nic = Menu(_('Select one network interface to configure'), interfaces.values(),cursor_index=cursor_idx).run()
|
||||
nic = Menu(_('Select one network interface to configure'), interfaces.values(), cursor_index=cursor_idx, sort=False).run()
|
||||
|
||||
if not nic:
|
||||
return {}
|
||||
return None
|
||||
|
||||
# nic = network_manager_nt
|
||||
|
||||
if nic == interfaces['iso_config']:
|
||||
return {'type': 'iso_config'}
|
||||
if nic == interfaces['none']:
|
||||
return None
|
||||
elif nic == interfaces['iso_config']:
|
||||
return NetworkConfiguration(NicType.ISO)
|
||||
elif nic == interfaces['network_manager']:
|
||||
return {'type': 'network_manager', 'NetworkManager': True}
|
||||
return NetworkConfiguration(NicType.NM)
|
||||
else:
|
||||
# Current workaround:
|
||||
# For selecting modes without entering text within brackets,
|
||||
|
|
@ -543,10 +545,17 @@ def ask_to_configure_network(preset :Dict[str, Any] = {}) -> Dict[str, Any]:
|
|||
if len(dns_input):
|
||||
dns = dns_input.split(' ')
|
||||
|
||||
return {'type': nic, 'dhcp': False, 'ip': ip, 'gateway': gateway, 'dns': dns}
|
||||
return NetworkConfiguration(
|
||||
NicType.MANUAL,
|
||||
iface=nic,
|
||||
ip=ip,
|
||||
gateway=gateway,
|
||||
dns=dns,
|
||||
dhcp=False
|
||||
)
|
||||
else:
|
||||
# this will contain network iface names
|
||||
return {'type': nic}
|
||||
return NetworkConfiguration(NicType.MANUAL, iface=nic)
|
||||
|
||||
|
||||
def partition_overlap(partitions :list, start :str, end :str) -> bool:
|
||||
|
|
|
|||
|
|
@ -73,8 +73,7 @@ There are three different configuration files, all of which are optional.
|
|||
"keyboard-language": "us",
|
||||
"mirror-region": "Worldwide",
|
||||
"nic": {
|
||||
"NetworkManager": true,
|
||||
"nic": "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)"
|
||||
"type": "NM"
|
||||
},
|
||||
"ntp": true,
|
||||
"packages": ["docker", "git", "wget", "zsh"],
|
||||
|
|
@ -124,9 +123,13 @@ Options for ``--config``
|
|||
| | | "Worldwide" or "Sweden" | | Either takes a dictionary structure of region and a given set of mirrors. | |
|
||||
| | | | Or just a region and archinstall will source any mirrors for that region automatically | |
|
||||
+----------------------+--------------------------------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------+
|
||||
| nic | | { NetworkManager: <boolean> } | | Takes three different kind of options. Copy, NetworkManager or a nic name. | No |
|
||||
| | | { "eth0": {"address": "<ip>", "subnet": "255.0.0.0"}}| | Copy will copy the network configuration used in the live ISO. NetworkManager will | |
|
||||
| | | "Copy ISO network configuration to installation" | | install and configure `NetworkManager <https://wiki.archlinux.org/title/NetworkManager>`_ | |
|
||||
| nic | | { type: <ISO|NM|MANUAL> } | | Type must be one of ISO, NM, MANUAL. ISO will copy the configuration on the image, | No |
|
||||
| | | | | NM configures NetworkManager and MANUAL allows to specify custom configuration | |
|
||||
| | | { "iface": "eth0"} | | Only MANUAL: name of the interface | |
|
||||
| | | { "dhcp": <boolean>} | | Only MANUAL: If set to true DHCP auto will be setup and all further configs ignored | |
|
||||
| | | { "ip": <ip>} | | Only MANUAL: Ip address to set, is MANDATORY | |
|
||||
| | | { "gateway": <ip>} | | Only MANUAL: Optional gateway | |
|
||||
| | | { "dns": [<ip>]} | | Only MANUAL: Optional DNS servers | |
|
||||
+----------------------+--------------------------------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------+
|
||||
| ntp | <boolean> | Set to true to set-up ntp post install | No |
|
||||
+----------------------+--------------------------------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------+
|
||||
|
|
|
|||
|
|
@ -15,8 +15,7 @@
|
|||
}
|
||||
},
|
||||
"nic": {
|
||||
"NetworkManager": true,
|
||||
"nic": "Use NetworkManager (necessary to configure internet graphically in GNOME and KDE)"
|
||||
"type": "NM"
|
||||
},
|
||||
"ntp": true,
|
||||
"packages": [],
|
||||
|
|
@ -26,4 +25,4 @@
|
|||
"sys-encoding": "utf-8",
|
||||
"sys-language": "en_US",
|
||||
"timezone": "UTC"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
"keyboard-layout": "us",
|
||||
"mirror-region": "Worldwide",
|
||||
"nic": {
|
||||
"NetworkManager": true
|
||||
"type": "NM"
|
||||
},
|
||||
"ntp": true,
|
||||
"packages": ["docker", "git", "wget", "zsh"],
|
||||
|
|
|
|||
|
|
@ -145,11 +145,11 @@ def perform_installation(mountpoint):
|
|||
# Set mirrors used by pacstrap (outside of installation)
|
||||
if archinstall.arguments.get('mirror-region', None):
|
||||
archinstall.use_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors for the live medium
|
||||
|
||||
|
||||
# Retrieve list of additional repositories and set boolean values appropriately
|
||||
enable_testing = 'testing' in archinstall.arguments.get('additional-repositories', None)
|
||||
enable_multilib = 'multilib' in archinstall.arguments.get('additional-repositories', None)
|
||||
|
||||
|
||||
if installation.minimal_installation(testing=enable_testing, multilib=enable_multilib):
|
||||
installation.set_locale(archinstall.arguments['sys-language'], archinstall.arguments['sys-encoding'].upper())
|
||||
installation.set_hostname(archinstall.arguments['hostname'])
|
||||
|
|
@ -163,16 +163,10 @@ def perform_installation(mountpoint):
|
|||
|
||||
# If user selected to copy the current ISO network configuration
|
||||
# Perform a copy of the config
|
||||
if archinstall.arguments.get('nic', {}).get('type', '') == 'iso_config':
|
||||
installation.copy_iso_network_config(enable_services=True) # Sources the ISO network configuration to the install medium.
|
||||
elif archinstall.arguments.get('nic', {}).get('NetworkManager', False):
|
||||
installation.add_additional_packages("networkmanager")
|
||||
installation.enable_service('NetworkManager.service')
|
||||
# Otherwise, if a interface was selected, configure that interface
|
||||
elif archinstall.arguments.get('nic', {}):
|
||||
installation.configure_nic(**archinstall.arguments.get('nic', {}))
|
||||
installation.enable_service('systemd-networkd')
|
||||
installation.enable_service('systemd-resolved')
|
||||
network_config = archinstall.arguments.get('nic', None)
|
||||
|
||||
if network_config:
|
||||
network_config.config_installer(installation)
|
||||
|
||||
if archinstall.arguments.get('audio', None) is not None:
|
||||
installation.log(f"This audio server will be used: {archinstall.arguments.get('audio', None)}", level=logging.INFO)
|
||||
|
|
|
|||
|
|
@ -393,19 +393,10 @@ def os_setup(installation):
|
|||
if archinstall.arguments['swap']:
|
||||
installation.setup_swap('zram')
|
||||
|
||||
# If user selected to copy the current ISO network configuration
|
||||
# Perform a copy of the config
|
||||
if archinstall.arguments.get('nic', {}).get('type', '') == 'iso_config':
|
||||
installation.copy_iso_network_config(
|
||||
enable_services=True) # Sources the ISO network configuration to the install medium.
|
||||
elif archinstall.arguments.get('nic', {}).get('NetworkManager', False):
|
||||
installation.add_additional_packages("networkmanager")
|
||||
installation.enable_service('NetworkManager.service')
|
||||
# Otherwise, if a interface was selected, configure that interface
|
||||
elif archinstall.arguments.get('nic', {}):
|
||||
installation.configure_nic(**archinstall.arguments.get('nic', {}))
|
||||
installation.enable_service('systemd-networkd')
|
||||
installation.enable_service('systemd-resolved')
|
||||
network_config = archinstall.arguments.get('nic', None)
|
||||
|
||||
if network_config:
|
||||
network_config.config_installer(installation)
|
||||
|
||||
if archinstall.arguments.get('audio', None) is not None:
|
||||
installation.log(f"This audio server will be used: {archinstall.arguments.get('audio', None)}",level=logging.INFO)
|
||||
|
|
|
|||
24
schema.json
24
schema.json
|
|
@ -84,18 +84,18 @@
|
|||
"description": "Choose between NetworkManager, manual configuration, use systemd-networkd from the ISO or no configuration",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"NetworkManager": {
|
||||
"description": "<boolean>",
|
||||
"type": "boolean"
|
||||
},
|
||||
"interface-name": {
|
||||
"address": "ip address",
|
||||
"subnet": "255.255.255.0",
|
||||
"gateway": "ip address",
|
||||
"dns": "ip address"
|
||||
},
|
||||
"nic": "Copy ISO network configuration to installation",
|
||||
"nic": {}
|
||||
"type": "string",
|
||||
"iface": "string",
|
||||
"dhcp": "boolean",
|
||||
"ip": "string",
|
||||
"gateway": "string",
|
||||
"dns": {
|
||||
"description": "List of DNS servers",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ntp": {
|
||||
|
|
|
|||
Loading…
Reference in New Issue