From fc0dbe8ae95ee4874b4ec04e2e27a759c109db42 Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Wed, 6 Sep 2023 18:20:12 +0200 Subject: [PATCH] network: use consolidated s390 device configuration (#1802482,#1937049) Implements the znet part of referenced bugs. Depends on https://github.com/ibm-s390-linux/s390-tools commit 73f51e45a8c4 ("zdev: add helper to convert from zdev config to rd.znet"). The spec file already reflects the new dependency on `zdev-to-rd.znet` in a new version of the s390 architecture specific sub-package s390utils-core. Dracut commit ("feat(znet): use zdev for consolidated device configuration"), replaces the distribution-specific persistent configuration of s390 (channel-attached) network devices with a common consolidated mechanism using chzdev from s390-tools. So there is no more ccw.conf nor s390-specific low-level network config in NetworkManager connections nor ifcfg files. The spec file update reflects this new dependency on the updated dracut module "znet" in a new version of the dracut-network sub-package. Therefore, drop NETTYPE and OPTIONS. Keep SUBCHANNELS nonetheless because it can still serve as a matching key for NM connections. Delegate the generation of rd.znet statements to a helper tool from s390-tools, which gets its low-level config information from the consolidated mechanism using chzdev. There are two different code paths involved: * Root-fs on something (such as iSCSI or NFS) that depends on znet =>_get_dracut_znet_argument_from_connection(). Related earlier commits: commit fa174ab0e7b1 ("Write rd_CCW when root fs is on a network device on s390x (#577193)") and lately replacing former code: commit f85682f4b6b4 ("network module: add support for getting dracut arguments") commit 7cf4d6492f4c ("network module: use network module to get dracut arguments") and finally replacing initscripts ifcfg by NetworkManager connection: commit 840c984fca65 ("network: generate dracut arguments from connections (#1751189)") (Note that this generated rd.znet is independent of the (last) one just inherited from the boot parameters between commit 64fb10673441 ("Preserve network args on s390x.") and commit a4ba9aec1031 ("Do not pass rd.znet on to installed system unconditionally").) * Configure znet on boot with rd.znet= but without any corresponding ip= and instead use the kickstart command "network" to perform high-level configuration of the network interface created with rd.znet. This creates a non-initramfs NM connection. => pyanaconda.modules.network.initialization.ApplyKickstartTask.run => pyanaconda.modules.network.nm_client.add_connection_from_ksdata => pyanaconda.modules.network.nm_client.create_connections_from_ksdata => get_s390_settings() and _update_wired_connection_with_s390_settings() (In contrast, early initrd network setups get both the low-level s390 config and high-level interface config via nm-initrd-generator, which parses rd.znet= as well as ip=.) Signed-off-by: Steffen Maier --- anaconda.spec.in | 3 +- pyanaconda/modules/network/nm_client.py | 20 ++++--------- pyanaconda/modules/network/utils.py | 19 ------------ .../network/test_module_network_nm_client.py | 30 +++++++++---------- 4 files changed, 21 insertions(+), 51 deletions(-) diff --git a/anaconda.spec.in b/anaconda.spec.in index 1728f634ee85..51b7ca26578a 100644 --- a/anaconda.spec.in +++ b/anaconda.spec.in @@ -26,7 +26,7 @@ Source0: https://github.com/rhinstaller/%{name}/releases/download/%{name}-%{vers %define dasbusver 1.3 %define dbusver 1.2.3 %define dnfver 3.6.0 -%define dracutver 034-7 +%define dracutver FIXME %define fcoeutilsver 1.0.12-3.20100323git %define gettextver 0.19.8 %define gtk3ver 3.22.17 @@ -120,6 +120,7 @@ Requires: teamd %ifarch s390 s390x Requires: openssh Requires: s390utils-core >= %{s390utilscorever} +Requires: dracut-network >= %{dracutver} %endif Requires: NetworkManager >= %{nmver} Requires: NetworkManager-libnm >= %{nmver} diff --git a/pyanaconda/modules/network/nm_client.py b/pyanaconda/modules/network/nm_client.py index 21282c580c49..a6f1efe89573 100644 --- a/pyanaconda/modules/network/nm_client.py +++ b/pyanaconda/modules/network/nm_client.py @@ -35,6 +35,7 @@ from pyanaconda.modules.network.utils import get_s390_settings, netmask2prefix, prefix2netmask from pyanaconda.modules.network.config_file import is_config_file_for_system from pyanaconda.core.dbus import SystemBus +from pyanaconda.core import util from pyanaconda.anaconda_loggers import get_module_logger log = get_module_logger(__name__) @@ -437,12 +438,6 @@ def _update_wired_connection_with_s390_settings(connection, s390cfg): if s390cfg['SUBCHANNELS']: subchannels = s390cfg['SUBCHANNELS'].split(",") s_wired.props.s390_subchannels = subchannels - if s390cfg['NETTYPE']: - s_wired.props.s390_nettype = s390cfg['NETTYPE'] - if s390cfg['OPTIONS']: - opts = s390cfg['OPTIONS'].split(" ") - opts_dict = {k: v for k, v in (o.split("=") for o in opts)} - s_wired.props.s390_options = opts_dict def _create_new_connection(network_data, device_name): @@ -1376,15 +1371,10 @@ def _get_dracut_znet_argument_from_connection(connection): argument = "" wired_setting = connection.get_setting_wired() if wired_setting and is_s390(): - nettype = wired_setting.get_s390_nettype() - # get_s390_subchannels() returns a list of subchannels - subchannels = wired_setting.get_s390_subchannels() - if nettype and subchannels: - argument = "rd.znet={},{}".format(nettype, ",".join(subchannels)) - options = wired_setting.get_property(NM.SETTING_WIRED_S390_OPTIONS) - if options: - options_string = ','.join("{}={}".format(key, val) for key, val in options.items()) - argument += ",{}".format(options_string) + devspec = util.execWithCapture("/lib/s390-tools/zdev-to-rd.znet", + ["persistent", + connection.get_interface_name()]).strip() + argument = "rd.znet={}".format(devspec) return argument diff --git a/pyanaconda/modules/network/utils.py b/pyanaconda/modules/network/utils.py index ec5c361f8370..710446870ec6 100644 --- a/pyanaconda/modules/network/utils.py +++ b/pyanaconda/modules/network/utils.py @@ -34,8 +34,6 @@ def get_s390_settings(devname): cfg = { 'SUBCHANNELS': '', - 'NETTYPE': '', - 'OPTIONS': '' } subchannels = [] @@ -45,23 +43,6 @@ def get_s390_settings(devname): return cfg cfg['SUBCHANNELS'] = ','.join(subchannels) - # Example of the ccw.conf file content: - # qeth,0.0.0900,0.0.0901,0.0.0902,layer2=0,portname=FOOBAR,portno=0 - # - # SUBCHANNELS="0.0.0900,0.0.0901,0.0.0902" - # NETTYPE="qeth" - # OPTIONS="layer2=1 portname=FOOBAR portno=0" - if not os.path.exists('/run/install/ccw.conf'): - return cfg - with open('/run/install/ccw.conf') as f: - # pylint: disable=redefined-outer-name - for line in f: - if cfg['SUBCHANNELS'] in line: - items = line.strip().split(',') - cfg['NETTYPE'] = items[0] - cfg['OPTIONS'] = " ".join(i for i in items[1:] if '=' in i) - break - return cfg diff --git a/tests/unit_tests/pyanaconda_tests/modules/network/test_module_network_nm_client.py b/tests/unit_tests/pyanaconda_tests/modules/network/test_module_network_nm_client.py index 3e165a038eef..e95fec6acc7b 100644 --- a/tests/unit_tests/pyanaconda_tests/modules/network/test_module_network_nm_client.py +++ b/tests/unit_tests/pyanaconda_tests/modules/network/test_module_network_nm_client.py @@ -116,17 +116,20 @@ def test_get_ports_from_connections(self, get_iface_from_connection): assert get_ports_from_connections(nm_client, "team", [TEAM1_UUID]) == \ set([("ens11", "ens11", ENS11_UUID)]) + @patch("pyanaconda.modules.network.nm_client._get_dracut_znet_argument_from_connection") @patch("pyanaconda.modules.network.nm_client.get_connections_available_for_iface") @patch("pyanaconda.modules.network.nm_client.get_ports_from_connections") @patch("pyanaconda.modules.network.nm_client.is_s390") def test_get_dracut_arguments_from_connection(self, is_s390, get_ports_from_connections_mock, - get_connections_available_for_iface): + get_connections_available_for_iface, + _get_dracut_znet_argument_from_connection): nm_client = Mock() CON_UUID = "44755f4c-ee12-45b4-ba5e-e10f83de51af" # IPv4 config auto, IPv6 config auto, mac address specified is_s390.return_value = False + _get_dracut_znet_argument_from_connection.return_value = "" ip4_config_attrs = { "get_method.return_value": NM.SETTING_IP4_CONFIG_METHOD_AUTO, } @@ -162,6 +165,8 @@ def test_get_dracut_arguments_from_connection(self, is_s390, get_ports_from_conn # IPv4 config static, mac address not specified, s390 is_s390.return_value = True + _get_dracut_znet_argument_from_connection.return_value = \ + "rd.znet=qeth,0.0.0900,0.0.0901,0.0.0902,layer2=1,portname=FOOBAR,portno=0" address_attrs = { "get_address.return_value": "10.34.39.44", "get_prefix.return_value": 24, @@ -176,11 +181,6 @@ def test_get_dracut_arguments_from_connection(self, is_s390, get_ports_from_conn ip4_config = self._get_mock_objects_from_attrs([ip4_config_attrs])[0] wired_setting_attrs = { "get_mac_address.return_value": None, - "get_s390_nettype.return_value": "qeth", - "get_s390_subchannels.return_value": ["0.0.0900", "0.0.0901", "0.0.0902"], - "get_property.return_value": {"layer2": "1", - "portname": "FOOBAR", - "portno": "0"}, } wired_setting = self._get_mock_objects_from_attrs([wired_setting_attrs])[0] cons_attrs = [ @@ -199,6 +199,7 @@ def test_get_dracut_arguments_from_connection(self, is_s390, get_ports_from_conn # IPv6 config dhcp is_s390.return_value = False + _get_dracut_znet_argument_from_connection.return_value = "" ip6_config_attrs = { "get_method.return_value": NM.SETTING_IP6_CONFIG_METHOD_DHCP, } @@ -222,6 +223,7 @@ def test_get_dracut_arguments_from_connection(self, is_s390, get_ports_from_conn # IPv6 config manual is_s390.return_value = False + _get_dracut_znet_argument_from_connection.return_value = "" address_attrs = { "get_address.return_value": "2001::5", "get_prefix.return_value": 64, @@ -253,6 +255,7 @@ def test_get_dracut_arguments_from_connection(self, is_s390, get_ports_from_conn # IPv4 config auto, team is_s390.return_value = False + _get_dracut_znet_argument_from_connection.return_value = "" ip4_config_attrs = { "get_method.return_value": NM.SETTING_IP4_CONFIG_METHOD_AUTO, } @@ -279,6 +282,8 @@ def test_get_dracut_arguments_from_connection(self, is_s390, get_ports_from_conn # IPv4 config auto, vlan, s390, parent specified by interface name is_s390.return_value = True + _get_dracut_znet_argument_from_connection.return_value = \ + "rd.znet=qeth,0.0.0900,0.0.0901,0.0.0902,layer2=1,portname=FOOBAR,portno=0" ip4_config_attrs = { "get_method.return_value": NM.SETTING_IP4_CONFIG_METHOD_AUTO, } @@ -300,11 +305,6 @@ def test_get_dracut_arguments_from_connection(self, is_s390, get_ports_from_conn # Mock parent connection wired_setting_attrs = { "get_mac_address.return_value": None, - "get_s390_nettype.return_value": "qeth", - "get_s390_subchannels.return_value": ["0.0.0900", "0.0.0901", "0.0.0902"], - "get_property.return_value": {"layer2": "1", - "portname": "FOOBAR", - "portno": "0"}, } wired_setting = self._get_mock_objects_from_attrs([wired_setting_attrs])[0] parent_cons_attrs = [ @@ -326,6 +326,7 @@ def test_get_dracut_arguments_from_connection(self, is_s390, get_ports_from_conn # IPv4 config auto, vlan, parent specified by connection uuid VLAN_PARENT_UUID = "5e6ead30-d133-4c8c-ba59-818c5ced6a7c" is_s390.return_value = False + _get_dracut_znet_argument_from_connection.return_value = "" ip4_config_attrs = { "get_method.return_value": NM.SETTING_IP4_CONFIG_METHOD_AUTO, } @@ -361,6 +362,8 @@ def test_get_dracut_arguments_from_connection(self, is_s390, get_ports_from_conn # IPv4 config auto, vlan, parent specified by connection uuid, s390 (we # need the parent connection in s390 case, not only parent iface) is_s390.return_value = True + _get_dracut_znet_argument_from_connection.return_value = \ + "rd.znet=qeth,0.0.0900,0.0.0901,0.0.0902,layer2=1,portname=FOOBAR,portno=0" ip4_config_attrs = { "get_method.return_value": NM.SETTING_IP4_CONFIG_METHOD_AUTO, } @@ -382,11 +385,6 @@ def test_get_dracut_arguments_from_connection(self, is_s390, get_ports_from_conn # Mock parent connection wired_setting_attrs = { "get_mac_address.return_value": None, - "get_s390_nettype.return_value": "qeth", - "get_s390_subchannels.return_value": ["0.0.0900", "0.0.0901", "0.0.0902"], - "get_property.return_value": {"layer2": "1", - "portname": "FOOBAR", - "portno": "0"}, } wired_setting = self._get_mock_objects_from_attrs([wired_setting_attrs])[0] parent_cons_attrs = [