#!/usr/bin/python3 -cimport os, sys; os.execv(os.path.dirname(sys.argv[1]) + "/../common/pywrap", sys.argv)## Copyright (C) 2013 Red Hat, Inc.# SPDX-License-Identifier: LGPL-2.1-or-laterimport netlibimport testlibfrom lib.constants import TEST_OS_DEFAULTclass TestNetworkingSettings(netlib.NetworkCase):provision = {"machine1": {},"machine2": {"image": TEST_OS_DEFAULT, "address": "10.111.113.2/20", "dhcp": True}}def testNoConnectionSettings(self):b = self.browserm = self.machineself.login_and_go("/network")b.wait_visible("#networking")iface = self.add_iface(activate=False)self.wait_for_iface(iface, active=False)# checkpoints are realtime sensitive, avoid long NM operationsself.settle_cpu()self.select_iface(iface)b.wait_visible("#network-interface")# Check that there is no connection for the devicecons = m.execute(f"nmcli -t -m tabular -f CONNECTIONS.AVAILABLE-CONNECTION-PATHS dev show {iface}")self.assertEqual(cons.strip(), "")# Edit and apply the ghost settingsself.configure_iface_setting('IPv4')b.wait_visible("#network-ip-settings-dialog")b.select_from_dropdown("#network-ip-settings-select-method", "manual")b.set_input_text('#network-ip-settings-address-0', "1.2.3.4")b.set_input_text('#network-ip-settings-netmask-0', "24")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")self.wait_for_iface_setting('IPv4', 'Address 1.2.3.4/24')self.toggle_onoff("label[for='interface-switch']")def assert_connection_setting(con_id, field, value):self.assertEqual(m.execute(f'nmcli -m tabular -t -f {field} con show "{con_id}"').strip(),value)# Check that we now have connection settingscon_id = testlib.wait(lambda: self.iface_con_id(iface))assert_connection_setting(con_id, "ipv4.method", "manual")# The interface will be activated. Deactivate it.self.wait_for_iface_setting('Status', '1.2.3.4/24')self.toggle_onoff("label[for='interface-switch']")self.wait_for_iface_setting('Status', 'Inactive')# Delete the connection settings again and wait for the ghost# settings to be re-created.m.execute(f'nmcli con del "{con_id}"')self.wait_for_iface_setting('IPv4', 'Automatic')# Activate with ghost settingsself.toggle_onoff("label[for='interface-switch']")self.wait_for_iface_setting('Status', '10.111.')# Check again that we now have connection settingscon_id = testlib.wait(lambda: self.iface_con_id(iface))assert_connection_setting(con_id, "ipv4.method", "auto")# Change some more settings and check that the actual config# and dialog reflects the changeself.configure_iface_setting('IPv4')b.wait_visible("#network-ip-settings-dialog")self.wait_onoff("[data-field=dns]", val=True)self.toggle_onoff("[data-field=dns]")self.wait_onoff("[data-field=dns_search]", val=False)b.click("#network-ip-settings-dns-add")b.set_input_text("#network-ip-settings-dns-server-0", "1.2.3.4")b.click("#network-ip-settings-dns-search-add")b.set_input_text("#network-ip-settings-search-domain-0", "foo.com")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")assert_connection_setting(con_id, "ipv4.ignore-auto-dns", "yes")assert_connection_setting(con_id, "ipv4.dns", "1.2.3.4")assert_connection_setting(con_id, "ipv4.dns-search", "foo.com")self.configure_iface_setting('IPv4')self.wait_onoff("[data-field=dns]", val=False)self.wait_onoff("[data-field=dns_search]", val=False)b.wait_val("#network-ip-settings-dns-server-0", "1.2.3.4")b.wait_val("#network-ip-settings-search-domain-0", "foo.com")b.click("#network-ip-settings-cancel")b.wait_not_present("#network-ip-settings-dialog")self.configure_iface_setting('IPv6')b.wait_visible("#network-ip-settings-dialog")b.select_from_dropdown("#network-ip-settings-select-method", "disabled")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")assert_connection_setting(con_id, "ipv6.method", "disabled")# Open the dialog, expand all the fields and assert pixelsself.configure_iface_setting("IPv4")b.click("#network-ip-settings-address-add")b.click("#network-ip-settings-route-add")b.click("#network-ip-settings-dns-add")b.click("#network-ip-settings-dns-search-add")b.assert_pixels("#network-ip-settings-dialog", "network-ip-settings-dialog")# Check that IPv4/IPv6 settings dialogs only show the supported IP methods for wireguard# Skip images without the wireguard-tools packageif not m.image.startswith("rhel-8"):b.go("/network")b.click("#networking-add-wg")b.set_input_text("#network-wireguard-settings-addresses-input", "1.2.3.4/24")wg_iface = b.val("#network-wireguard-settings-interface-name-input")b.click("#network-wireguard-settings-save")b.wait_text("#network-interface-name", wg_iface)self.configure_iface_setting("IPv4")b._wait_present("#network-ip-settings-select-method option[value='manual']")b._wait_present("#network-ip-settings-select-method option[value='disabled']")unsupported_ip4_methods = ['auto', 'dhcp', 'link-local', 'ignore', 'shared']for method in unsupported_ip4_methods:b.wait_not_present(f"#network-ip-settings-select-method option[value='{method}']")b.click("#network-ip-settings-cancel")b.wait_not_present("#network-ip-settings-dialog")self.configure_iface_setting("IPv6")supported_ip6_methods = ['link-local', 'manual', 'disabled']for method in supported_ip6_methods:b._wait_present(f"#network-ip-settings-select-method option[value='{method}']")unsupported_ip6_methods = ['auto', 'dhcp', 'ignore', 'shared']for method in unsupported_ip6_methods:b.wait_not_present(f"#network-ip-settings-select-method option[value='{method}']")def testOtherSettings(self):b = self.browserm = self.machineiface = self.add_iface()con_id = self.iface_con_id(iface)m.execute(f"nmcli con mod '{con_id}' connection.gateway-ping-timeout 12")self.login_and_go("/network")self.wait_for_iface(iface)# IPv4 address sharingself.select_iface(iface)b.wait_visible("#network-interface")self.configure_iface_setting('IPv4')b.wait_visible("#network-ip-settings-dialog")b.select_from_dropdown("#network-ip-settings-select-method", "shared")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")self.assertEqual(m.execute(f"nmcli -m tabular -t -f ipv4.method con show '{con_id}'").strip(),"shared")self.assertEqual(m.execute(f"nmcli -m tabular -t -f connection.gateway-ping-timeout con show '{con_id}'").strip(),"12")# IPv6 route# by default there's a route to link-local only (fe80::)show_cmd = f"ip -6 route show dev {iface}"testlib.wait(lambda: "fe80::/64" in m.execute(show_cmd))# add a manual oneself.configure_iface_setting('IPv6')b.wait_visible("#network-ip-settings-dialog")b.click('#network-ip-settings-route-add')b.set_input_text('#network-ip-settings-route-address-0', "fe80:2::")b.set_input_text('#network-ip-settings-route-netmask-0', "60")b.set_input_text('#network-ip-settings-route-gateway-0', "fe80:2::3")b.set_input_text('#network-ip-settings-route-metric-0', "42")b.click('#network-ip-settings-save')b.wait_not_present("#network-ip-settings-dialog")# setting should be appliedtestlib.wait(lambda: "metric 42" in m.execute(show_cmd))out = m.execute(show_cmd)self.assertIn("fe80:2::/60 via fe80:2::3 proto static metric 42", out)self.assertIn("fe80:2::3 proto static metric 42", out)# original link-local route still existsself.assertIn("fe80::/64", out)b.wait_attr("#network-interface", "data-test-wait", "false")# dialog prefills fields with current settingsself.configure_iface_setting('IPv6')b.wait_visible("#network-ip-settings-dialog")b.wait_val('#network-ip-settings-route-address-0', "fe80:2::")b.wait_val('#network-ip-settings-route-netmask-0', "60")b.wait_val('#network-ip-settings-route-gateway-0', "fe80:2::3")b.wait_val('#network-ip-settings-route-metric-0', "42")b.click('#network-ip-settings-cancel')b.wait_not_present("#network-ip-settings-dialog")# Test editing connection without a hardcoded interfaceiface = self.add_iface(activate=False)con_name = "cockpit-test-con"b.go("/network")b.wait_visible("#networking")m.execute(f"""nmcli con add con-name {con_name} connection.type 802-3-ethernet connection.autoconnect no \ipv4.meth auto ipv6.meth auto ipv6.addr-gen-mode eui64nmcli con sh | grep -q '{con_name}'nmcli con up {con_name} ifname {iface}# check that no connection.interface-name is configured[ -z "$(nmcli --get connection.interface-name con sh {con_name})" ]""")self.addCleanup(m.execute, f"nmcli con del {con_name}")self.select_iface(iface)b.wait_visible("#network-interface")self.configure_iface_setting('IPv4')b.click("#network-ip-settings-dns-add")b.set_input_text('#network-ip-settings-dns-server-0', "8.8.8.8")b.click("#network-ip-settings-save")# page should still display interface detail page after savingb.wait_visible("#network-interface")self.wait_for_iface_setting("IPv4", "AutomaticAdditional DNS 8.8.8.8")# Test multiconnect connectionb.go("/network")b.wait_visible("#networking")iface1 = self.add_iface(activate=False)iface2 = self.add_iface(activate=False)# add temporary connections with multiconnect enabledm.execute(f"""nmcli con add con-name 'Wired Connection' save no connection.type 802-3-ethernet \connection.autoconnect no connection.multi-connect multiple \ipv4.meth auto ipv6.meth auto ipv6.addr-gen-mode eui64nmcli con sh | grep -q 'Wired Connection'for IFACE in {iface1} {iface2}; donmcli con up 'Wired Connection' ifname ${{IFACE}}done""")# Edit interface with nonpersistent Wired Connection activeself.select_iface(iface1)b.wait_visible("#network-interface")self.configure_iface_setting('IPv4')b.select_from_dropdown("#network-ip-settings-select-method", "manual")b.set_input_text('#network-ip-settings-address-0', "10.11.12.13")b.set_input_text('#network-ip-settings-netmask-0', "24")b.click("#network-ip-settings-dns-add")b.set_input_text('#network-ip-settings-dns-server-0', "8.8.8.8")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")self.wait_for_iface_setting("IPv4", "Address 10.11.12.13/24Gateway 10.11.12.1DNS 8.8.8.8")# Check that new connection exists and is applied to the interfaceself.assertEqual(m.execute(f"nmcli --get connection.interface-name,connection.multi-connect,ipv4.addresses,ipv4.dns con sh {iface1}"),f"{iface1}\n0\n10.11.12.13/24\n8.8.8.8\n")# Wired Connection is unmodifiedself.assertEqual(m.execute("nmcli --get ipv4.method con sh 'Wired Connection'"), "auto\n")# Further edits will edit the new connectionself.configure_iface_setting('IPv4')b.set_input_text('#network-ip-settings-dns-server-0', "1.1.1.1")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")self.wait_for_iface_setting("IPv4", "Address 10.11.12.13/24Gateway 10.11.12.1DNS 1.1.1.1")m.execute(f'[ $(nmcli --get ipv4.dns con sh {iface1}) == "1.1.1.1" ]')# Editing auto-connect also creates new connection when necessaryb.go("/network")b.wait_visible("#networking")self.select_iface(iface2)b.wait_visible("#network-interface")b.wait_visible('#autoreconnect:not(:checked)')b.set_checked('#autoreconnect', val=True)b.wait_visible('#autoreconnect:checked')# Check that new connection exists and autoconnect is enabledself.assertEqual(m.execute(f"nmcli --get connection.interface-name,connection.autoconnect,connection.multi-connect con sh {iface2}"),f"{iface2}\nyes\n0\n")if __name__ == '__main__':testlib.test_main()