#!/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 testlib@testlib.nondestructiveclass TestNetworkingBasic(netlib.NetworkCase):def testBasic(self):b = self.browserm = self.machineif not m.ostree_image:# screenshot assumes running firewalld and absent virbr0 (in particular, *3* interfaces)m.execute("systemctl start firewalld")# ensure PCP is on for pixel tests, so that we get the zoom/range selectorsif b.pixels_label:m.execute("systemctl start pmlogger")self.login_and_go("/network")b.wait_visible("#networking")iface = 'cockpit1'self.add_veth(iface, dhcp_cidr="10.111.113.2/20")self.nm_activate_eth(iface)self.wait_for_iface(iface)b.wait_not_present("#network-interface")b.wait_in_text("#networking-graphs", "Transmitting")b.wait_in_text("#networking-graphs", "Receiving")# PCP is only enabled for pixel tests# zoom/range selectors are hidden when PCP is disabledif b.pixels_label:b.click("#zoom-control button:nth-of-type(2)")b.wait_in_text("#zoom-control button.pf-v6-c-menu-toggle", "1 hour")b.click("#zoom-control button.pf-v6-c-menu-toggle")b.click(".pf-v6-c-menu ul li:nth-child(3) > button")b.wait_in_text("#zoom-control button.pf-v6-c-menu-toggle", "5 minutes")# FIXME: rtl test was flaky, debug it and remove the skipb.assert_pixels("#networking", "network-main",ignore=["td[data-label=Sending]","td[data-label=Receiving]","td[data-label='IP address']","#networking-graphs .pf-v6-l-grid",".cockpit-log-panel .pf-v6-c-card__body","#networking-firewall-summary .pf-v6-c-card__body",],# IPv6 addresses vary wildly, and their different rendered widths change the column widthsskip_layouts=['medium', 'mobile', 'rtl'])# Details of test ifaceself.select_iface(iface)b.wait_visible("#network-interface")b.assert_pixels("#network-interface .network-interface-details","network-interface",mock={"#network-interface-mac": "11:22:33:44:55:66",".networking-interface-status": "12.123.123.123/20, fedc:0:0:0:1234:ff:abcd:1234/64",})con_id = testlib.wait(lambda: self.iface_con_id(iface))# Toggle "Connect automatically"#b.wait_visible('#autoreconnect:checked')b.set_checked('#autoreconnect', val=False)self.assertEqual(m.execute(f"nmcli -g connection.autoconnect con show {con_id}"), "no\n")b.wait_visible('#autoreconnect:not(:checked)')b.set_checked('#autoreconnect', val=True)b.wait_visible('#autoreconnect:checked')self.assertEqual(m.execute(f"nmcli -g connection.autoconnect con show {con_id}"), "yes\n")# Configure a manual IPv4 addressself.configure_iface_setting('IPv4')b.wait_visible("#network-ip-settings-dialog")b.select_from_dropdown("#network-ip-settings-dialog select", "manual")# Manual mode disables automatic switchesb.wait_visible("#network-ip-settings-dialog [data-field='dns'] input[type=checkbox]:disabled")b.wait_visible("#network-ip-settings-dialog [data-field='dns_search'] input[type=checkbox]:disabled")b.wait_visible("#network-ip-settings-dialog [data-field='routes'] input[type=checkbox]:disabled")# Test IPv4 validation# Addressb.set_input_text('#network-ip-settings-address-0', "192.168.48.10.2")b.set_input_text('#network-ip-settings-netmask-0', "24")b.click("#network-ip-settings-save")b.wait_in_text(".pf-v6-c-alert", "Invalid IP address: 192.168.48.10.2")b.set_input_text('#network-ip-settings-address-0', "192.168.256.10")b.click("#network-ip-settings-save")b.wait_in_text(".pf-v6-c-alert", "Invalid IP address: 192.168.256.10")b.set_input_text('#network-ip-settings-address-0', "192.168.48.10")b.set_input_text('#network-ip-settings-gateway', "192.168.48.")b.click("#network-ip-settings-save")# Gatewayb.wait_in_text(".pf-v6-c-alert", "Invalid gateway address: 192.168.48.")b.set_input_text('#network-ip-settings-gateway', "192.168.48.1")# DNSb.click("#network-ip-settings-dns-add")b.set_input_text('#network-ip-settings-dns-server-0', "8..8")b.click("#network-ip-settings-save")b.wait_in_text(".pf-v6-c-alert", "Invalid DNS address: 8..8")b.set_input_text('#network-ip-settings-dns-server-0', "8.8.8.8")# Routeb.click("#network-ip-settings-route-add")b.set_input_text('#network-ip-settings-route-address-0', "192")b.set_input_text('#network-ip-settings-route-netmask-0', "24")b.set_input_text('#network-ip-settings-route-gateway-0', "192.168.48.1")b.set_input_text('#network-ip-settings-route-metric-0', "500")b.click("#network-ip-settings-save")b.wait_in_text(".pf-v6-c-alert", "Invalid destination address: 192")b.set_input_text('#network-ip-settings-route-address-0', "192.168.66.0")b.set_input_text('#network-ip-settings-route-gateway-0', "not.an.ip.address")b.click("#network-ip-settings-save")b.wait_in_text(".pf-v6-c-alert", "Invalid gateway address: not.an.ip.address")b.set_input_text('#network-ip-settings-route-gateway-0', "192.168.48.1")b.set_input_text('#network-ip-settings-address-0', "1.2.3.4")b.set_input_text('#network-ip-settings-netmask-0', "255.255.0.8")b.set_input_text('#network-ip-settings-gateway', "1.2.3.1")b.click("#network-ip-settings-save")b.wait_text_not("#network-ip-settings-error h4", "")b.set_input_text('#network-ip-settings-netmask-0', "255.255.192.0")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/18Gateway 1.2.3.1DNS 8.8.8.8")m.execute(f"until ip a show dev {iface} | grep -q 'inet 1.2.3.4/18'; do sleep 0.3; done",timeout=10)# Add IPv4 route without optional propertiesself.configure_iface_setting('IPv4')b.wait_visible("#network-ip-settings-dialog")# route without metric and next-hop addressb.set_input_text('#network-ip-settings-route-address-0', "192.168.67.0")b.set_input_text('#network-ip-settings-route-netmask-0', "24")b.set_input_text('#network-ip-settings-route-gateway-0', "")b.set_input_text('#network-ip-settings-route-metric-0', "")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")route = m.execute(f"nmcli -t -f ipv4.routes con sh {iface}").strip()self.assertEqual(route, "ipv4.routes:192.168.67.0/24")# route without metricself.configure_iface_setting('IPv4')b.wait_visible("#network-ip-settings-dialog")b.set_input_text('#network-ip-settings-route-address-0', "192.168.68.0")b.set_input_text('#network-ip-settings-route-netmask-0', "24")b.set_input_text('#network-ip-settings-route-gateway-0', "192.168.48.1")b.set_input_text('#network-ip-settings-route-metric-0', "")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")route = m.execute(f"nmcli -t -f ipv4.routes con sh {iface}").strip()self.assertEqual(route, "ipv4.routes:192.168.68.0/24 192.168.48.1")# route without next-hop addressself.configure_iface_setting('IPv4')b.wait_visible("#network-ip-settings-dialog")b.set_input_text('#network-ip-settings-route-address-0', "192.168.69.0")b.set_input_text('#network-ip-settings-route-netmask-0', "24")b.set_input_text('#network-ip-settings-route-gateway-0', "")b.set_input_text('#network-ip-settings-route-metric-0', "500")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")route = m.execute(f"nmcli -t -f ipv4.routes con sh {iface}").strip()self.assertEqual(route, "ipv4.routes:192.168.69.0/24 500")# Configure manual IPv6 addressb.click("#networking-edit-ipv6")b.wait_visible("#network-ip-settings-dialog")b.select_from_dropdown("#network-ip-settings-select-method", "manual")# Test IPv6 validation# Addressb.set_input_text('#network-ip-settings-address-0', "2001:db8::10::1")b.set_input_text('#network-ip-settings-netmask-0', "64")b.click("#network-ip-settings-save")b.wait_in_text(".pf-v6-c-alert", "Invalid IP address: 2001:db8::10::1")b.set_input_text('#network-ip-settings-address-0', "no:ipv6:here::1")b.set_input_text('#network-ip-settings-netmask-0', "64")b.click("#network-ip-settings-save")b.wait_in_text(".pf-v6-c-alert", "Invalid IP address: no:ipv6:here::1")b.set_input_text('#network-ip-settings-address-0', "2001:db8::10:2")b.set_input_text('#network-ip-settings-netmask-0', "64")b.set_input_text('#network-ip-settings-gateway', "2001:db8::10:q")b.click("#network-ip-settings-save")# Gatewayb.wait_in_text(".pf-v6-c-alert", "Invalid gateway address: 2001:db8::10:q")b.set_input_text('#network-ip-settings-gateway', "2001:db8::10:1")# DNSb.click("#network-ip-settings-dns-add")b.set_input_text('#network-ip-settings-dns-server-0', "2001:db8:64:::")b.click("#network-ip-settings-save")b.wait_in_text(".pf-v6-c-alert", "Invalid DNS address: 2001:db8:64:::")b.set_input_text('#network-ip-settings-dns-server-0', "2001:db8:cafe::1")# Routeb.click("#network-ip-settings-route-add")b.set_input_text('#network-ip-settings-route-address-0', "2001")b.set_input_text('#network-ip-settings-route-netmask-0', "48")b.set_input_text('#network-ip-settings-route-gateway-0', "2001:db8::10:1")b.set_input_text('#network-ip-settings-route-metric-0', "500")b.click("#network-ip-settings-save")b.wait_in_text(".pf-v6-c-alert", "Invalid destination address: 2001")b.set_input_text('#network-ip-settings-route-address-0', "2001:db8:face::")b.set_input_text('#network-ip-settings-route-gateway-0', "::db8:cafe::1")b.click("#network-ip-settings-save")b.wait_in_text(".pf-v6-c-alert", "Invalid gateway address: ::db8:cafe::1")b.set_input_text('#network-ip-settings-route-gateway-0', "2001:db8::10:1")b.set_input_text("#network-ip-settings-address-0", "2001::1")b.set_input_text("#network-ip-settings-netmask-0", "64")b.set_input_text("#network-ip-settings-gateway", "::")b.click("button:contains('Save')")b.wait_not_present("#network-ip-settings-dialog")self.wait_for_iface_setting("IPv6", "Address 2001::1/64DNS 2001:db8:cafe::1")m.execute(f"until ip a show dev {iface} | grep -q 'inet6 2001::1/64 scope global'; do sleep 0.3; done",timeout=10)# Add IPv6 route without optional propertiesself.configure_iface_setting('IPv6')b.wait_visible("#network-ip-settings-dialog")# route without metric and next-hop addressb.set_input_text('#network-ip-settings-route-address-0', "2001:db8:face::")b.set_input_text('#network-ip-settings-route-netmask-0', "64")b.set_input_text('#network-ip-settings-route-gateway-0', "")b.set_input_text('#network-ip-settings-route-metric-0', "")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")route = m.execute(f"nmcli -t -f ipv6.routes con sh {iface}").strip()self.assertEqual(route, "ipv6.routes:2001:db8:face::/64")# route without metricself.configure_iface_setting('IPv6')b.wait_visible("#network-ip-settings-dialog")b.set_input_text('#network-ip-settings-route-address-0', "2001:db8:face:1::")b.set_input_text('#network-ip-settings-route-netmask-0', "64")b.set_input_text('#network-ip-settings-route-gateway-0', "2001:db8::10:1")b.set_input_text('#network-ip-settings-route-metric-0', "")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")route = m.execute(f"nmcli -t -f ipv6.routes con sh {iface}").strip()self.assertEqual(route, "ipv6.routes:2001:db8:face:1::/64 2001:db8::10:1")# route without next-hop addressself.configure_iface_setting('IPv6')b.wait_visible("#network-ip-settings-dialog")b.set_input_text('#network-ip-settings-route-address-0', "2001:db8:face:2::")b.set_input_text('#network-ip-settings-route-netmask-0', "64")b.set_input_text('#network-ip-settings-route-gateway-0', "")b.set_input_text('#network-ip-settings-route-metric-0', "500")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")route = m.execute(f"nmcli -t -f ipv6.routes con sh {iface}").strip()self.assertEqual(route, "ipv6.routes:2001:db8:face:2::/64 500")# Disconnectself.wait_onoff("label[for='interface-switch']", val=True)self.toggle_onoff("label[for='interface-switch']")self.wait_for_iface_setting('Status', 'Inactive')# Reconnect through the UIself.toggle_onoff("label[for='interface-switch']")b.wait_in_text(f"#network-interface .pf-v6-c-card:contains('{iface}')", "1.2.3.4/18")# Disconnect from the CLI, UI reactsm.execute(f"nmcli device disconnect {iface}")self.wait_onoff("label[for='interface-switch']", val=False)# Switch it back to "auto" from the command line and bring it# up again#m.execute(f"nmcli connection modify '{con_id}' ipv4.method auto")m.execute(f"nmcli connection modify '{con_id}' ipv4.gateway ''")m.execute(f"nmcli connection modify '{con_id}' ipv4.addresses ''")self.wait_for_iface_setting('IPv4', "Automatic")m.execute(f"nmcli connection up '{con_id}'")self.wait_for_iface_setting('Status', '10.111.')# Switch off automatic DNS#self.configure_iface_setting('IPv4')b.wait_visible("#network-ip-settings-dialog")self.wait_onoff("#network-ip-settings-dialog [data-field='dns']", val=True)self.toggle_onoff("#network-ip-settings-dialog [data-field='dns']")# The "DNS search domains" setting should follow suitself.wait_onoff("#network-ip-settings-dialog [data-field='dns_search']", val=False)b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")testlib.wait(lambda: "yes" in m.execute(f"nmcli -f ipv4.ignore-auto-dns connection show '{con_id}'"))# Validate that IPv6 addresses are properly shortened#def set_and_check_ipv6(expected: str, addr: str, mask: str = "64", gateway: str = "::"):self.configure_iface_setting('IPv6')b.wait_visible("#network-ip-settings-dialog")b.set_input_text("#network-ip-settings-address-0", addr)b.set_input_text("#network-ip-settings-netmask-0", mask)b.set_input_text("#network-ip-settings-gateway", gateway)b.click("button:contains('Save')")b.wait_not_present("#network-ip-settings-dialog")self.wait_for_iface_setting("IPv6", f"Address {expected}")set_and_check_ipv6("2001:db8::ff00:42:8329/64", "2001:db8:0000:0000:0000:ff00:0042:8329")set_and_check_ipv6("2001::1/48", "2001:0:0:0:0:0:0:1", "48")set_and_check_ipv6("::1/128", "0:0:0:0:0:0:0:1", "128")set_and_check_ipv6("::/64", "0:0:0:0:0:0:0:0")set_and_check_ipv6("2001:db0:0:1::1428:57ab", "2001:0db0:0000:0001:0000:0000:1428:57ab")# first longest sequence is replacedset_and_check_ipv6("2001::aaaa:0:0:aaaa:bbbb/64", "2001:0000:0000:aaaa:0000:0000:aaaa:bbbb")# no compression neededset_and_check_ipv6("2001:db8:100:200:300:4:5000:6/64", "2001:db8:100:200:300:4:5000:6")# no compression for single fields of zero, only drop leading zerosset_and_check_ipv6("2001:0:a:0:a:0:a:0/64", "2001:0000:000a:0000:000a:0000:000a:0000")# left sequence is not the longestset_and_check_ipv6("2001:0:0:ffff::1/64", "2001:0:0:ffff:0:0:0:1")# left sequence is not the longest (full address)set_and_check_ipv6("2001:0:0:aaaa::1/64", "2001:0000:0000:aaaa:0000:0000:0000:0001")# left sequence is the longestset_and_check_ipv6("2001::1000:0:0:1/64", "2001:0000:0000:0000:1000:0000:0000:0001")# same length zeros are at the start and at the endset_and_check_ipv6("::db0:0:1:1:0:0/64", "0:0:db0:0:1:1:0:0")# end is longerset_and_check_ipv6("0:0:db0:0:1::/64", "0:0:db0:0:1:0:0:0")# start is longerset_and_check_ipv6("::db0:0:1:0:0/64", "0:0:0:db0:0:1:0:0")# check that default gateway is also shortenedset_and_check_ipv6("2001:db8:cafe::1/64", "2001:db8:cafe:0:0:0:0:1", "64", "2001:0db8:cafe:0000:0000:0000:0000:0010")self.configure_iface_setting('IPv6')b.wait_visible("#network-ip-settings-dialog")b.wait_attr_contains("#network-ip-settings-gateway", "value", "2001:db8:cafe::10")b.go("/network")# Create a bridge interface and disable it to test if disabled connections can be modified.# Connection exists, is down and the device itself does not exist as long as the connection is downm.execute("nmcli con add con-name cockpitbr type bridge ifname cockpitbr ipv4.meth disab ipv6.meth disab")self.addCleanup(m.execute, "nmcli con del cockpitbr")self.wait_for_iface("cockpitbr", prefix="No carrier")m.execute("nmcli con down cockpitbr")self.wait_for_iface("cockpitbr", active=False)# check that connection exists but interface does notm.execute("nmcli con sh | grep -q 'cockpitbr'")m.execute("ip link sh | grep -q --invert-match 'cockpitbr'")self.select_iface("cockpitbr")b.wait_visible("#network-interface")self.wait_for_iface_setting("Status", "Inactive")# Configure IPv4 addressself.configure_iface_setting("IPv4")b.wait_visible("#network-ip-settings-dialog")b.select_from_dropdown("#network-ip-settings-select-method", "manual")b.wait_visible("#network-ip-settings-address-0")b.set_input_text("#network-ip-settings-address-0", "10.0.5.10")b.set_input_text("#network-ip-settings-netmask-0", "24")b.set_input_text("#network-ip-settings-gateway", "10.0.5.1")b.click("#network-ip-settings-save")self.wait_for_iface_setting("IPv4", "Address 10.0.5.10/24Gateway 10.0.5.1")self.wait_for_iface_setting("Status", "Inactive")# Configure IPv6 addressself.configure_iface_setting("IPv6")b.wait_visible("#network-ip-settings-dialog")b.select_from_dropdown("#network-ip-settings-select-method", "manual")b.wait_visible("#network-ip-settings-address-0")b.set_input_text("#network-ip-settings-address-0", "2001:db8::10")b.set_input_text("#network-ip-settings-netmask-0", "64")b.set_input_text("#network-ip-settings-gateway", "2001:db8::1")b.click("#network-ip-settings-save")self.wait_for_iface_setting("IPv6", "Address 2001:db8::10/64Gateway 2001:db8::1")self.wait_for_iface_setting("Status", "Inactive")# Start the interface and verify new address is setb.click("#interface-switch")self.wait_for_iface_setting("Status", "10.0.5.10/24,")m.execute("ip addr sh cockpitbr | grep -q 'inet 10.0.5.10/24'")m.execute("ip addr sh cockpitbr | grep -q 'inet6 2001:db8::10/64'")def testIpHelper(self):b = self.browserm = self.machineself.login_and_go("/network")b.wait_visible("#networking")iface = "cockpit1"self.add_veth(iface, dhcp_cidr="10.111.113.2/20")self.nm_activate_eth(iface)self.wait_for_iface(iface)b.click("button:contains('cockpit1')")# wait until dialog initializedb.click("#networking-edit-ipv4:contains('edit')")b.wait_visible("#network-ip-settings-dialog")b.select_from_dropdown("#network-ip-settings-select-method", "manual")b.wait_visible("#network-ip-settings-address-0")# test class A IPb.set_input_text("#network-ip-settings-address-0", "10.0.5.1")b.wait_val("#network-ip-settings-netmask-0", "8")b.set_input_text("#network-ip-settings-netmask-0", "")# test class B IPb.set_input_text("#network-ip-settings-address-0", "172.16.44.2")b.wait_val("#network-ip-settings-netmask-0", "16")b.set_input_text("#network-ip-settings-netmask-0", "")# test class C IPb.set_input_text("#network-ip-settings-address-0", "192.168.1.1")b.wait_val("#network-ip-settings-netmask-0", "24")b.set_input_text("#network-ip-settings-netmask-0", "")# others | Need to manually reset fieldsb.set_input_text("#network-ip-settings-netmask-0", "")b.set_input_text("#network-ip-settings-gateway", "")b.set_input_text("#network-ip-settings-address-0", "225.4.3.2")b.wait_val("#network-ip-settings-netmask-0", "")b.wait_val("#network-ip-settings-gateway", "")# free manual edit & saveb.set_input_text("#network-ip-settings-address-0", "192.168.1.1")b.set_input_text("#network-ip-settings-netmask-0", "25")b.set_input_text("#network-ip-settings-gateway", "192.168.1.126")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")self.assertIn("192.168.1.1/25", m.execute(f"nmcli -g ipv4.addresses connection show {iface}"))self.assertIn("192.168.1.126", m.execute(f"nmcli -g ipv4.gateway connection show {iface}"))b.click("#networking-edit-ipv4:contains('edit')")b.wait_visible("#network-ip-settings-dialog")# gateway is not changed after it has been explicitly edited by userb.set_input_text("#network-ip-settings-gateway", "192.168.20.7")b.set_input_text("#network-ip-settings-address-0", "10.0.0.5")b.wait_val("#network-ip-settings-gateway", "192.168.20.7")b.set_input_text("#network-ip-settings-address-0", "192.168.2.5")b.set_input_text("#network-ip-settings-netmask-0", "24")b.wait_val("#network-ip-settings-gateway", "192.168.20.7")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")self.wait_for_iface_setting("IPv4", "Address 192.168.2.5/24Gateway 192.168.20.7")# Test classless gateway prefilling# the gateway is set to the first usable address in subnet# for subnets with prefix smaller than 30b.click("#networking-edit-ipv4:contains('edit')")b.wait_visible("#network-ip-settings-dialog")b.set_input_text("#network-ip-settings-address-0", "10.11.101.240")b.set_input_text("#network-ip-settings-netmask-0", "8")b.wait_val("#network-ip-settings-gateway", "10.0.0.1")# /13b.set_input_text("#network-ip-settings-netmask-0", "255.248.0.0")b.wait_val("#network-ip-settings-gateway", "10.8.0.1")b.set_input_text("#network-ip-settings-netmask-0", "15")b.wait_val("#network-ip-settings-gateway", "10.10.0.1")# /23b.set_input_text("#network-ip-settings-netmask-0", "255.255.254.0")b.wait_val("#network-ip-settings-gateway", "10.11.100.1")b.set_input_text("#network-ip-settings-netmask-0", "24")b.wait_val("#network-ip-settings-gateway", "10.11.101.1")# /25# first subnet smaller than 255 addresses, first address no longer ends with ".1"b.set_input_text("#network-ip-settings-netmask-0", "255.255.255.128")b.wait_val("#network-ip-settings-gateway", "10.11.101.129")b.set_input_text("#network-ip-settings-netmask-0", "27")b.wait_val("#network-ip-settings-gateway", "10.11.101.225")# /28# host address is the same as network addressb.set_input_text("#network-ip-settings-netmask-0", "255.255.255.240")b.wait_val("#network-ip-settings-gateway", "")# for prefixes 30-32 gateway is not setb.set_input_text("#network-ip-settings-address-0", "10.11.101.244")b.set_input_text("#network-ip-settings-netmask-0", "28")b.wait_val("#network-ip-settings-gateway", "10.11.101.241")# /30b.set_input_text("#network-ip-settings-netmask-0", "255.255.255.252")b.wait_val("#network-ip-settings-gateway", "")b.set_input_text("#network-ip-settings-netmask-0", "28")b.wait_val("#network-ip-settings-gateway", "10.11.101.241")b.set_input_text("#network-ip-settings-netmask-0", "31")b.wait_val("#network-ip-settings-gateway", "")b.set_input_text("#network-ip-settings-netmask-0", "28")b.wait_val("#network-ip-settings-gateway", "10.11.101.241")# /32b.set_input_text("#network-ip-settings-netmask-0", "255.255.255.255")b.wait_val("#network-ip-settings-gateway", "")# wrong prefixesb.set_input_text("#network-ip-settings-netmask-0", "33")b.wait_val("#network-ip-settings-gateway", "")b.set_input_text("#network-ip-settings-netmask-0", "asd23")b.wait_val("#network-ip-settings-gateway", "")# Mask does not change after it's been setb.set_input_text("#network-ip-settings-address-0", "10.11.101.244")b.set_input_text("#network-ip-settings-netmask-0", "255.255.254.0")b.set_input_text("#network-ip-settings-address-0", "192.168.88.13")b.wait_val("#network-ip-settings-netmask-0", "255.255.254.0")# but gateway does as it has not been set explicitlyb.wait_val("#network-ip-settings-gateway", "192.168.88.1")# set gateway, then change host address to different networkb.set_input_text("#network-ip-settings-gateway", "192.168.89.254")b.set_input_text("#network-ip-settings-address-0", "172.16.11.12")# both gateway and masks are unchangedb.wait_val("#network-ip-settings-netmask-0", "255.255.254.0")b.wait_val("#network-ip-settings-gateway", "192.168.89.254")b.set_input_text("#network-ip-settings-address-0", "192.168.88.13")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")self.wait_for_iface_setting("IPv4", "Address 192.168.88.13/23Gateway 192.168.89.254")# IPv6 prefillingb.click("#networking-edit-ipv6:contains('edit')")b.wait_visible("#network-ip-settings-dialog")b.select_from_dropdown("#network-ip-settings-select-method", "manual")b.wait_visible("#network-ip-settings-address-0")# nothing is filled when plain IPv4 is enteredb.set_input_text("#network-ip-settings-address-0", "10.11.101.240")b.wait_val("#network-ip-settings-netmask-0", "")b.wait_val("#network-ip-settings-gateway", "")# prefix length does not accept network maskb.set_input_text("#network-ip-settings-netmask-0", "255.255.240.0")b.wait_val("#network-ip-settings-gateway", "")# default prefix is /64b.set_input_text("#network-ip-settings-address-0", "2001:db8:cafe:face:0:0:dcba:a")b.set_input_text("#network-ip-settings-netmask-0", "64")b.wait_val("#network-ip-settings-gateway", "2001:db8:cafe:face::1")b.set_input_text("#network-ip-settings-netmask-0", "97")b.wait_val("#network-ip-settings-gateway", "2001:db8:cafe:face::8000:1")b.set_input_text("#network-ip-settings-netmask-0", "105")b.wait_val("#network-ip-settings-gateway", "2001:db8:cafe:face::dc80:1")# for prefixes 126-128 gateway is not setb.set_input_text("#network-ip-settings-netmask-0", "126")b.wait_val("#network-ip-settings-gateway", "")b.set_input_text("#network-ip-settings-netmask-0", "105")b.wait_val("#network-ip-settings-gateway", "2001:db8:cafe:face::dc80:1")b.set_input_text("#network-ip-settings-netmask-0", "127")b.wait_val("#network-ip-settings-gateway", "")b.set_input_text("#network-ip-settings-netmask-0", "105")b.wait_val("#network-ip-settings-gateway", "2001:db8:cafe:face::dc80:1")b.set_input_text("#network-ip-settings-netmask-0", "128")b.wait_val("#network-ip-settings-gateway", "")# gateway is not set when host address is network addressb.set_input_text("#network-ip-settings-address-0", "2001:db8:0:face:0:0:0:0")b.set_input_text("#network-ip-settings-netmask-0", "66")b.wait_val("#network-ip-settings-gateway", "")# gateway is not set when host address is first addressb.set_input_text("#network-ip-settings-address-0", "2001:db8:0:face::1")b.wait_val("#network-ip-settings-gateway", "")# gateway is not changed after it's been set manuallyb.set_input_text("#network-ip-settings-address-0", "2001:db8:0:face::15")b.set_input_text("#network-ip-settings-netmask-0", "106")b.set_input_text("#network-ip-settings-gateway", "2001:db8:cafe:face::dc80:aaab")b.set_input_text("#network-ip-settings-address-0", "2001:db8:0:face:dead::15")b.wait_val("#network-ip-settings-gateway", "2001:db8:cafe:face::dc80:aaab")# after changing prefix gateway is still unchangedb.set_input_text("#network-ip-settings-netmask-0", "32")b.wait_val("#network-ip-settings-gateway", "2001:db8:cafe:face::dc80:aaab")b.set_input_text("#network-ip-settings-address-0", "2001:db8::1")b.click("#network-ip-settings-save")b.wait_not_present("#network-ip-settings-dialog")self.wait_for_iface_setting("IPv6", "Address 2001:db8::1/32Gateway 2001:db8:cafe:face::dc80:aaab")def testNoService(self):b = self.browserm = self.machineiface = "cockpit42"self.add_veth(iface)self.addCleanup(m.execute, "systemctl enable --now NetworkManager")def assert_running():b.wait_not_present("#networking-nm-crashed")b.wait_not_present("#networking-nm-disabled")b.wait_visible("#networking-graphs")b.wait_in_text("#networking-interfaces", iface)def assert_stopped(enabled):# should hide graphs and actions and show the appropriate notificationb.wait_not_present("#networking-graphs")b.wait_not_present("#networking-interfaces")if enabled:b.wait_visible("#networking-nm-crashed")b.wait_not_present("#networking-nm-disabled")else:b.wait_not_present("#networking-nm-crashed")b.wait_visible("#networking-nm-disabled")def assert_not_found():# should hide graphs and actions and show the appropriate notificationb.wait_not_present("#networking-graphs")b.wait_not_present("#networking-interfaces")b.wait_visible("#networking-nm-not-found")self.login_and_go("/network")assert_running()# stop/start NM on CLI, page should noticem.execute("systemctl stop NetworkManager")assert_stopped(enabled=True)m.execute("systemctl start NetworkManager")assert_running()# stop NM, test inline start buttonm.execute("systemctl stop NetworkManager")assert_stopped(enabled=True)b.click("#networking-nm-crashed button")assert_running()# stop NM, test troubleshoot buttonm.execute("systemctl stop NetworkManager")assert_stopped(enabled=True)b.click("#networking-nm-crashed a")b.enter_page("/system/services")b.wait_text(".service-name", "Network Manager")b.click(".service-top-panel button.pf-v6-c-menu-toggle")b.click("#services-page > .pf-v6-c-menu button.pf-v6-c-menu__item:contains('Start')")b.wait_in_text("#statuses", "Running")# networking page should notice start from Services pageb.go("/network")b.enter_page("/network")assert_running()# stop and disable NM, enablement info notificationm.execute("systemctl stop NetworkManager; systemctl disable NetworkManager")assert_stopped(enabled=False)b.click("#networking-nm-disabled button")assert_running()testlib.wait(lambda: m.execute("systemctl is-enabled NetworkManager"))# /usr in ostree is readonlyif not m.ostree_image:# remove the NM service file, test 'no-found' notification# This works for ND tests since there is a self.addCleanup(m.execute, "systemctl enable --now NetworkManager") in the start of the testself.restore_file('/usr/lib/systemd/system/NetworkManager.service')m.execute("rm /usr/lib/systemd/system/NetworkManager.service; systemctl daemon-reload; systemctl stop NetworkManager")assert_not_found()self.allow_journal_messages(".*org.freedesktop.NetworkManager.*")# Killing NM affects realmd as wellself.allow_journal_messages(".*org.freedesktop.realmd.Service.*")def testUnprivileged(self):b = self.browserm = self.machineself.login_and_go("/network", superuser=False)b.wait_visible("#networking")iface = 'cockpit1'self.add_veth(iface, dhcp_cidr="10.111.113.2/20")self.nm_activate_eth(iface)self.wait_for_iface(iface)con_id = testlib.wait(lambda: self.iface_con_id(iface))mac = m.execute(f"cat /sys/class/net/{iface}/address").strip()self.select_iface(iface)b.wait_visible("#network-interface")# On/Off button is disabled, but shows the correct valueb.wait_visible("#interface-switch:disabled")self.wait_onoff("label[for='interface-switch']", val=True)# not editableb.wait_visible('#autoreconnect:disabled')b.wait_not_present("#networking-edit-ipv4")b.wait_not_present("#networking-edit-mac")b.wait_text("#network-interface-mac", mac.upper())# unpriv UI reacts to system changem.execute(f"nmcli device disconnect {iface}")self.wait_onoff("label[for='interface-switch']", val=False)m.execute(f"nmcli connection up '{con_id}'")self.wait_onoff("label[for='interface-switch']", val=True)# UI becomes editable when gaining privilegesb.become_superuser()b.wait_visible('#autoreconnect:not(disabled)')b.wait_visible("#networking-edit-ipv4")b.wait_visible("#networking-edit-mac")b.wait_visible("#interface-switch:not(disabled)")if __name__ == '__main__':testlib.test_main()