This commit is contained in:
Richard Megginson 2025-12-01 11:35:50 -07:00 committed by GitHub
commit b68dffc8f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
64 changed files with 2296 additions and 1315 deletions

View file

@ -8,8 +8,6 @@ on: # yamllint disable-line rule:truthy
types:
- checks_requested
push:
branches:
- main
workflow_dispatch:
permissions:
@ -35,13 +33,6 @@ jobs:
# container
- { image: "centos-9", env: "container-ansible-core-2.16" }
- { image: "centos-9-bootc", env: "container-ansible-core-2.16" }
# broken on non-running dbus
# - { image: "centos-10", env: "container-ansible-core-2.17" }
- { image: "centos-10-bootc", env: "container-ansible-core-2.17" }
- { image: "fedora-41", env: "container-ansible-core-2.17" }
- { image: "fedora-42", env: "container-ansible-core-2.17" }
- { image: "fedora-41-bootc", env: "container-ansible-core-2.17" }
- { image: "fedora-42-bootc", env: "container-ansible-core-2.17" }
env:
TOX_ARGS: "--skip-tags tests::infiniband,tests::nvme,tests::scsi"

View file

@ -31,8 +31,10 @@ network_provider_os_default: "{{
ansible_distribution_major_version is version('7', '<')
else 'nm' }}"
# If NetworkManager.service is running, assume that 'nm' is currently in-use,
# otherwise initscripts
# otherwise initscripts. However, in non-booted environments we don't have
# ansible_facts.services, so use the above OS default.
__network_provider_current: "{{
network_provider_os_default if ansible_facts.services is not defined else
'nm' if 'NetworkManager.service' in ansible_facts.services and
ansible_facts.services['NetworkManager.service']['state'] == 'running'
else 'initscripts' }}"
@ -136,6 +138,9 @@ __network_provider_setup:
nm:
service_name: "{{ __network_service_name_default_nm }}"
packages: "{{ __network_packages_default_nm }}"
nm_offline:
service_name: "{{ __network_service_name_default_nm }}"
packages: "{{ __network_packages_default_nm }}"
initscripts:
service_name: "{{ __network_service_name_default_initscripts }}"
packages: "{{ __network_packages_default_initscripts }}"

View file

@ -71,6 +71,7 @@ import subprocess
import time
import traceback
import logging
import stat
# pylint: disable=import-error, no-name-in-module
from ansible.module_utils.basic import AnsibleModule
@ -1712,7 +1713,7 @@ class RunEnvironment(object):
self._check_mode = None
@property
def ifcfg_header(self):
def managed_file_header(self):
return None
def log(
@ -1728,7 +1729,7 @@ class RunEnvironment(object):
):
raise NotImplementedError()
def run_command(self, argv, encoding=None):
def run_command(self, argv, encoding=None, check_rc=False):
raise NotImplementedError()
def _check_mode_changed(self, old_check_mode, new_check_mode, connections):
@ -1780,11 +1781,11 @@ class RunEnvironmentAnsible(RunEnvironment):
self.module = module
@property
def ifcfg_header(self):
def managed_file_header(self):
return self.module.params["__header"]
def run_command(self, argv, encoding=None):
return self.module.run_command(argv, encoding=encoding)
def run_command(self, argv, encoding=None, check_rc=False):
return self.module.run_command(argv, encoding=encoding, check_rc=check_rc)
def _run_results_push(self, n_connections):
c = []
@ -1935,8 +1936,8 @@ class Cmd(object):
self._is_changed_modified_system = False
self._debug_flags = debug_flags
def run_command(self, argv, encoding=None):
return self.run_env.run_command(argv, encoding=encoding)
def run_command(self, argv, encoding=None, check_rc=False):
return self.run_env.run_command(argv, encoding=encoding, check_rc=check_rc)
@property
def is_changed_modified_system(self):
@ -2030,6 +2031,8 @@ class Cmd(object):
def create(provider, **kwargs):
if provider == "nm":
return Cmd_nm(**kwargs)
if provider == "nm_offline":
return Cmd_nm_offline(**kwargs)
elif provider == "initscripts":
return Cmd_initscripts(**kwargs)
raise MyError("unsupported provider %s" % (provider))
@ -2639,6 +2642,519 @@ class Cmd_nm(Cmd):
###############################################################################
class Cmd_nm_offline(Cmd):
def __init__(self, **kwargs):
Cmd.__init__(self, **kwargs)
self.validate_one_type = ArgValidator_ListConnections.VALIDATE_ONE_MODE_NM
self._checkpoint = None
def profile_path(self, name):
return os.path.join(
"/etc/NetworkManager/system-connections", name + ".nmconnection"
)
def run_prepare(self):
# we can't check any hardware or runtime status, we can just trust the input
pass
# mirror Cmd_nm.connection_create()
def connection_create(self, connections, idx):
connection = connections[idx]
# global/type independent arguments
if "nm.uuid" not in connection:
connection["nm.uuid"] = Util.create_uuid()
if "nm.exists" not in connection:
connection["nm.exists"] = True
argv = [
"nmcli",
"--offline",
"connection",
"add",
"ifname",
connection["interface_name"],
"con-name",
connection["name"],
"type",
connection["type"],
"autoconnect",
"yes" if connection["autoconnect"] else "no",
"connection.autoconnect-retries",
str(connection["autoconnect_retries"]),
"connection.uuid",
connection["nm.uuid"],
]
if connection["cloned_mac"] != "default":
argv.extend(["cloned-mac", connection["cloned_mac"]])
# composite devices
if connection["controller"] is not None:
if connection["port_type"] is None:
self.log_error(
idx,
"connection.port-type must be specified when connection.controller is set",
)
# must use uuid instead of name for controller here
controller_uuid = ArgUtil.connection_find_controller_uuid(
connection["controller"], connections
)
argv.extend(
[
"connection.controller",
controller_uuid,
"connection.port-type",
connection["port_type"],
]
)
# skip IP and other config for composites
return argv
c_ip = connection["ip"]
ip4_addrs = []
ip6_addrs = []
for address in c_ip["address"]:
addr = "{0}/{1}".format(address["address"], address["prefix"])
if address["family"] == socket.AF_INET:
ip4_addrs.append(addr)
elif address["family"] == socket.AF_INET6:
ip6_addrs.append(addr)
else:
self.log_error(idx, "unknown address family %s" % (address["family"]))
argv.extend(
[
"ipv4.method",
"auto" if c_ip["dhcp4"] else "manual" if ip4_addrs else "disabled",
"ipv4.addresses",
", ".join(ip4_addrs),
"ipv6.method",
(
"disabled"
if c_ip["ipv6_disabled"]
else (
"auto"
if c_ip["auto6"]
else (
"manual"
if ip6_addrs
else
# online backend uses legacy "ignore", DTRT for this new backend
"ignore"
)
)
), # "link-local",
"ipv6.addresses",
", ".join(ip6_addrs),
]
)
# gateway
if c_ip["gateway4"]:
argv.extend(["ipv4.gateway", c_ip["gateway4"]])
if c_ip["gateway6"]:
argv.extend(["ipv6.gateway", c_ip["gateway6"]])
# dns*
dns4_addrs = []
dns6_addrs = []
for dns in c_ip["dns"]:
if dns["family"] == socket.AF_INET:
dns4_addrs.append(dns["address"])
elif dns["family"] == socket.AF_INET6:
dns6_addrs.append(dns["address"])
else:
self.log_error(idx, "unknown DNS address family %s" % (dns["family"]))
if dns4_addrs:
argv.extend(["ipv4.dns", ",".join(dns4_addrs)])
if dns6_addrs:
argv.extend(["ipv6.dns", ",".join(dns6_addrs)])
if c_ip["dns_search"]:
# NM only allows to configure ipvN.dns-search when IPvN is enabled
if c_ip["dhcp4"] or ip4_addrs:
argv.extend(["ipv4.dns-search", " ".join(c_ip["dns_search"])])
if c_ip["auto6"] or ip6_addrs:
argv.extend(["ipv6.dns-search", " ".join(c_ip["dns_search"])])
if c_ip["dns_options"]:
argv.extend(
[
"ipv4.dns-options",
",".join(c_ip["dns_options"]),
"ipv6.dns-options",
",".join(c_ip["dns_options"]),
]
)
if c_ip["dns_priority"] != 0:
argv.extend(
[
"ipv4.dns-priority",
str(c_ip["dns_priority"]),
"ipv6.dns-priority",
str(c_ip["dns_priority"]),
]
)
if c_ip["ipv4_ignore_auto_dns"] is not None:
argv.extend(
[
"ipv4.ignore-auto-dns",
"yes" if c_ip["ipv4_ignore_auto_dns"] else "no",
]
)
if c_ip["ipv6_ignore_auto_dns"] is not None:
argv.extend(
[
"ipv6.ignore-auto-dns",
"yes" if c_ip["ipv6_ignore_auto_dns"] else "no",
]
)
# route
if c_ip["route_metric4"] is not None:
argv.extend(["ipv4.route-metric", str(c_ip["route_metric4"])])
if c_ip["route_metric6"] is not None:
argv.extend(["ipv6.route-metric", str(c_ip["route_metric6"])])
# routes
if c_ip.get("route"):
ipv4_routes = []
ipv6_routes = []
for route in c_ip["route"]:
route_str = route["network"]
if route.get("prefix"):
route_str += "/" + str(route["prefix"])
if route.get("gateway"):
route_str += " " + route["gateway"]
if route.get("metric"):
route_str += " " + str(route["metric"])
if route.get("type"):
route_str += " type=" + route["type"]
if route.get("table"):
route_str += " table=" + str(route["table"])
if route.get("src"):
route_str += " src=" + route["src"]
if route["family"] == socket.AF_INET:
ipv4_routes.append(route_str)
elif route["family"] == socket.AF_INET6:
ipv6_routes.append(route_str)
if ipv4_routes:
argv.extend(["ipv4.routes", ",".join(ipv4_routes)])
if ipv6_routes:
argv.extend(["ipv6.routes", ",".join(ipv6_routes)])
# routing rules
if c_ip.get("routing_rule"):
ipv4_rules = []
ipv6_rules = []
for rule in c_ip["routing_rule"]:
rule_parts = []
if rule.get("priority"):
rule_parts.append("priority " + rule["priority"])
if rule.get("from"):
rule_parts.append("from " + rule["from"])
if rule.get("to"):
rule_parts.append("to " + rule["to"])
if rule.get("table"):
rule_parts.append("table " + rule["table"])
if rule_parts:
rule_str = " ".join(rule_parts)
if rule["family"] == socket.AF_INET:
ipv4_rules.append(rule_str)
elif rule["family"] == socket.AF_INET6:
ipv6_rules.append(rule_str)
if ipv4_rules:
argv.extend(["ipv4.routing-rules", " ".join(ipv4_rules)])
if ipv6_rules:
argv.extend(["ipv6.routing-rules", " ".join(ipv6_rules)])
# DHCP options
if c_ip.get("dhcp4_send_hostname") is not None:
argv.extend(
[
"ipv4.dhcp-send-hostname",
"yes" if c_ip["dhcp4_send_hostname"] else "no",
]
)
if c_ip.get("dhcp6_send_hostname") is not None:
argv.extend(
[
"ipv6.dhcp-send-hostname",
"yes" if c_ip["dhcp6_send_hostname"] else "no",
]
)
# zone
if connection.get("zone"):
argv.extend(["connection.zone", connection["zone"]])
# mac address
if connection.get("mac") and connection["mac"] != "default":
if connection["type"] == "wireless":
argv.extend(["802-11-wireless.mac-address", connection["mac"]])
else:
argv.extend(["802-3-ethernet.mac-address", connection["mac"]])
# mtu
if connection.get("mtu"):
if connection["type"] == "wireless":
argv.extend(["802-11-wireless.mtu", str(connection["mtu"])])
else:
argv.extend(["802-3-ethernet.mtu", str(connection["mtu"])])
# ethernet settings
if connection.get("ethernet"):
eth = connection["ethernet"]
if eth.get("autoneg") is not None:
argv.extend(
["802-3-ethernet.auto-negotiate", "yes" if eth["autoneg"] else "no"]
)
if eth.get("speed"):
argv.extend(["802-3-ethernet.speed", str(eth["speed"])])
if eth.get("duplex"):
argv.extend(["802-3-ethernet.duplex", eth["duplex"]])
# type-specific configurations
# bond options[mode, miimon, downdelay, updelay, arp_interval, arp_ip_target, arp_validate, balance-slb, primary,
# primary_reselect, fail_over_mac, use_carrier, ad_select, xmit_hash_policy, resend_igmp, lacp_rate, active_slave, ad_actor_sys_prio,
# ad_actor_system, ad_user_port_key, all_slaves_active, arp_all_targets, min_links, num_grat_arp, num_unsol_na, packets_per_slave,
# tlb_dynamic_lb, lp_interval, peer_notif_delay, arp_missed_max, lacp_active, ns_ip6_target].,
if connection["type"] == "bond":
opts = []
for key, value in connection["bond"].items():
if value is not None:
if key in ["all_ports_active", "use_carrier", "tlb_dynamic_lb"]:
value = int(value)
if key in ["all_ports_active", "packets_per_port"]:
# wokeignore:rule=slave
key = key.replace("port", "slave")
opts.append("{0}={1}".format(key, str(value)))
if opts:
argv.extend(["bond.options", ",".join(opts)])
elif connection["type"] == "bridge":
if connection.get("bridge"):
bridge = connection["bridge"]
if bridge.get("stp") is not None:
argv.extend(["bridge.stp", "yes" if bridge["stp"] else "no"])
if bridge.get("priority") is not None:
argv.extend(["bridge.priority", str(bridge["priority"])])
if bridge.get("forward_delay") is not None:
argv.extend(["bridge.forward-delay", str(bridge["forward_delay"])])
if bridge.get("hello_time") is not None:
argv.extend(["bridge.hello-time", str(bridge["hello_time"])])
if bridge.get("max_age") is not None:
argv.extend(["bridge.max-age", str(bridge["max_age"])])
if bridge.get("ageing_time") is not None:
argv.extend(["bridge.ageing-time", str(bridge["ageing_time"])])
elif connection["type"] == "vlan":
if connection.get("vlan") and connection["vlan"].get("id") is not None:
argv.extend(["vlan.id", str(connection["vlan"]["id"])])
if connection.get("parent"):
argv.extend(["vlan.parent", connection["parent"]])
elif connection["type"] == "macvlan":
if connection.get("macvlan"):
macvlan = connection["macvlan"]
if macvlan.get("mode"):
argv.extend(["macvlan.mode", macvlan["mode"]])
if macvlan.get("promiscuous") is not None:
argv.extend(
[
"macvlan.promiscuous",
"yes" if macvlan["promiscuous"] else "no",
]
)
if macvlan.get("tap") is not None:
argv.extend(["macvlan.tap", "yes" if macvlan["tap"] else "no"])
if connection.get("parent"):
argv.extend(["macvlan.parent", connection["parent"]])
elif connection["type"] == "infiniband":
if connection.get("infiniband"):
ib = connection["infiniband"]
if ib.get("transport_mode"):
argv.extend(["infiniband.transport-mode", ib["transport_mode"]])
if ib.get("p_key") is not None:
argv.extend(["infiniband.p-key", str(ib["p_key"])])
if connection.get("parent"):
argv.extend(["infiniband.parent", connection["parent"]])
elif connection["type"] == "wireless":
if connection.get("wireless"):
wifi = connection["wireless"]
if wifi.get("ssid"):
argv.extend(["802-11-wireless.ssid", wifi["ssid"]])
if wifi.get("key_mgmt"):
argv.extend(["802-11-wireless-security.key-mgmt", wifi["key_mgmt"]])
if wifi.get("password") and wifi["key_mgmt"] in ["wpa-psk", "sae"]:
argv.extend(["802-11-wireless-security.psk", wifi["password"]])
elif connection["type"] == "team":
if connection.get("team") and connection["team"].get("config"):
# Team config is typically JSON, pass as-is
argv.extend(["team.config", connection["team"]["config"]])
# ethtool settings
if connection.get("ethtool"):
ethtool = connection["ethtool"]
# ethtool features
if ethtool.get("features"):
for feature, value in ethtool["features"].items():
if value is not None:
feature_name = feature.replace("_", "-")
if value:
value = "on"
else:
value = "off"
argv.extend(["ethtool.feature-" + feature_name, value])
# ethtool coalesce settings
if ethtool.get("coalesce"):
for param, value in ethtool["coalesce"].items():
if value is not None:
param_name = param.replace("_", "-")
argv.extend(["ethtool.coalesce-" + param_name, str(value)])
# ethtool ring settings
if ethtool.get("ring"):
for param, value in ethtool["ring"].items():
if value is not None:
param_name = param.replace("_", "-")
argv.extend(["ethtool.ring-" + param_name, str(value)])
# ieee802_1x settings
if connection.get("ieee802_1x"):
ieee = connection["ieee802_1x"]
if ieee.get("eap"):
argv.extend(
[
"802-1x.eap",
(
",".join(ieee["eap"])
if isinstance(ieee["eap"], list)
else ieee["eap"]
),
]
)
if ieee.get("identity"):
argv.extend(["802-1x.identity", ieee["identity"]])
if ieee.get("password"):
argv.extend(["802-1x.password", ieee["password"]])
if ieee.get("ca_cert"):
argv.extend(["802-1x.ca-cert", ieee["ca_cert"]])
if ieee.get("client_cert"):
argv.extend(["802-1x.client-cert", ieee["client_cert"]])
if ieee.get("private_key"):
argv.extend(["802-1x.private-key", ieee["private_key"]])
if ieee.get("private_key_password"):
argv.extend(
["802-1x.private-key-password", ieee["private_key_password"]]
)
# match settings
if connection.get("match"):
match = connection["match"]
if match.get("path"):
match_paths = (
match["path"]
if isinstance(match["path"], list)
else [match["path"]]
)
argv.extend(["match.path", ",".join(match_paths)])
if match.get("driver"):
match_drivers = (
match["driver"]
if isinstance(match["driver"], list)
else [match["driver"]]
)
argv.extend(["match.driver", ",".join(match_drivers)])
if match.get("interface_name"):
match_names = (
match["interface_name"]
if isinstance(match["interface_name"], list)
else [match["interface_name"]]
)
argv.extend(["match.interface-name", ",".join(match_names)])
return argv
def run_action_present(self, idx):
connection = self.connections[idx]
if not connection.get("type"):
# this is mostly test teardown, nobody uses that in container builds
if connection["state"] == "down":
self.log_info(idx, "nm_offline ignoring 'state: down'")
return
self.log_error(idx, "Connection 'type' not specified")
return
# DEBUG, drop for final commit
self.log_info(
idx, "XXX nm_offline provider action_present connection: %r" % connection
)
# create the profile
(rc, out, err) = self.run_command(
self.connection_create(self.connections, idx), check_rc=True
)
# Should Not Happen™, but make sure
if not out.strip():
self.log_error(
idx, "nmcli --offline returned no output (rc %d); err: %s" % (rc, err)
)
return
path = self.profile_path(connection["name"])
if self.check_mode == CheckMode.REAL_RUN:
with open(path, "w") as f:
f.write(self.run_env.managed_file_header)
f.write(out.decode("UTF-8"))
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR)
os.chown(path, 0, 0)
# nmcli always generates a new UUID, so comparing with existing file is moot
# always treat as changed, good enough for container builds
self.connections_data_set_changed(idx)
def run_action_absent(self, idx):
connection = self.connections[idx]
# DEBUG, drop for final commit
self.log_info(
idx, "XXX nm_offline provider action_absent connection: %r" % connection
)
try:
os.unlink(self.profile_path(connection["name"]))
self.connections_data_set_changed(idx)
except FileNotFoundError:
self.log_debug(
idx, "nm_offline: profile '%s' already absent" % connection["name"]
)
def run_action_up(self, idx):
# no runtime ops in offline provider
pass
def run_action_down(self, idx):
# no runtime ops in offline provider
pass
###############################################################################
class Cmd_initscripts(Cmd):
def __init__(self, **kwargs):
Cmd.__init__(self, **kwargs)
@ -2763,7 +3279,7 @@ class Cmd_initscripts(Cmd):
)
new_content = IfcfgUtil.content_from_dict(
ifcfg_all, header=self.run_env.ifcfg_header
ifcfg_all, header=self.run_env.managed_file_header
)
if old_content == new_content:

View file

@ -18,6 +18,7 @@ galaxy_info:
- "9"
galaxy_tags:
- centos
- containerbuild
- el6
- el7
- el8

View file

@ -4,6 +4,13 @@
- name: Ensure ansible_facts used by role
include_tasks: tasks/set_facts.yml
- name: Switch to offline NM backend if host is not booted
set_fact:
network_provider: "nm_offline"
when:
- network_provider == "nm"
- not __network_is_booted
- name: Print network provider
debug:
msg: "Using network provider: {{ network_provider }}"
@ -14,7 +21,7 @@
msg: Only the `nm` provider supports using the `network_state` variable
when:
- network_state != {}
- network_provider == "initscripts"
- network_provider != "nm"
- name: Abort applying the network state configuration if the system version
of the managed host is below 8
@ -151,10 +158,10 @@
- name: Enable and start NetworkManager
service:
name: "{{ network_service_name }}"
state: started
state: "{{ 'started' if __network_is_booted else omit }}"
enabled: true
when:
- network_provider == "nm" or network_state != {}
- network_provider in ["nm", "nm_offline"] or network_state != {}
no_log: true
# If any 802.1x connections are used, the wpa_supplicant
@ -162,10 +169,10 @@
- name: Enable and start wpa_supplicant
service:
name: wpa_supplicant
state: started
state: "{{ 'started' if __network_is_booted else omit }}"
enabled: true
when:
- network_provider == "nm"
- network_provider in ["nm", "nm_offline"]
- __network_wpa_supplicant_required
- name: Enable network service

View file

@ -19,6 +19,27 @@
set_fact:
__network_is_ostree: "{{ __ostree_booted_stat.stat.exists }}"
- name: Determine if system is booted with systemd
when: __network_is_booted is not defined
block:
- name: Run systemctl
# noqa command-instead-of-module
command: systemctl is-system-running
register: __is_system_running
changed_when: false
check_mode: false
failed_when: false
- name: Require installed systemd
fail:
msg: "Error: This role requires systemd to be installed."
when: '"No such file or directory" in __is_system_running.msg | d("")'
- name: Set flag to indicate that systemd runtime operations are available
set_fact:
# see https://www.man7.org/linux/man-pages/man1/systemctl.1.html#:~:text=is-system-running%20output
__network_is_booted: "{{ __is_system_running.stdout != 'offline' }}"
- name: Check which services are running
service_facts:
no_log: true

View file

@ -1,2 +1,2 @@
[defaults]
task_timeout=480
task_timeout=600

View file

@ -0,0 +1,3 @@
---
collections:
- name: community.general

View file

@ -5,21 +5,14 @@
vars:
interface: 802-1x-test
tasks:
- name: "INIT: 802.1x tests"
debug:
msg: "##################################################"
- name: Include the task 'setup_802.1x.yml'
include_tasks: tasks/setup_802.1x.yml
- name: Test configuring 802.1x authentication
block:
- name: "TEST: 802.1x profile with private key password and ca cert"
debug:
msg: "##################################################"
- name: Import network role
import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: Test setting 802.1x authentication
include_tasks: tasks/run_test.yml
vars:
lsr_description: Test 802.1x authentication
lsr_setup:
- tasks/setup_802.1x.yml
lsr_test:
- network_connections:
- name: "{{ interface }}"
interface_name: veth2
state: up
@ -38,28 +31,25 @@
- none
client_cert: /etc/pki/tls/client.pem
ca_cert: /etc/pki/tls/cacert.pem
- name: Ensure ping command is present
package:
name: iputils
state: present
use: "{{ (__network_is_ostree | d(false)) |
ternary('ansible.posix.rhel_rpm_ostree', omit) }}"
- name: "TEST: I can ping the EAP server"
command: ping -c1 203.0.113.1
changed_when: false
- name: Import network role
import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
persistent_state: absent
state: down
- name: >-
TEST: 802.1x profile with unencrypted private key,
domain suffix match, and system ca certs
debug:
msg: "##################################################"
lsr_assert:
- what: tasks/assert_command_output.yml
condition: "{{ __network_is_booted }}"
lsr_command: ping -c1 203.0.113.1
lsr_packages: [iputils]
lsr_cleanup:
- what: tasks/down_profile+delete_interface.yml
condition: "{{ __network_is_booted and not __bootc_validation | default(false) }}"
profile: "{{ interface }}"
lsr_persistent_state: absent
- tasks/check_network_dns.yml
- name: Stop test if building image or validation is enabled
meta: end_host
when: ansible_connection | d("") == "buildah" or __bootc_validation | default(false)
- name: >-
Test 802.1x profile with unencrypted private key, domain suffix match, and system ca certs
block:
- name: Copy cacert to system truststore
copy:
src: cacert.pem

View file

@ -6,145 +6,97 @@
type: veth
interface: veth0
tasks:
- name: Include the task 'show_interfaces.yml'
include_tasks: tasks/show_interfaces.yml
- name: Include the task 'manage_test_interface.yml'
include_tasks: tasks/manage_test_interface.yml
- name: Test setting auto_gateway to true
include_tasks: tasks/run_test.yml
vars:
state: present
- name: Include the task 'assert_device_present.yml'
include_tasks: tasks/assert_device_present.yml
- name: >-
TEST: I can configure an interface with auto_gateway enabled
debug:
msg: "##################################################"
- name: Import network role
import_role:
name: linux-system-roles.network
lsr_description: Test auto_gateway setting to true
lsr_setup:
- what: tasks/manage_test_interface.yml
state: present
- tasks/assert_device_present.yml
lsr_test:
- network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
auto_gateway: true
dhcp4: false
auto6: false
address:
- "2001:db8::2/64"
- "203.0.113.2/24"
gateway6: "2001:db8::1"
gateway4: "203.0.113.1"
# change the default route metric to higher value so that it will
# not take precedence over other routes or not ignore other
# routes
route_metric4: 65535
lsr_assert:
- tasks/assert_device_present.yml
- what: tasks/assert_profile_present.yml
profile: "{{ interface }}"
- what: tasks/assert_command_output.yml
condition: "{{ __network_is_booted }}"
lsr_command: ip route
lsr_stdout: default via 203.0.113.1 dev {{ interface }}
- what: tasks/assert_command_output.yml
condition: "{{ __network_is_booted and network_provider == 'nm' }}"
lsr_command: ip -6 route
lsr_stdout: default via 2001:db8::1 dev {{ interface }}
lsr_cleanup:
- what: tasks/down_profile+delete_interface.yml
condition: "{{ __network_is_booted }}"
profile: "{{ interface }}"
lsr_persistent_state: absent
- what: tasks/manage_test_interface.yml
state: absent
- tasks/check_network_dns.yml
- name: Stop test if building image or validation is enabled
meta: end_host
when: ansible_connection | d("") == "buildah" or __bootc_validation | default(false)
- name: Test setting auto_gateway to false
include_tasks: tasks/run_test.yml
vars:
network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
auto_gateway: true
dhcp4: false
auto6: false
address:
- "2001:db8::2/64"
- "203.0.113.2/24"
gateway6: "2001:db8::1"
gateway4: "203.0.113.1"
# change the default route metric to higher value so that it will
# not take precedence over other routes or not ignore other
# routes
route_metric4: 65535
- name: Include the task 'assert_device_present.yml' again
include_tasks: tasks/assert_device_present.yml
- name: Include the task 'assert_profile_present.yml'
include_tasks: tasks/assert_profile_present.yml
vars:
profile: "{{ interface }}"
- name: "Show ipv4 routes"
command: "ip route"
register: ipv4_routes
changed_when: false
- name: "Assert default ipv4 route is present"
assert:
that: __test_str in ipv4_routes.stdout
vars:
__test_str: default via 203.0.113.1 dev {{ interface }}
- name: "Get ipv6 routes"
command: "ip -6 route"
register: ipv6_route
changed_when: false
- name: "Assert default ipv6 route is present"
assert:
that: __test_str in ipv6_route.stdout
vars:
__test_str: default via 2001:db8::1 dev {{ interface }}
when: network_provider == "nm"
- name: "TEARDOWN: remove profiles."
debug:
msg: "##################################################"
- name: Import network role to remove interface
import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
persistent_state: absent
state: down
ignore_errors: true # noqa ignore-errors
- name: Include the task 'manage_test_interface.yml' to remove interface
include_tasks: tasks/manage_test_interface.yml
vars:
state: absent
- name: >-
TEST: I can configure an interface with auto_gateway disabled
debug:
msg: "##################################################"
- name: Include the task 'manage_test_interface.yml' to disable auto_gateway
include_tasks: tasks/manage_test_interface.yml
vars:
state: present
- name: Import network role to disable auto_gateway
import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
auto_gateway: false
dhcp4: false
auto6: false
address:
- "2001:db8::2/64"
- "203.0.113.2/24"
gateway6: "2001:db8::1"
gateway4: "203.0.113.1"
- name: Include the task 'assert_device_present.yml' - 3
include_tasks: tasks/assert_device_present.yml
- name: Include the task 'assert_profile_present.yml' again
include_tasks: tasks/assert_profile_present.yml
vars:
profile: "{{ interface }}"
- name: "Show ipv4 routes again"
command: "ip route"
register: ipv4_routes
changed_when: false
- name: "Assert default ipv4 route is absent"
assert:
that: __test_str not in ipv4_routes.stdout
vars:
__test_str: default via 203.0.113.1 dev {{ interface }}
- name: "Get ipv6 routes again"
command: "ip -6 route"
register: ipv6_route
changed_when: false
- name: "Assert default ipv6 route is absent"
assert:
that: __test_str not in ipv6_route.stdout
vars:
__test_str: default via 2001:db8::1 dev {{ interface }}
when: network_provider == "nm"
- name: "TEARDOWN: remove profiles. again"
debug:
msg: "##################################################"
- name: Import network role to remove interface again
import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
persistent_state: absent
state: down
ignore_errors: true # noqa ignore-errors
- name: Include the task 'manage_test_interface.yml' to remove interface again
include_tasks: tasks/manage_test_interface.yml
vars:
state: absent
- name: Verify network state restored to default
include_tasks: tasks/check_network_dns.yml
lsr_description: Test auto_gateway setting to false
lsr_setup:
- what: tasks/manage_test_interface.yml
state: present
- tasks/assert_device_present.yml
lsr_test:
- network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
auto_gateway: false
dhcp4: false
auto6: false
address:
- "2001:db8::2/64"
- "203.0.113.2/24"
gateway6: "2001:db8::1"
gateway4: "203.0.113.1"
lsr_assert:
- tasks/assert_device_present.yml
lsr_assert_when:
- what: tasks/assert_profile_present.yml
profile: "{{ interface }}"
- what: tasks/assert_command_output.yml
condition: "{{ __network_is_booted }}"
lsr_command: ip route
lsr_not_stdout: default via 203.0.113.1 dev {{ interface }}
- what: tasks/assert_command_output.yml
condition: "{{ __network_is_booted and network_provider == 'nm' }}"
lsr_command: ip -6 route
lsr_not_stdout: default via 2001:db8::1 dev {{ interface }}
lsr_cleanup:
- what: tasks/down_profile+delete_interface.yml
condition: "{{ __network_is_booted }}"
profile: "{{ interface }}"
lsr_persistent_state: absent
- what: tasks/manage_test_interface.yml
state: absent
- tasks/check_network_dns.yml

View file

@ -72,26 +72,85 @@
- "{{ controller_profile }}"
- "{{ port1_profile }}"
- "{{ port2_profile }}"
- name: "** TEST check polling interval"
command: grep 'Polling Interval'
/proc/net/bonding/{{ controller_device }}
register: result
until: "'110' in result.stdout"
changed_when: false
- name: "** TEST check IPv4"
command: ip -4 a s {{ controller_device }}
register: result
until: "'192.0.2' in result.stdout"
retries: 20
delay: 2
changed_when: false
- name: "** TEST check IPv6"
command: ip -6 a s {{ controller_device }}
register: result
until: "'2001' in result.stdout"
retries: 20
delay: 2
changed_when: false
- name: Runtime checks for booted systems
when: __network_is_booted | bool
block:
- name: "** TEST check polling interval"
command: grep 'Polling Interval'
/proc/net/bonding/{{ controller_device }}
register: result
until: "'110' in result.stdout"
changed_when: false
- name: "** TEST check IPv4"
command: ip -4 a s {{ controller_device }}
register: result
until: "'192.0.2' in result.stdout"
retries: 20
delay: 2
changed_when: false
- name: "** TEST check IPv6"
command: ip -6 a s {{ controller_device }}
register: result
until: "'2001' in result.stdout"
retries: 20
delay: 2
changed_when: false
# These are primarily interesting for non-booted systems; but let's
# check on booted systems too, to ensure the assertions are valid
- name: NM Config file checks
when:
- network_provider != "initscripts"
- ansible_distribution_major_version | int >= 9
block:
- name: Read controller config
slurp:
src: "/etc/NetworkManager/system-connections/{{ controller_profile }}.nmconnection"
register: controller_config_b64
- name: Check controller config
assert:
that:
# [connection]
- "'id=' + controller_profile in controller_config"
- "'type=bond' in controller_config"
- "'interface-name=' + controller_device in controller_config"
# [bond]
- "'mode=active-backup' in controller_config"
- "'miimon=110' in controller_config"
# [ipv4]
- "'method=auto' in controller_config"
- "'route-metric=65535' in controller_config"
fail_msg: "{{ controller_profile }} is bad: {{ controller_config }}"
vars:
controller_config: "{{ controller_config_b64.content | b64decode }}"
- name: Read port configs
loop:
- { name: "{{ port1_profile }}", iface_name: "{{ dhcp_interface1 }}" }
- { name: "{{ port2_profile }}", iface_name: "{{ dhcp_interface2 }}" }
slurp:
src: "/etc/NetworkManager/system-connections/{{ item.name }}.nmconnection"
register: port1_config_b64
- name: Check port configs
loop: "{{ port1_config_b64.results }}"
vars:
port_config: "{{ item.content | b64decode }}"
assert:
that:
# [connection]
- "'id=' + item.item.name in port_config"
- "'type=ethernet' in port_config"
# that points to UUID of controller, a bit cumbersome to match; but let's assume nmcli DTRT
- "'controller=' in port_config"
- "'interface-name=' + item.item.iface_name in port_config"
- "'port-type=bond' in port_config"
- "'[ipv4]' not in port_config"
- "'[ipv6]' not in port_config"
fail_msg: "{{ item.item.name }} is bad: {{ port_config }}"
always:
- name: Clean up the test devices and the connection profiles
tags:
@ -116,6 +175,7 @@
command: ip link del {{ controller_device }}
failed_when: false
changed_when: false
when: __network_is_booted | bool
- name: Import the task 'remove_test_interfaces_with_dhcp.yml'
import_tasks: tasks/remove_test_interfaces_with_dhcp.yml
- name: "Restore the /etc/resolv.conf for initscript"
@ -125,3 +185,4 @@
changed_when: false
- name: Verify network state restored to default
include_tasks: tasks/check_network_dns.yml
when: __network_is_booted | bool

View file

@ -54,54 +54,80 @@
interface_name: "{{ dhcp_interface2 }}"
controller: "{{ controller_profile }}"
- name: Verify nmcli cloned-mac-address entry
command: >-
nmcli -f 802-3-ethernet.cloned-mac-address con show {{ item.name }}
register: cloned_mac_address
ignore_errors: true
changed_when: false
loop:
- {name: "{{ controller_profile }}", mac: "12:23:34:45:56:60"}
- {name: "{{ port1_profile }}", mac: "12:23:34:45:56:61"}
- {name: "{{ port2_profile }}", mac: "--"}
- name: Verify nm provider
when: network_provider == 'nm'
block:
- name: Verify nmcli cloned-mac-address entry
command: >-
nmcli -f 802-3-ethernet.cloned-mac-address con show {{ item.name }}
register: cloned_mac_address
ignore_errors: true
changed_when: false
loop:
- {name: "{{ controller_profile }}", mac: "12:23:34:45:56:60"}
- {name: "{{ port1_profile }}", mac: "12:23:34:45:56:61"}
- {name: "{{ port2_profile }}", mac: "--"}
- name: >
Assert that cloned-mac-address addresses are configured correctly
assert:
that:
- item.stdout.endswith(item.item.mac)
msg: cloned-mac-address is configured incorrectly
loop: "{{ cloned_mac_address.results }}"
when: network_provider == 'nm'
- name: >
Assert that cloned-mac-address addresses are configured correctly
assert:
that:
- item.stdout.endswith(item.item.mac)
msg: cloned-mac-address is configured incorrectly
loop: "{{ cloned_mac_address.results }}"
- name: Verify the MAC address in {{ controller_profile }}
command: >-
grep 'MACADDR'
/etc/sysconfig/network-scripts/ifcfg-{{ controller_profile }}
register: mac_address_controller
ignore_errors: true
changed_when: false
# mostly interesting for offline provider, but let's cross-check with
# online NM to ensure the conditions are valid - except that on some
# older versions of NM, the connection files are not created, so we
# skip this test on those versions.
- name: Verify NM config files
when:
- network_provider.startswith('nm')
- ansible_facts['distribution_major_version'] | int >= 9
block:
- name: Read profile config files
slurp:
src: "/etc/NetworkManager/system-connections/{{ item }}.nmconnection"
register: config_b64
loop:
- "{{ controller_profile }}"
- "{{ port1_profile }}"
- "{{ port2_profile }}"
- name: Check profile config files
assert:
that:
- "'cloned-mac-address=12:23:34:45:56:60' in config_b64.results[0].content | b64decode"
- "'cloned-mac-address=12:23:34:45:56:61' in config_b64.results[1].content | b64decode"
- "'cloned-mac-adress=' not in config_b64.results[2].content | b64decode"
- name: Verify initscripts provider
when: network_provider == 'initscripts'
block:
- name: Verify the MAC address in {{ controller_profile }}
command: >-
grep 'MACADDR'
/etc/sysconfig/network-scripts/ifcfg-{{ controller_profile }}
register: mac_address_controller
ignore_errors: true
changed_when: false
- name: Verify the MAC address in {{ port1_profile }}
command: >-
grep 'MACADDR'
/etc/sysconfig/network-scripts/ifcfg-{{ port1_profile }}
register: mac_address_port1
ignore_errors: true
changed_when: false
when: network_provider == 'initscripts'
- name: Verify the MAC address in {{ port1_profile }}
command: >-
grep 'MACADDR'
/etc/sysconfig/network-scripts/ifcfg-{{ port1_profile }}
register: mac_address_port1
ignore_errors: true
changed_when: false
- name: Assert that MAC addresses are configured correctly for bonding
interface
assert:
that:
- mac_address_controller.stdout is search("12:23:34:45:56:60")
- mac_address_port1.stdout is search("12:23:34:45:56:61")
msg: the MAC addresses are configured incorrectly for bonding
interface
when: network_provider == 'initscripts'
- name: Assert that MAC addresses are configured correctly for bonding
interface
assert:
that:
- mac_address_controller.stdout is search("12:23:34:45:56:60")
- mac_address_port1.stdout is search("12:23:34:45:56:61")
msg: the MAC addresses are configured incorrectly for bonding
interface
always:
- name: Clean up the test devices and the connection profiles
@ -127,8 +153,10 @@
command: ip link del {{ controller_device }}
failed_when: false
changed_when: false
when: __network_is_booted | bool
- name: Import the task 'remove_test_interfaces_with_dhcp.yml'
import_tasks: tasks/remove_test_interfaces_with_dhcp.yml
when: __network_is_booted | bool
- name: Restore the /etc/resolv.conf for initscript
command: mv -vf /etc/resolv.conf.bak /etc/resolv.conf
when:

View file

@ -11,6 +11,7 @@
dhcp_interface2: test2
lsr_fail_debug:
- __network_connections_result
- __install_status
bond_options_to_assert:
- {key: 'mode', value: '802.3ad'}
- {key: 'ad_actor_sys_prio', value: '65535'}
@ -50,7 +51,44 @@
- tasks/create_test_interfaces_with_dhcp.yml
- tasks/assert_dhcp_device_present.yml
lsr_test:
- tasks/create_bond_profile.yml
- network_connections:
# Create a bond controller
- name: "{{ controller_profile }}"
state: up
type: bond
interface_name: "{{ controller_device }}"
bond:
mode: 802.3ad
ad_actor_sys_prio: 65535
ad_actor_system: 00:00:5e:00:53:5d
ad_select: stable
ad_user_port_key: 1023
all_ports_active: true
downdelay: 0
lacp_rate: slow
lp_interval: 128
miimon: 110
min_links: 0
num_grat_arp: 64
primary_reselect: better
resend_igmp: 225
updelay: 0
use_carrier: true
xmit_hash_policy: encap2+3
ip:
route_metric4: 65535
# add an ethernet to the bond
- name: "{{ port1_profile }}"
state: up
type: ethernet
interface_name: "{{ dhcp_interface1 }}"
controller: "{{ controller_profile }}"
# add a second ethernet to the bond
- name: "{{ port2_profile }}"
state: up
type: ethernet
interface_name: "{{ dhcp_interface2 }}"
controller: "{{ controller_profile }}"
lsr_assert:
- tasks/assert_controller_device_present.yml
- tasks/assert_bond_port_profile_present.yml
@ -59,6 +97,10 @@
- tasks/cleanup_bond_profile+device.yml
- tasks/remove_test_interfaces_with_dhcp.yml
- name: Stop test if building image or validation is enabled
meta: end_host
when: ansible_connection | d("") == "buildah" or __bootc_validation | default(false)
- name: "Reset bond options to assert"
set_fact:
bond_options_to_assert:
@ -83,7 +125,32 @@
- tasks/create_test_interfaces_with_dhcp.yml
- tasks/assert_dhcp_device_present.yml
lsr_test:
- tasks/create_bond_profile_reconfigure.yml
- network_connections:
# Create a bond controller
- name: "{{ controller_profile }}"
state: up
type: bond
interface_name: "{{ controller_device }}"
bond:
mode: active-backup
arp_interval: 60
arp_ip_target: 192.0.2.128
arp_validate: none
primary: "{{ dhcp_interface1 }}"
ip:
route_metric4: 65535
# add an ethernet to the bond
- name: "{{ port1_profile }}"
state: up
type: ethernet
interface_name: "{{ dhcp_interface1 }}"
controller: "{{ controller_profile }}"
# add a second ethernet to the bond
- name: "{{ port2_profile }}"
state: up
type: ethernet
interface_name: "{{ dhcp_interface2 }}"
controller: "{{ controller_profile }}"
lsr_assert:
- tasks/assert_bond_options.yml
lsr_cleanup:

View file

@ -29,7 +29,44 @@
- tasks/create_test_interfaces_with_dhcp.yml
- tasks/assert_dhcp_device_present.yml
lsr_test:
- tasks/create_bond_profile.yml
- network_connections:
# Create a bond controller
- name: "{{ controller_profile }}"
state: up
type: bond
interface_name: "{{ controller_device }}"
bond:
mode: 802.3ad
ad_actor_sys_prio: 65535
ad_actor_system: 00:00:5e:00:53:5d
ad_select: stable
ad_user_port_key: 1023
all_ports_active: true
downdelay: 0
lacp_rate: slow
lp_interval: 128
miimon: 110
min_links: 0
num_grat_arp: 64
primary_reselect: better
resend_igmp: 225
updelay: 0
use_carrier: true
xmit_hash_policy: encap2+3
ip:
route_metric4: 65535
# add an ethernet to the bond
- name: "{{ port1_profile }}"
state: up
type: ethernet
interface_name: "{{ dhcp_interface1 }}"
controller: "{{ controller_profile }}"
# add a second ethernet to the bond
- name: "{{ port2_profile }}"
state: up
type: ethernet
interface_name: "{{ dhcp_interface2 }}"
controller: "{{ controller_profile }}"
- tasks/create_bond_port_match_by_mac.yml
lsr_assert:
- tasks/assert_controller_device_present.yml

View file

@ -5,51 +5,36 @@
vars:
interface: LSR-TST-br31
tasks:
- name: Include the task 'show_interfaces.yml'
include_tasks: tasks/show_interfaces.yml
- name: Include the task 'assert_device_absent.yml'
include_tasks: tasks/assert_device_absent.yml
- name: Add test bridge
include_role:
name: linux-system-roles.network
- name: Include the task 'run_test.yml'
include_tasks: tasks/run_test.yml
vars:
network_connections:
- name: "{{ interface }}"
interface_name: "{{ interface }}"
state: up
type: bridge
ip:
dhcp4: false
auto6: true
- name: Assert device present
include_tasks: tasks/assert_device_present.yml
- name: Assert profile present
include_tasks: tasks/assert_profile_present.yml
vars:
profile: "{{ interface }}"
- name: Include the task 'down_profile+delete_interface.yml'
include_tasks: tasks/down_profile+delete_interface.yml
vars:
profile: "{{ interface }}"
# FIXME: assert profile/device down
- name: Include the task 'remove_profile.yml'
include_tasks: tasks/remove_profile.yml
vars:
profile: "{{ interface }}"
- name: Assert profile absent
include_tasks: tasks/assert_profile_absent.yml
vars:
profile: "{{ interface }}"
- name: Assert device absent
include_tasks: tasks/assert_device_absent.yml
- name: Verify network state restored to default
include_tasks: tasks/check_network_dns.yml
lsr_description: Test configuring bridges
lsr_setup:
- tasks/show_interfaces.yml
- what: tasks/assert_device_absent.yml
condition: "{{ not __bootc_validation | d(false) }}"
lsr_test:
- network_connections:
- name: "{{ interface }}"
interface_name: "{{ interface }}"
state: up
type: bridge
ip:
dhcp4: false
auto6: true
lsr_assert:
- tasks/assert_device_present.yml
- what: tasks/assert_profile_present.yml
profile: "{{ interface }}"
lsr_cleanup:
- what: tasks/down_profile+delete_interface.yml
condition: "{{ __network_is_booted }}"
profile: "{{ interface }}"
lsr_persistent_state: absent
- what: tasks/remove_profile.yml
profile: "{{ interface }}"
- what: tasks/assert_profile_absent.yml
profile: "{{ interface }}"
- what: tasks/assert_device_absent.yml
profile: "{{ interface }}"
- tasks/check_network_dns.yml

View file

@ -6,134 +6,154 @@
type: veth
interface: ethtest0
tasks:
- name: Include the task 'show_interfaces.yml'
include_tasks: tasks/show_interfaces.yml
- name: Include the task 'manage_test_interface.yml'
include_tasks: tasks/manage_test_interface.yml
- name: Test dns support
include_tasks: tasks/run_test.yml
vars:
state: present
- name: Include the task 'assert_device_present.yml'
include_tasks: tasks/assert_device_present.yml
- name: Include network role
include_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
interface_name: "{{ interface }}"
state: up
type: ethernet
autoconnect: true
ip:
route_metric4: 100
dhcp4: false
gateway4: 192.0.2.1
dns_priority: 9999
dns:
- 192.0.2.2
- 198.51.100.5
- 2001:db8::20
dns_search:
- example.com
- example.org
dns_options:
- no-aaaa
- rotate
- timeout:1
route_metric6: -1
auto6: false
gateway6: 2001:db8::1
address:
- 192.0.2.3/24
- 198.51.100.3/26
- 2001:db8::80/7
route:
- network: 198.51.100.128
prefix: 26
gateway: 198.51.100.1
metric: 2
- network: 198.51.100.64
prefix: 26
gateway: 198.51.100.6
metric: 4
route_append_only: false
rule_append_only: true
- name: Verify nmcli connection DNS entry for IPv4
shell: |
set -euxo pipefail
nmcli connection show {{ interface }} | grep ipv4.dns
register: ipv4_dns
ignore_errors: true
changed_when: false
- name: Verify nmcli connection DNS entry for IPv6
shell: |
set -euxo pipefail
nmcli connection show {{ interface }} | grep ipv6.dns
register: ipv6_dns
ignore_errors: true
changed_when: false
- name: "Assert that DNS addresses are configured correctly"
assert:
that:
- "'192.0.2.2' in ipv4_dns.stdout"
- "'198.51.100.5' in ipv4_dns.stdout"
- "'2001:db8::20' in ipv6_dns.stdout"
msg: "DNS addresses are configured incorrectly"
- name: "Assert that DNS search domains are configured correctly"
assert:
that:
- "'example.com' in ipv4_dns.stdout"
- "'example.org' in ipv4_dns.stdout"
- "'example.com' in ipv6_dns.stdout"
- "'example.org' in ipv6_dns.stdout"
msg: "DNS search domains are configured incorrectly"
- name: "Assert that DNS options are configured correctly"
assert:
that:
- "'no-aaaa' in ipv4_dns.stdout"
- "'rotate' in ipv4_dns.stdout"
- "'timeout:1' in ipv4_dns.stdout"
- "'no-aaaa' in ipv6_dns.stdout"
- "'rotate' in ipv6_dns.stdout"
- "'timeout:1' in ipv6_dns.stdout"
msg: "DNS options are configured incorrectly"
- name: "Assert that DNS priority is configured correctly"
assert:
that:
- "'9999' in ipv4_dns.stdout"
- "'9999' in ipv6_dns.stdout"
msg: "DNS priority is configured incorrectly"
- name: Include the tasks 'down_profile+delete_interface.yml'
include_tasks: tasks/down_profile+delete_interface.yml
vars:
profile: "{{ interface }}"
# FIXME: assert profile/device down
- name: Include the task 'remove_profile.yml'
include_tasks: tasks/remove_profile.yml
vars:
profile: "{{ interface }}"
- name: Include the task 'assert_profile_absent.yml'
include_tasks: tasks/assert_profile_absent.yml
vars:
profile: "{{ interface }}"
- name: Include the task 'assert_device_absent.yml'
include_tasks: tasks/assert_device_absent.yml
- name: Verify network state restored to default
include_tasks: tasks/check_network_dns.yml
lsr_description: Test dns support
lsr_setup:
- what: tasks/manage_test_interface.yml
state: present
- tasks/assert_device_present.yml
lsr_test:
- network_connections:
- name: "{{ interface }}"
interface_name: "{{ interface }}"
state: up
type: ethernet
autoconnect: true
ip:
route_metric4: 100
dhcp4: false
gateway4: 192.0.2.1
dns_priority: 9999
dns:
- 192.0.2.2
- 198.51.100.5
- 2001:db8::20
dns_search:
- example.com
- example.org
dns_options:
- no-aaaa
- rotate
- timeout:1
route_metric6: -1
auto6: false
gateway6: 2001:db8::1
address:
- 192.0.2.3/24
- 198.51.100.3/26
- 2001:db8::80/7
route:
- network: 198.51.100.128
prefix: 26
gateway: 198.51.100.1
metric: 2
- network: 198.51.100.64
prefix: 26
gateway: 198.51.100.6
metric: 4
route_append_only: false
rule_append_only: true
lsr_assert:
- what: tasks/assert_connection_settings.yml
condition: "{{ network_provider == 'nm' }}"
lsr_connection_name: "{{ interface }}"
lsr_connection_settings:
- section: connection
option: id
value: "{{ interface }}"
- section: connection
option: interface-name
value: "{{ interface }}"
- section: connection
option: type
value: ethernet
nmvalue: 802-3-ethernet
- section: ipv4
option: route-metric
value: "100"
- section: ipv4
option: dns
value: 192.0.2.2;198.51.100.5;
nmvalue: 192.0.2.2,198.51.100.5
- section: ipv4
option: dns-search
value: example.com;example.org;
nmvalue: example.com,example.org
- section: ipv6
option: dns
value: 2001:db8::20;
nmvalue: 2001:db8::20
- section: ipv6
option: dns-search
value: example.com;example.org;
nmvalue: example.com,example.org
- section: ipv4
option: dns-options
value: no-aaaa;rotate;timeout:1;
nmvalue: no-aaaa,rotate,timeout:1
- section: ipv6
option: dns-options
value: no-aaaa;rotate;timeout:1;
nmvalue: no-aaaa,rotate,timeout:1
- section: ipv4
option: dns-priority
value: 9999
- section: ipv6
option: dns-priority
value: 9999
- section: ipv4
option: method
value: manual
- section: ipv6
option: method
value: manual
- section: ipv4
option: address1
value: 192.0.2.3/24
nmvalue: false
- section: ipv4
option: address2
value: 198.51.100.3/26
nmvalue: false
- section: ipv4
option: addresses
nmvalue: 192.0.2.3/24, 198.51.100.3/26
- section: ipv6
option: address1
value: 2001:db8::80/7
nmvalue: false
- section: ipv6
option: addresses
nmvalue: 2001:db8::80/7
- section: ipv4
option: gateway
value: 192.0.2.1
- section: ipv6
option: gateway
value: 2001:db8::1
- section: ipv4
option: route1
value: 198.51.100.128/26,198.51.100.1,2
nmvalue: false
- section: ipv4
option: route2
value: 198.51.100.64/26,198.51.100.6,4
nmvalue: false
- section: ipv4
option: routes
nmvalue: 198.51.100.128/26 198.51.100.1 2, 198.51.100.64/26 198.51.100.6 4
lsr_cleanup:
- what: tasks/down_profile+delete_interface.yml
condition: "{{ __network_is_booted }}"
profile: "{{ interface }}"
lsr_persistent_state: absent
- what: tasks/remove_profile.yml
profile: "{{ interface }}"
- what: tasks/assert_profile_absent.yml
condition: "{{ __network_is_booted }}"
profile: "{{ interface }}"
- what: tasks/assert_device_absent.yml
profile: "{{ interface }}"
- tasks/check_network_dns.yml

View file

@ -10,106 +10,79 @@
debug:
msg: Inside ethernet tests
- name: Show network_provider
debug:
var: network_provider
- name: Include the task 'show_interfaces.yml'
include_tasks: tasks/show_interfaces.yml
- name: Include the task 'manage_test_interface.yml'
include_tasks: tasks/manage_test_interface.yml
vars:
state: present
- name: Include the task 'assert_device_present.yml'
include_tasks: tasks/assert_device_present.yml
- name: Test static interface up
include_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
interface_name: "{{ interface }}"
state: up
type: ethernet
autoconnect: true
ip:
address: 192.0.2.1/24
- name: Include the task 'assert_output_in_stderr_without_warnings.yml'
include_tasks: tasks/assert_output_in_stderr_without_warnings.yml
- name: Show network_provider after running role
debug:
var: network_provider
- name: Get NM connection file
slurp:
src: "/etc/NetworkManager/system-connections/{{ interface }}.nmconnection"
register: nm_connection_file
when:
- network_provider == 'nm'
# RHEL up to 8 uses initscripts backend
- ansible_distribution_major_version | int >= 9
- name: Assert settings in NM connection file
assert:
that:
- "('interface-name=' + interface) in nm_connection_file.content | b64decode"
- "'type=ethernet' in nm_connection_file.content | b64decode"
- "'address1=192.0.2.1/24' in nm_connection_file.content | b64decode"
- "'method=manual' in nm_connection_file.content | b64decode"
when:
- network_provider == 'nm'
# RHEL up to 8 uses initscripts backend
- ansible_distribution_major_version | int >= 9
- name: Get NM connection status
command: "nmcli connection show {{ interface }}"
changed_when: false
register: nm_connection_status
when: network_provider == 'nm'
- name: Assert NM connection status
assert:
that:
- nm_connection_status.stdout is search("ipv4.addresses:\s+192.0.2.1/24")
when: network_provider == 'nm'
- name: Get initscripts connection file
slurp:
src: "/etc/sysconfig/network-scripts/ifcfg-{{ interface }}"
register: initscripts_connection_file
when: network_provider == 'initscripts' or ansible_distribution_major_version | int < 9
- name: Assert settings in initscripts connection file
assert:
that:
- "'TYPE=Ethernet' in initscripts_connection_file.content | b64decode"
- "'DEVICE={{ interface }}' in initscripts_connection_file.content | b64decode"
- "'IPADDR=192.0.2.1' in initscripts_connection_file.content | b64decode"
- "'PREFIX=24' in initscripts_connection_file.content | b64decode"
when: network_provider == 'initscripts' or ansible_distribution_major_version | int < 9
- name: Include the tasks 'down_profile+delete_interface.yml'
include_tasks: tasks/down_profile+delete_interface.yml
vars:
profile: "{{ interface }}"
# FIXME: assert profile/device down
- name: Include the task 'remove_profile.yml'
include_tasks: tasks/remove_profile.yml
vars:
profile: "{{ interface }}"
- name: Include the task 'assert_profile_absent.yml'
include_tasks: tasks/assert_profile_absent.yml
vars:
profile: "{{ interface }}"
- name: Include the task 'assert_device_absent.yml'
include_tasks: tasks/assert_device_absent.yml
- name: Verify network state restored to default
include_tasks: tasks/check_network_dns.yml
- name: Test creating the bridge connection
tags:
- tests::states:create
block:
- name: Include the task 'run_test.yml'
include_tasks: tasks/run_test.yml
vars:
lsr_description: I can create a profile
lsr_setup:
- what: tasks/delete_interface.yml
condition: "{{ not __bootc_validation | default(false) }}"
- what: tasks/assert_device_absent.yml
condition: "{{ not __bootc_validation | default(false) }}"
- what: tasks/manage_test_interface.yml
state: present
- tasks/assert_device_present.yml
lsr_test:
- network_connections:
- name: "{{ interface }}"
interface_name: "{{ interface }}"
state: up
type: ethernet
autoconnect: true
ip:
address: 192.0.2.1/24
lsr_assert:
- tasks/assert_output_in_stderr_without_warnings.yml
- tasks/assert_device_present.yml
# Device should be present because of autoconnect: true by
# default for NM (this might be considered a bug)
- what: tasks/assert_connection_settings.yml
condition: "{{ network_provider == 'nm' }}"
lsr_connection_name: "{{ interface }}"
lsr_connection_settings:
- section: connection
option: interface-name
value: "{{ interface }}"
- section: connection
option: type
value: ethernet
nmvalue: 802-3-ethernet
- section: ipv4
option: address1
value: 192.0.2.1/24
nmvalue: false
- section: ipv4
option: addresses
nmvalue: 192.0.2.1/24
- section: ipv4
option: method
value: manual
- what: tasks/assert_connection_settings.yml
condition: "{{ network_provider == 'initscripts' or ansible_distribution_major_version | int < 9 }}"
lsr_connection_name: "{{ interface }}"
lsr_connection_settings:
- TYPE=Ethernet
- DEVICE={{ interface }}
- IPADDR=192.0.2.1
- PREFIX=24
- what: tasks/assert_nm_connection_status.yml
condition: "{{ network_provider == 'nm' and __network_is_booted }}"
lsr_connection_name: "{{ interface }}"
lsr_connection_output: 'ipv4.addresses:\s+192.0.2.1/24'
lsr_cleanup:
- what: tasks/down_profile+delete_interface.yml
condition: "{{ __network_is_booted }}"
profile: "{{ interface }}"
lsr_persistent_state: absent
- what: tasks/remove_profile.yml
profile: "{{ interface }}"
- what: tasks/assert_profile_absent.yml
condition: "{{ __network_is_booted }}"
profile: "{{ interface }}"
- what: tasks/assert_device_absent.yml
profile: "{{ interface }}"
- tasks/check_network_dns.yml

View file

@ -12,153 +12,117 @@
tags:
- always
- name: "INIT: Ethtool coalesce tests"
debug:
msg: "##################################################"
- name: Include the task 'show_interfaces.yml'
include_tasks: tasks/show_interfaces.yml
- name: Include the task 'manage_test_interface.yml'
include_tasks: tasks/manage_test_interface.yml
vars:
state: present
- name: Include the task 'assert_device_present.yml'
include_tasks: tasks/assert_device_present.yml
- name: Install ethtool (test dependency)
package:
name: ethtool
state: present
use: "{{ (__network_is_ostree | d(false)) |
ternary('ansible.posix.rhel_rpm_ostree', omit) }}"
- name: Include network role vars used by tests
include_role:
name: linux-system-roles.network
tasks_from: set_facts.yml
public: true
- name: Test ethtool coalesce settings
- name: Run tests
block:
- name: >-
TEST: I can create a profile without any coalescing option.
debug:
msg: "##################################################"
- name: Import network role
import_role:
name: linux-system-roles.network
- name: Test creating profile without changing ethtool coalesce settings
when:
- __network_is_booted
- not __bootc_validation | d(false)
include_tasks: tasks/run_test.yml
vars:
network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
dhcp4: false
auto6: false
lsr_description: Test creating profile without changing ethtool coalesce
lsr_setup:
- tasks/show_interfaces.yml
- what: tasks/manage_test_interface.yml
state: present
- tasks/assert_device_present.yml
lsr_test:
- network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
dhcp4: false
auto6: false
lsr_assert: # NOTE: Cleanup is done in always at very end of file
- what: tasks/assert_command_output.yml
condition: "{{ network_provider == 'nm' }}"
lsr_command: nmcli -g ethtool.coalesce-rx-frames c show {{ interface | quote }}
lsr_not_stdout: coalesce
- what: tasks/assert_command_output.yml
condition: "{{ network_provider == 'initscripts' }}"
lsr_command: cat /etc/sysconfig/network-scripts/ifcfg-{{ interface | quote }}
lsr_not_stdout: ETHTOOL
lsr_cleanup: []
- name: Get profile's coalescing options
command: nmcli -g ethtool.coalesce-rx-frames c show {{ interface }}
register: no_coalesce_nm
when:
- network_provider == "nm"
changed_when: false
- name: "ASSERT: The profile does not contain coalescing options"
assert:
that: no_coalesce_nm.stdout | length == 0
when:
- network_provider == "nm"
- name: Get profile's coalescing options
command:
grep ETHTOOL /etc/sysconfig/network-scripts/ifcfg-{{ interface }}
register: no_coalesce_initscripts
ignore_errors: true
when:
- network_provider == "initscripts"
changed_when: false
- name: "ASSERT: The profile does not contain coalescing options"
assert:
that: no_coalesce_initscripts.stdout | length == 0
when:
- network_provider == "initscripts"
- name: >-
TEST: I can set rx-frames.
debug:
msg: "##################################################"
- name: Import network role
import_role:
name: linux-system-roles.network
- name: "TEST: I can set rx-frames."
include_tasks: tasks/run_test.yml
vars:
network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
dhcp4: false
auto6: false
ethtool:
coalesce:
rx_frames: 128
- name: Get profile's coalescing options
command: nmcli -g ethtool.coalesce-rx-frames c show {{ interface }}
register: with_coalesce_nm
when:
- network_provider == "nm"
changed_when: false
- name: Assert coalesce options set in profile
assert:
that: with_coalesce_nm.stdout == '128'
when:
- network_provider == "nm"
lsr_description: Test setting coalesce option
lsr_setup:
- tasks/show_interfaces.yml
- what: tasks/manage_test_interface.yml
state: present
- tasks/assert_device_present.yml
lsr_test:
- network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
dhcp4: false
auto6: false
ethtool:
coalesce:
rx_frames: 128
lsr_assert:
- what: tasks/assert_connection_settings.yml
condition: "{{ network_provider == 'nm' }}"
lsr_connection_name: "{{ interface }}"
lsr_connection_settings:
- section: ethtool
option: coalesce-rx-frames
value: "128"
- what: tasks/assert_command_output.yml
condition: "{{ network_provider == 'nm' }}"
lsr_command: nmcli -g ethtool.coalesce-rx-frames c show {{ interface | quote }}
lsr_stdout: "128"
- what: tasks/assert_command_output.yml
condition: "{{ network_provider == 'initscripts' }}"
lsr_command: grep ETHTOOL /etc/sysconfig/network-scripts/ifcfg-{{ interface | quote }}
lsr_stdout: rx-frames 128
lsr_cleanup: []
- name: Get profile's coalescing options
command:
grep ETHTOOL /etc/sysconfig/network-scripts/ifcfg-{{ interface }}
register: with_coalesce_initscripts
ignore_errors: true
- name: Test clearing ethtool coalesce settings
when:
- network_provider == "initscripts"
changed_when: false
- name: Assert coalesce options set in profile
assert:
that: '"rx-frames 128" in with_coalesce_initscripts.stdout'
when:
- network_provider == "initscripts"
- name: "TEST: I can clear coalescing options"
debug:
msg: "##################################################"
- name: Import network role
import_role:
name: linux-system-roles.network
- __network_is_booted
- not __bootc_validation | d(false)
include_tasks: tasks/run_test.yml
vars:
network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
dhcp4: false
auto6: false
- name: Get profile's coalescing options
command: nmcli -g ethtool.coalesce-rx-frames c show {{ interface }}
when:
- network_provider == "nm"
register: clear_coalesce_nm
changed_when: false
- name: "ASSERT: The profile does reset coalescing options"
assert:
that: clear_coalesce_nm.stdout | length == 0
when:
- network_provider == "nm"
- name: Get profile's coalescing options
command:
grep ETHTOOL /etc/sysconfig/network-scripts/ifcfg-{{ interface }}
register: clear_coalesce_initscripts
ignore_errors: true
when:
- network_provider == "initscripts"
changed_when: false
- name: "ASSERT: The profile does reset coalescing options"
assert:
that: clear_coalesce_initscripts.stdout | length == 0
when:
- network_provider == "initscripts"
lsr_description: Test creating profile without changing ethtool features
lsr_setup:
- tasks/show_interfaces.yml
- what: tasks/manage_test_interface.yml
state: present
- tasks/assert_device_present.yml
lsr_test:
- network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
dhcp4: false
auto6: false
lsr_assert: # NOTE: Cleanup is done in always at very end of file
- what: tasks/assert_command_output.yml
condition: "{{ network_provider == 'nm' }}"
lsr_command: nmcli -g ethtool.coalesce-rx-frames c show {{ interface | quote }}
lsr_not_stdout: coalesce
- what: tasks/assert_command_output.yml
condition: "{{ network_provider == 'initscripts' }}"
lsr_command: cat /etc/sysconfig/network-scripts/ifcfg-{{ interface | quote }}
lsr_not_stdout: ETHTOOL
lsr_cleanup: []
always:
- name: Clean up the test device and the connection profile
when: ansible_connection != "buildah"
tags:
- "tests::cleanup"
block:

View file

@ -12,137 +12,66 @@
tags:
- always
- name: "INIT: Ethtool feeatures tests"
debug:
msg: "##################################################"
- name: Include the task 'show_interfaces.yml'
include_tasks: tasks/show_interfaces.yml
- name: Include the task 'manage_test_interface.yml'
include_tasks: tasks/manage_test_interface.yml
vars:
state: present
- name: Include the task 'assert_device_present.yml'
include_tasks: tasks/assert_device_present.yml
- name: Install ethtool (test dependency)
package:
name: ethtool
state: present
use: "{{ (__network_is_ostree | d(false)) |
ternary('ansible.posix.rhel_rpm_ostree', omit) }}"
- name: Include network role vars used by tests
include_role:
name: linux-system-roles.network
tasks_from: set_facts.yml
public: true
- name: Test ethtool features settings
- name: Run tests
block:
- name: >-
TEST: I can create a profile without changing the ethtool features.
debug:
msg: "##################################################"
- name: Get current device features
command: "ethtool --show-features {{ interface }}"
register: original_ethtool_features
changed_when: false
- name: Import network role
import_role:
name: linux-system-roles.network
- name: Test creating profile without changing ethtool features
when:
- __network_is_booted
- not __bootc_validation | d(false)
include_tasks: tasks/run_test.yml
vars:
network_connections:
- name: "{{ interface }}"
state: up
type: ethernet
ip:
dhcp4: "no"
auto6: "no"
- name: Get current device features
command: "ethtool --show-features {{ interface }}"
register: ethtool_features
changed_when: false
- name: "ASSERT: The profile does not change the ethtool features"
assert:
that:
- original_ethtool_features.stdout == ethtool_features.stdout
lsr_description: Test creating profile without changing ethtool features
lsr_setup:
- tasks/show_interfaces.yml
- what: tasks/manage_test_interface.yml
state: present
- tasks/assert_device_present.yml
- what: tasks/assert_command_output.yml
lsr_packages: [ethtool]
lsr_command: ethtool --show-features {{ interface | quote }}
lsr_test:
- network_connections:
- name: "{{ interface }}"
state: up
type: ethernet
ip:
dhcp4: "no"
auto6: "no"
lsr_assert: # NOTE: Cleanup is done in always at very end of file
- what: tasks/assert_command_output.yml
lsr_packages: [ethtool]
lsr_command: ethtool --show-features {{ interface | quote }}
lsr_stdout: "{{ __previous_command_output.stdout }}"
lsr_cleanup: []
- name: >-
TEST: I can disable gro and tx-tcp-segmentation and enable gso.
debug:
msg: "##################################################"
- name: Import network role
import_role:
name: linux-system-roles.network
- name: Set original ethtool features
when:
- __network_is_booted
- not __bootc_validation | d(false)
set_fact:
original_ethtool_features: "{{ __previous_command_output }}"
- name: "TEST: I can disable gro and tx-tcp-segmentation and enable gso."
include_tasks: tasks/run_test.yml
vars:
network_connections:
- name: "{{ interface }}"
state: up
type: ethernet
ip:
dhcp4: "no"
auto6: "no"
ethtool:
features:
gro: "no"
gso: "yes"
tx-tcp-segmentation: "no"
- name: Get current device features
command: "ethtool --show-features {{ interface }}"
register: ethtool_features
changed_when: false
- name: Show ethtool_features
debug:
var: ethtool_features.stdout_lines
- name: Assert device features
assert:
that:
- >-
'generic-receive-offload: off' in
ethtool_features.stdout_lines
- >-
'generic-segmentation-offload: on' in
ethtool_features.stdout_lines
- >-
'tx-tcp-segmentation: off' in
ethtool_features.stdout_lines | map('trim')
- name: >-
TEST: I can enable tx_tcp_segmentation (using underscores).
debug:
msg: "##################################################"
- name: Import network role
import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
state: up
type: ethernet
ip:
dhcp4: "no"
auto6: "no"
ethtool:
features:
tx_tcp_segmentation: "yes"
- name: Get current device features
command: "ethtool --show-features {{ interface }}"
register: ethtool_features
changed_when: false
- name: Show ethtool_features
debug:
var: ethtool_features.stdout_lines
- name: Assert device features
assert:
that:
- >-
'tx-tcp-segmentation: on' in
ethtool_features.stdout_lines | map('trim')
- name: I cannot change tx_tcp_segmentation and tx-tcp-segmentation at
the same time.
block:
- name: >-
TEST: Change feature with both underscores and dashes.
debug:
msg: "##################################################"
- name: Configure ethtool features setting
network_connections:
provider: "{{ network_provider | mandatory }}"
connections:
lsr_description: Test creating profile without changing ethtool features
lsr_setup:
- tasks/show_interfaces.yml
- what: tasks/manage_test_interface.yml
state: present
- tasks/assert_device_present.yml
- what: tasks/assert_command_output.yml
condition: "{{ __network_is_booted }}"
lsr_packages: [ethtool]
lsr_command: ethtool --show-features {{ interface | quote }}
lsr_test:
- network_connections:
- name: "{{ interface }}"
state: up
type: ethernet
@ -151,10 +80,90 @@
auto6: "no"
ethtool:
features:
tx_tcp_segmentation: "no"
gro: "no"
gso: "yes"
tx-tcp-segmentation: "no"
__header: "# Ansible managed test header"
register: __network_connections_result
lsr_assert:
- what: tasks/assert_connection_settings.yml
condition: "{{ network_provider == 'nm' }}"
lsr_connection_name: "{{ interface }}"
lsr_connection_settings:
- section: ethtool
option: feature-gro
value: "false"
nmvalue: "off"
- section: ethtool
option: feature-gso
value: "true"
nmvalue: "on"
- section: ethtool
option: feature-tx-tcp-segmentation
value: "false"
nmvalue: "off"
- what: tasks/assert_command_output.yml
condition: "{{ __network_is_booted }}"
lsr_packages: [ethtool]
lsr_command: ethtool --show-features {{ interface | quote }}
lsr_stdout_lines:
- "generic-receive-offload: off"
- "generic-segmentation-offload: on"
- "\ttx-tcp-segmentation: off" # noqa no-tabs
lsr_cleanup: []
- name: >-
TEST: I can enable tx_tcp_segmentation (using underscores).
when:
- __network_is_booted
- not __bootc_validation | d(false)
include_tasks: tasks/run_test.yml
vars:
lsr_description: Test enabling tx_tcp_segmentation (using underscores)
lsr_setup: []
lsr_test:
- network_connections:
- name: "{{ interface }}"
state: up
type: ethernet
ip:
dhcp4: "no"
auto6: "no"
ethtool:
features:
tx_tcp_segmentation: "yes"
lsr_assert:
- what: tasks/assert_command_output.yml
lsr_packages: [ethtool]
lsr_command: ethtool --show-features {{ interface | quote }}
lsr_stdout_lines:
- "\ttx-tcp-segmentation: on" # noqa no-tabs
lsr_cleanup: []
- name: I cannot change tx_tcp_segmentation and tx-tcp-segmentation at
the same time.
when:
- __network_is_booted
- not __bootc_validation | d(false)
block:
- name: >-
TEST: Change feature with both underscores and dashes.
include_tasks: tasks/run_test.yml
vars:
lsr_description: Test changing feature with both underscores and dashes
lsr_setup: []
lsr_test:
- network_connections:
- name: "{{ interface }}"
state: up
type: ethernet
ip:
dhcp4: "no"
auto6: "no"
ethtool:
features:
tx_tcp_segmentation: "no"
tx-tcp-segmentation: "no"
lsr_assert: []
lsr_cleanup: []
rescue:
- name: Show network_connections result
debug:
@ -168,7 +177,6 @@
fatal error: configuration error:
connections[0].ethtool.features: duplicate key
'tx_tcp_segmentation'
always:
- name: Check failure
debug:
@ -178,32 +186,30 @@
that: __network_connections_result.failed
- name: "TEST: I can reset features to their original value."
debug:
msg: "##################################################"
- name: Import network role
import_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
state: up
type: ethernet
ip:
dhcp4: "no"
auto6: "no"
- name: Get current device features
command: "ethtool --show-features {{ interface }}"
register: ethtool_features
changed_when: false
# Resetting the ethtools only works with NetworkManager
- name: "ASSERT: The profile does not change the ethtool features"
assert:
that:
- original_ethtool_features.stdout == ethtool_features.stdout
when:
network_provider == 'nm'
- __network_is_booted
- not __bootc_validation | d(false)
include_tasks: tasks/run_test.yml
vars:
lsr_description: Test resetting features to their original value
lsr_setup: []
lsr_test:
- network_connections:
- name: "{{ interface }}"
state: up
type: ethernet
ip:
dhcp4: "no"
auto6: "no"
lsr_assert:
- what: tasks/assert_command_output.yml
lsr_packages: [ethtool]
lsr_command: ethtool --show-features {{ interface | quote }}
lsr_stdout: "{{ original_ethtool_features.stdout }}"
lsr_cleanup: []
always:
- name: Clean up the test device and the connection profile
when: ansible_connection != "buildah"
tags:
- "tests::cleanup"
block:

View file

@ -12,194 +12,129 @@
tags:
- always
- name: "INIT: Ethtool ring tests"
debug:
msg: "##################################################"
- name: Include the task 'show_interfaces.yml'
include_tasks: tasks/show_interfaces.yml
- name: Include the task 'manage_test_interface.yml'
include_tasks: tasks/manage_test_interface.yml
vars:
state: present
- name: Include the task 'assert_device_present.yml'
include_tasks: tasks/assert_device_present.yml
- name: Install ethtool (test dependency)
package:
name: ethtool
state: present
use: "{{ (__network_is_ostree | d(false)) |
ternary('ansible.posix.rhel_rpm_ostree', omit) }}"
- name: Include network role vars used by tests
include_role:
name: linux-system-roles.network
tasks_from: set_facts.yml
public: true
- name: Test ethtool ring settings
- name: Run tests
block:
- name: >-
TEST: I can create a profile without any ring option.
debug:
msg: "##################################################"
- name: Import network role
import_role:
name: linux-system-roles.network
- name: Test creating profile without changing ethtool ring settings
when:
- __network_is_booted
- not __bootc_validation | d(false)
include_tasks: tasks/run_test.yml
vars:
network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
dhcp4: false
auto6: false
lsr_description: Test creating profile without changing ethtool ring settings
lsr_setup:
- tasks/show_interfaces.yml
- what: tasks/manage_test_interface.yml
state: present
- tasks/assert_device_present.yml
lsr_test:
- network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
dhcp4: false
auto6: false
lsr_assert: # NOTE: Cleanup is done in always at very end of file
- what: tasks/assert_command_output.yml
condition: "{{ network_provider == 'nm' }}"
lsr_command: nmcli -g ethtool.ring-rx c show {{ interface | quote }}
lsr_not_stdout: ring-rx
- what: tasks/assert_command_output.yml
condition: "{{ network_provider == 'initscripts' }}"
lsr_command: cat /etc/sysconfig/network-scripts/ifcfg-{{ interface | quote }}
lsr_not_stdout: ETHTOOL
lsr_cleanup: []
- name: Get profile's ring options
command: nmcli -g ethtool.ring-rx c show {{ interface }}
register: no_ring_nm
when:
- network_provider == "nm"
changed_when: false
- name: "ASSERT: The profile does not contain ring options"
assert:
that: no_ring_nm.stdout | length == 0
when:
- network_provider == "nm"
- name: Get profile's ring options
command:
grep ETHTOOL /etc/sysconfig/network-scripts/ifcfg-{{ interface }}
register: no_ring_initscripts
ignore_errors: true
when:
- network_provider == "initscripts"
changed_when: false
- name: "ASSERT: The profile does not contain ring options"
assert:
that: no_ring_initscripts.stdout | length == 0
when:
- network_provider == "initscripts"
- name: >-
TEST: I can set rx.
debug:
msg: "##################################################"
- name: Import network role
import_role:
name: linux-system-roles.network
- name: "TEST: I can set rx ring settings."
include_tasks: tasks/run_test.yml
vars:
network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
dhcp4: false
auto6: false
ethtool:
ring:
rx: 128
rx_jumbo: 128
rx_mini: 128
tx: 128
lsr_description: Test setting rx ring settings
lsr_setup:
- tasks/show_interfaces.yml
- what: tasks/manage_test_interface.yml
state: present
- tasks/assert_device_present.yml
lsr_test:
- network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
dhcp4: false
auto6: false
ethtool:
ring:
rx: 128
rx_jumbo: 128
rx_mini: 128
tx: 128
lsr_assert:
- what: tasks/assert_connection_settings.yml
condition: "{{ network_provider == 'nm' }}"
lsr_connection_name: "{{ interface }}"
lsr_connection_settings:
- section: ethtool
option: ring-rx
value: "128"
- section: ethtool
option: ring-rx-jumbo
value: "128"
- section: ethtool
option: ring-rx-mini
value: "128"
- section: ethtool
option: ring-tx
value: "128"
- what: tasks/assert_command_output.yml
condition: "{{ network_provider == 'initscripts' }}"
lsr_command: grep ETHTOOL /etc/sysconfig/network-scripts/ifcfg-{{ interface | quote }}
lsr_stdout_lines:
- rx 128
- rx-jumbo 128
- rx-mini 128
- tx 128
lsr_cleanup: []
- name: Get profile's ethtool.ring-rx options
command: nmcli -g ethtool.ring-rx c show {{ interface }}
register: with_ring_rx
- name: Test clearing ethtool ring settings
when:
- network_provider == "nm"
changed_when: false
- name: Assert ethtool.ring-rx option set in profile
assert:
that: with_ring_rx.stdout == '128'
when:
- network_provider == "nm"
- name: Get profile's ethtool.ring-rx-jumbo options
command: nmcli -g ethtool.ring-rx-jumbo c show {{ interface }}
register: with_ring_rx_jumbo
when:
- network_provider == "nm"
changed_when: false
- name: Assert ethtool.ring-rx-jumbo option set in profile
assert:
that: with_ring_rx_jumbo.stdout == '128'
when:
- network_provider == "nm"
- name: Get profile's ethtool.ring-rx-mini options
command: nmcli -g ethtool.ring-rx-mini c show {{ interface }}
register: with_ring_rx_mini
when:
- network_provider == "nm"
changed_when: false
- name: Assert ethtool.ring-rx-mini option set in profile
assert:
that: with_ring_rx_mini.stdout == '128'
when:
- network_provider == "nm"
- name: Get profile's ethtool.ring-tx options
command: nmcli -g ethtool.ring-tx c show {{ interface }}
register: with_ring_tx
when:
- network_provider == "nm"
changed_when: false
- name: Assert ethtool.ring-tx option set in profile
assert:
that: with_ring_tx.stdout == '128'
when:
- network_provider == "nm"
- name: Get profile's ethtool.ring options
command:
grep ETHTOOL /etc/sysconfig/network-scripts/ifcfg-{{ interface }}
register: with_ring
ignore_errors: true
when:
- network_provider == "initscripts"
changed_when: false
- name: Assert ethtool.ring option set in profile
assert:
that:
- '"rx 128" in with_ring.stdout'
- '"rx-jumbo 128" in with_ring.stdout'
- '"rx-mini 128" in with_ring.stdout'
- '"tx 128" in with_ring.stdout'
when:
- network_provider == "initscripts"
- name: "TEST: I can clear ring options"
debug:
msg: "##################################################"
- name: Import network role
import_role:
name: linux-system-roles.network
- __network_is_booted
- not __bootc_validation | d(false)
include_tasks: tasks/run_test.yml
vars:
network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
dhcp4: false
auto6: false
- name: Get profile's ring options
command: nmcli -g ethtool.ring-rx c show {{ interface }}
register: clear_ring_nm
when:
- network_provider == "nm"
changed_when: false
- name: "ASSERT: The profile does reset ring options"
assert:
that: clear_ring_nm.stdout | length == 0
when:
- network_provider == "nm"
- name: Get profile's ring options
command:
grep ETHTOOL /etc/sysconfig/network-scripts/ifcfg-{{ interface }}
register: clear_ring_initscripts
ignore_errors: true
when:
- network_provider == "initscripts"
changed_when: false
- name: "ASSERT: The profile does reset ring options"
assert:
that: clear_ring_initscripts.stdout | length == 0
when:
- network_provider == "initscripts"
lsr_description: Test clearing ethtool ring settings
lsr_setup:
- tasks/show_interfaces.yml
- what: tasks/manage_test_interface.yml
state: present
- tasks/assert_device_present.yml
lsr_test:
- network_connections:
- name: "{{ interface }}"
type: ethernet
state: up
ip:
dhcp4: false
auto6: false
lsr_assert: # NOTE: Cleanup is done in always at very end of file
- what: tasks/assert_command_output.yml
condition: "{{ network_provider == 'nm' }}"
lsr_command: nmcli -g ethtool.ring-rx c show {{ interface | quote }}
lsr_not_stdout: ring-rx
- what: tasks/assert_command_output.yml
condition: "{{ network_provider == 'initscripts' }}"
lsr_command: cat /etc/sysconfig/network-scripts/ifcfg-{{ interface | quote }}
lsr_not_stdout: ETHTOOL
lsr_cleanup: []
always:
- name: Clean up the test device and the connection profile
when: ansible_connection != "buildah"
tags:
- "tests::cleanup"
block:

View file

@ -36,27 +36,52 @@
auto6: true
address:
- 198.51.100.3/24
- name: Get the nmcli ipv4.ignore-auto-dns setting
command: nmcli -f ipv4.ignore-auto-dns c show {{ interface }}
register: ipv4_ignore_auto_dns
changed_when: false
- name: Get the nmcli ipv6.ignore-auto-dns setting
command: nmcli -f ipv6.ignore-auto-dns c show {{ interface }}
register: ipv6_ignore_auto_dns
changed_when: false
# the nmcli and .nmconnection file formats are very different, so we
# need to do online and offline checks in different code paths
- name: Online check
when: __network_is_booted | bool
block:
- name: Get the nmcli ipv4.ignore-auto-dns setting
command: nmcli -f ipv4.ignore-auto-dns c show {{ interface }}
register: ipv4_ignore_auto_dns
changed_when: false
- name: Assert that the setting ipv4.ignore-auto-dns is 'no'
assert:
that:
- "'no' in ipv4_ignore_auto_dns.stdout"
msg: "the setting ipv4.ignore-auto-dns is 'yes'"
- name: Get the nmcli ipv6.ignore-auto-dns setting
command: nmcli -f ipv6.ignore-auto-dns c show {{ interface }}
register: ipv6_ignore_auto_dns
changed_when: false
- name: Assert that the setting ipv6.ignore-auto-dns is 'yes'
assert:
that:
- "'yes' in ipv6_ignore_auto_dns.stdout"
msg: "the setting ipv6.ignore-auto-dns is 'no'"
- name: Assert that the setting ipv4.ignore-auto-dns is 'no'
assert:
that:
- "'no' in ipv4_ignore_auto_dns.stdout"
msg: "the setting ipv4.ignore-auto-dns is 'yes'"
- name: Assert that the setting ipv6.ignore-auto-dns is 'yes'
assert:
that:
- "'yes' in ipv6_ignore_auto_dns.stdout"
msg: "the setting ipv6.ignore-auto-dns is 'no'"
- name: Offline check
when: not __network_is_booted | bool
block:
# noqa command-instead-of-module
- name: Check that .nmconnection file has no ipv4.ignore-auto-dns setting
command: >
sed -n '/^\[ipv4\]/,/^$/ {/ignore-auto-dns=/p}' /etc/NetworkManager/system-connections/{{ interface }}.nmconnection
changed_when: false
register: ipv4_ignore_auto_dns_file
failed_when: ipv4_ignore_auto_dns_file.stdout | trim != ""
# noqa command-instead-of-module
- name: Check that .nmconnection file has ipv6.ignore-auto-dns setting
command: >
sed -n '/^\[ipv6\]/,/^$/ {/ignore-auto-dns=/p}' /etc/NetworkManager/system-connections/{{ interface }}.nmconnection
changed_when: false
register: ipv6_ignore_auto_dns_file
failed_when: ipv6_ignore_auto_dns_file.stdout | trim != "ignore-auto-dns=true"
always:
- name: Remove test configuration

View file

@ -44,10 +44,13 @@
vars:
errmsg: ip.ipv6_disabled is not supported by the running version of NetworkManager
- name: Verify nmcli connection ipv6.method
shell: |
set -euxo pipefail
nmcli connection show {{ interface }} | grep ipv6.method
- name: Verify NM connection ipv6.method
command: >-
{{
("nmcli -f ipv6.method connection show " ~ interface)
if __network_is_booted else
("sed -n '/^\[ipv6\]/,/^$/ {/method=/p}' /etc/NetworkManager/system-connections/" ~ interface ~ ".nmconnection")
}}
register: ipv6_method
ignore_errors: true
changed_when: false

View file

@ -21,13 +21,23 @@
- 192.0.2.1/24
state: up
- name: Get DNS search entry for IPv4
command: nmcli -f ipv4.dns-search connection show br-example
command: >-
{{
"nmcli -f ipv4.dns-search connection show br-example"
if __network_is_booted else
"sed -n '/^\[ipv4\]/,/^$/ {/dns-search=/p}' /etc/NetworkManager/system-connections/br-example.nmconnection"
}}
register: ipv4_dns_search
ignore_errors: true
changed_when: false
- name: Get DNS search entry for IPv6
command: nmcli -f ipv6.dns-search connection show br-example
command: >-
{{
"nmcli -f ipv6.dns-search connection show br-example"
if __network_is_booted else
"sed -n '/^\[ipv6\]/,/^$/ {/dns-search=/p}' /etc/NetworkManager/system-connections/br-example.nmconnection"
}}
register: ipv6_dns_search
ignore_errors: true
changed_when: false
@ -67,7 +77,12 @@
state: up
- name: Get DNS search entry for IPv6
command: nmcli -f ipv6.dns-search connection show br-example
command: >-
{{
"nmcli -f ipv6.dns-search connection show br-example"
if __network_is_booted else
"sed -n '/^\[ipv6\]/,/^$/ {/dns-search=/p}' /etc/NetworkManager/system-connections/br-example.nmconnection"
}}
register: ipv6_dns_search_static
ignore_errors: true
changed_when: false
@ -99,7 +114,12 @@
state: up
- name: Get DNS search entry for IPv6
command: nmcli -f ipv6.dns-search connection show br-example
command: >-
{{
"nmcli -f ipv6.dns-search connection show br-example"
if __network_is_booted else
"sed -n '/^\[ipv6\]/,/^$/ {/dns-search=/p}' /etc/NetworkManager/system-connections/br-example.nmconnection"
}}
register: ipv6_dns_search_static_only
ignore_errors: true
changed_when: false

View file

@ -2,6 +2,9 @@
---
- name: Play for configuring network using network state variable
hosts: all
tags:
# this is runtime configuration and checks
- tests::booted
vars:
type: veth
interface0: ethtest0

View file

@ -8,111 +8,121 @@
interface1: ethtest1
tasks:
- name: Set type and interface0
set_fact:
type: "{{ type }}"
interface: "{{ interface0 }}"
- name: Show interfaces
include_tasks: tasks/show_interfaces.yml
- name: Manage test interface
include_tasks: tasks/manage_test_interface.yml
vars:
state: present
- name: Assert device is present
include_tasks: tasks/assert_device_present.yml
- name: Set interface1
set_fact:
interface: "{{ interface1 }}"
- name: Show interfaces again
include_tasks: tasks/show_interfaces.yml
- name: Manage test interface with second interface
include_tasks: tasks/manage_test_interface.yml
vars:
state: present
- name: Assert device is present with second interface
include_tasks: tasks/assert_device_present.yml
- name: Test the route or the warning log when configuring the route with
or without the interface name
block:
- name: Configure the IP addresses and the route with interface name
specified
import_role:
name: linux-system-roles.network
- name: Test the route or the warning log when configuring the route with
or without the interface name
include_tasks: tasks/run_test.yml
vars:
network_connections:
- name: "{{ interface0 }}"
interface_name: "{{ interface0 }}"
state: up
type: ethernet
autoconnect: false
ip:
address:
- 198.51.100.3/24
- 2001:db8::2/32
route:
- network: 198.51.10.64
prefix: 26
gateway: 198.51.100.6
metric: 4
- network: 2001:db6::4
prefix: 128
gateway: 2001:db8::1
metric: 2
- name: "{{ interface1 }}"
interface_name: "{{ interface1 }}"
state: up
type: ethernet
autoconnect: false
ip:
address:
- 198.51.100.6/24
- 2001:db8::4/32
route:
- network: 198.51.12.128
prefix: 26
gateway: 198.51.100.1
metric: 2
- name: Get the IPv4 routes from the route table main
command: ip -4 route
register: route_table_main_ipv4
changed_when: false
lsr_description: Test the route or the warning log when configuring the route with
or without the interface name
lsr_setup:
- tasks/show_interfaces.yml
- what: tasks/manage_test_interface.yml
state: present
lsr_interface: "{{ interface0 }}"
- what: tasks/assert_device_present.yml
lsr_interface: "{{ interface0 }}"
- what: tasks/manage_test_interface.yml
state: present
lsr_interface: "{{ interface1 }}"
- what: tasks/assert_device_present.yml
lsr_interface: "{{ interface1 }}"
lsr_test:
- network_connections:
- name: "{{ interface0 }}"
interface_name: "{{ interface0 }}"
state: up
type: ethernet
# Set autoconnect to true for buildah connection, otherwise,
# the test will need to start the connection manually
autoconnect: "{{ ansible_connection | d('') == 'buildah'}}"
ip:
address:
- 198.51.100.3/24
- 2001:db8::2/32
route:
- network: 198.51.10.64
prefix: 26
gateway: 198.51.100.6
metric: 4
- network: 2001:db6::4
prefix: 128
gateway: 2001:db8::1
metric: 2
- name: "{{ interface1 }}"
interface_name: "{{ interface1 }}"
state: up
type: ethernet
# Set autoconnect to true for buildah connection, otherwise,
# the test will need to start the connection manually
autoconnect: "{{ ansible_connection | d('') == 'buildah'}}"
ip:
address:
- 198.51.100.6/24
- 2001:db8::4/32
route:
- network: 198.51.12.128
prefix: 26
gateway: 198.51.100.1
metric: 2
lsr_assert:
- what: tasks/assert_connection_settings.yml
condition: "{{ network_provider == 'nm' }}"
lsr_connection_name: "{{ interface0 }}"
lsr_connection_settings:
- section: ipv4
option: route1
value: 198.51.10.64/26,198.51.100.6,4
nmvalue: false
ifcfg_route_value: ADDRESS0=198.51.10.64
- section: ipv4
option: routes
nmvalue: 198.51.10.64/26 198.51.100.6 4
- section: ipv6
option: route1
value: 2001:db6::4/128,2001:db8::1,2
nmvalue: false
ifcfg_route6_value: 2001:db6::4/128 via 2001:db8::1 metric 2
- section: ipv6
option: routes
nmvalue: 2001:db6::4/128 2001:db8::1 2
- what: tasks/assert_connection_settings.yml
condition: "{{ network_provider == 'nm' }}"
lsr_connection_name: "{{ interface1 }}"
lsr_connection_settings:
- section: ipv4
option: route1
value: 198.51.12.128/26,198.51.100.1,2
nmvalue: false
- section: ipv4
option: routes
nmvalue: 198.51.12.128/26 198.51.100.1 2
- what: tasks/assert_command_output.yml
condition: "{{ __network_is_booted }}"
lsr_command: ip -4 route
lsr_stdout_regex_list:
- "198.51.10.64/26 via 198.51.100.6 dev ethtest0\\s+(proto static )?metric 4"
- "198.51.12.128/26 via 198.51.100.1 dev ethtest1\\s+(proto static )?metric 2"
- what: tasks/assert_command_output.yml
condition: "{{ __network_is_booted }}"
lsr_command: ip -6 route
lsr_stdout_regex_list:
- "2001:db6::4 via 2001:db8::1 dev ethtest0\\s+(proto static )?metric 2"
lsr_cleanup: []
- name: Assert that the route table main contains the specified IPv4
routes
assert:
that:
# When running with nm provider, the route will be configured
# with `proto static`
# In RHEL-6.10 managed host, the attribute in the route is not
# equally spaced
- route_table_main_ipv4.stdout is search("198.51.10.64/26 via
198.51.100.6 dev ethtest0\s+(proto static )?metric 4")
- route_table_main_ipv4.stdout is search("198.51.12.128/26 via
198.51.100.1 dev ethtest1\s+(proto static )?metric 2")
msg: "the route table main does not contain the specified IPv4
route"
- name: Get the IPv6 routes from the route table main
command: ip -6 route
register: route_table_main_ipv6
changed_when: false
- name: Assert that the route table main contains the specified IPv6
routes
assert:
that:
- route_table_main_ipv6.stdout is search("2001:db6::4 via
2001:db8::1 dev ethtest0\s+(proto static )?metric 2")
msg: "the route table main does not contain the specified IPv6
route"
- name: Get the interface1 MAC address
command: cat /sys/class/net/{{ interface1 }}/address
register: interface1_mac
changed_when: false
when: __network_is_booted and not __bootc_validation | d(false)
- name: Configure the IP addresses and the route with only the MAC
address specified
import_role:
include_role:
name: linux-system-roles.network
when: __network_is_booted and not __bootc_validation | d(false)
vars:
network_connections:
- name: "{{ interface1 }}"
@ -133,28 +143,37 @@
the output device is logged for initscripts provider
assert:
that:
- __network_connections_result.stderr is search("\[003\]
<warn> .0, state.None persistent_state.present,
'{{ interface1 }}'. The connection {{ interface1 }} does not
specify an interface name. Therefore, the route to
198.58.10.64/26 will be configured without the output device
and the kernel will choose it automatically which might result
in an unwanted device being used. To avoid this, specify
`interface_name` in the connection appropriately.")
- __network_connections_result.stderr is search(__stderr_str)
msg: The warning about specifying the route without the output
device is not logged for initscripts provider
when: network_provider == "initscripts"
when:
- network_provider == "initscripts"
- __network_is_booted
- not __bootc_validation | d(false)
vars:
__stderr_str: >-
\[003\] <warn> .0, state.None persistent_state.present, '{{ interface1 }}'.
The connection {{ interface1 }} does not
specify an interface name. Therefore, the route to
198.58.10.64/26 will be configured without the output device
and the kernel will choose it automatically which might result
in an unwanted device being used. To avoid this, specify
`interface_name` in the connection appropriately.
- name: Assert that no warning is logged for nm provider
assert:
that:
- __network_connections_result.stderr is not search("<warn>")
msg: The warning is logged for nm provider
when: network_provider == "nm"
when:
- network_provider == "nm"
- __network_is_booted
- not __bootc_validation | d(false)
always:
- name: Remove test configuration
tags:
- "tests::cleanup"
when: ansible_connection != "buildah"
block:
- name: Bring down test devices and profiles
include_role:
@ -169,15 +188,20 @@
state: down
- name: Delete interface1
include_tasks: tasks/delete_interface.yml
vars:
lsr_interface: "{{ interface1 }}"
- name: Assert interface1 is absent
include_tasks: tasks/assert_device_absent.yml
- name: Set interface0
set_fact:
interface: "{{ interface0 }}"
vars:
lsr_interface: "{{ interface1 }}"
- name: Delete interface0
include_tasks: tasks/delete_interface.yml
vars:
lsr_interface: "{{ interface0 }}"
- name: Assert interface0 is absent
include_tasks: tasks/assert_device_absent.yml
vars:
lsr_interface: "{{ interface0 }}"
- name: Assert interface0 profile and interface1 profile are absent
include_tasks: tasks/assert_profile_absent.yml
vars:

View file

@ -5,6 +5,6 @@
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
- name: "{{ lsr_interface | d(interface) }}"
state: up
...

View file

@ -1,7 +1,7 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- name: "** TEST check IPv4"
command: ip -4 a s {{ interface | quote }}
command: ip -4 a s {{ lsr_interface | d(interface) | quote }}
register: result
until: address in result.stdout
retries: 20

View file

@ -9,13 +9,18 @@
loop_control:
loop_var: bond_opt
changed_when: false
when: __network_is_booted | bool
- name: Include the task 'assert_IPv4_present.yml'
include_tasks: assert_IPv4_present.yml
vars:
interface: "{{ controller_device }}"
lsr_interface: "{{ controller_device }}"
address: '192.0.2'
when: __network_is_booted | bool
- name: Include the task 'assert_IPv6_present.yml'
include_tasks: assert_IPv6_present.yml
vars:
interface: "{{ controller_device }}"
lsr_interface: "{{ controller_device }}"
address: '2001'
when: __network_is_booted | bool

View file

@ -0,0 +1,78 @@
# SPDX-License-Identifier: BSD-3-Clause
# Inputs:
# lsr_command: The command to run with the "command" module
# command can be either a string or a list
# lsr_shell: The command to run with the "shell" module
# lsr_packages: Any packages that need to be installed first
# to provide the command, if any
# lsr_stdout: The string to look for in the stdout of the command
# lsr_stderr: The string to look for in the stderr of the command
# lsr_not_stdout: This string must not be present in the stdout of the command
# lsr_not_stderr: This string must not be present in the stderr of the command
# Output:
# Will raise an error if command fails
# Will raise an error if stdout/stderr do not match given strings
---
- name: Ensure test packages are present
package:
name: "{{ lsr_packages }}"
state: present
use: "{{ (__network_is_ostree | d(false)) |
ternary('ansible.posix.rhel_rpm_ostree', omit) }}"
when: lsr_packages | d([]) | length > 0
- name: Run command and collect output
command:
cmd: "{{ lsr_command if lsr_command is string else omit }}"
argv: "{{ lsr_command if lsr_command is not string else omit }}"
when: lsr_command | d("") | length > 0
changed_when: false
register: __cmd_output
# noqa command-instead-of-shell
- name: Run command and collect output with shell
shell: "{{ lsr_shell }}"
when: lsr_shell | d("") | length > 0
changed_when: false
register: __shell_output
- name: Set command output
set_fact:
__command_output: "{{ __cmd_output if lsr_command | d('') | length > 0 else __shell_output }}"
- name: Set previous command output for before/after comparisons
set_fact:
__previous_command_output: "{{ __command_output }}"
- name: Assert lsr_stdout is in stdout
assert:
that: lsr_stdout in __command_output.stdout
when: lsr_stdout | d("") | length > 0
- name: Assert lsr_stdout_lines is in stdout
assert:
that: lsr_stdout_lines is subset(__command_output.stdout_lines)
when: lsr_stdout_lines | d([]) | length > 0
# assert that each regex in the list is in the stdout
- name: Assert lsr_stdout_regex_list is in stdout
assert:
that: __command_output.stdout is search(lsr_stdout_regex_list_item)
loop: "{{ lsr_stdout_regex_list | d([]) }}"
loop_control:
loop_var: lsr_stdout_regex_list_item
- name: Assert lsr_not_stdout is not in stdout
assert:
that: lsr_not_stdout not in __command_output.stdout
when: lsr_not_stdout | d("") | length > 0
- name: Assert lsr_stderr is in stderr
assert:
that: lsr_stderr in __command_output.stderr
when: lsr_stderr | d("") | length > 0
- name: Assert lsr_not_stderr is not in stderr
assert:
that: lsr_not_stderr not in __command_output.stderr
when: lsr_not_stderr | d("") | length > 0

View file

@ -0,0 +1,127 @@
# SPDX-License-Identifier: BSD-3-Clause
# Inputs
# - lsr_connection_name: the connection name
# - network_provider: the network provider
# - lsr_connection_settings: the connection file settings for NM files
---
- name: Assert NM connection settings
when:
- lsr_connection_name is defined
- lsr_connection_settings | d({}) | length > 0
- network_provider == "nm"
- ansible_distribution_major_version | int >= 9
vars:
__nm_connection_file_path: /etc/NetworkManager/system-connections/{{ lsr_connection_name }}.nmconnection
block:
- name: Show connection file
command: cat {{ __nm_connection_file_path | quote }}
changed_when: false
when: ansible_verbosity | int >= 2
- name: Stat connection file
stat:
path: "{{ __nm_connection_file_path }}"
register: __nm_connection_file_stat
- name: Assert settings in NM connection file
community.general.ini_file:
path: "{{ __nm_connection_file_path }}"
section: "{{ __nm_connection_file_item.section }}"
option: "{{ __nm_connection_file_item.option }}"
value: "{{ __nm_connection_file_item.value }}"
state: present
ignore_spaces: true
owner: "{{ __nm_connection_file_stat.stat.pw_name }}"
group: "{{ __nm_connection_file_stat.stat.gr_name }}"
mode: "{{ __nm_connection_file_stat.stat.mode }}"
register: __nm_connection_file
# nm only values do not define value
loop: "{{ lsr_connection_settings | selectattr('value', 'defined') | list }}"
loop_control:
loop_var: __nm_connection_file_item
failed_when: __nm_connection_file is changed
- name: Get nmcli connection settings
command: nmcli --fields all --terse connection show {{ lsr_connection_name | quote }}
register: __nm_connection_settings
changed_when: false
when: __network_is_booted
- name: Assert nmcli connection settings
assert:
that: setting in __nm_connection_settings.stdout_lines
loop: "{{ nmitems + items }}"
loop_control:
loop_var: __nm_connection_item
when: __network_is_booted
vars:
nmitems: "{{ lsr_connection_settings | selectattr('nmvalue', 'defined') | selectattr('nmvalue') | list }}"
items: "{{ lsr_connection_settings | rejectattr('nmvalue', 'defined') | list }}"
section: "{{ __nm_connection_item.section }}"
option: "{{ 'addresses' if __nm_connection_item.option == 'address1' else __nm_connection_item.option }}"
value: "{{ __nm_connection_item.nmvalue
if __nm_connection_item.nmvalue is defined and __nm_connection_item.nmvalue
else __nm_connection_item.value }}"
setting: "{{ section ~ '.' ~ option ~ ':' ~ value }}"
- name: Assert initscripts file settings
when:
- lsr_connection_name is defined
- lsr_connection_settings | d({}) | length > 0
- network_provider == "initscripts" or ansible_distribution_major_version | int < 9
vars:
__initscripts_connection_file_path: /etc/sysconfig/network-scripts/ifcfg-{{ lsr_connection_name }}
__initscripts_route_file_path: /etc/sysconfig/network-scripts/route-{{ lsr_connection_name }}
__initscripts_route6_file_path: /etc/sysconfig/network-scripts/route6-{{ lsr_connection_name }}
__check_route: "{{ lsr_connection_settings | selectattr('ifcfg_route_value', 'defined') | selectattr('ifcfg_route_value') |
map(attribute='ifcfg_route_value') | list | length > 0 }}"
__check_route6: "{{ lsr_connection_settings | selectattr('ifcfg_route6_value', 'defined') | selectattr('ifcfg_route6_value') |
map(attribute='ifcfg_route6_value') | list | length > 0 }}"
block:
- name: Show connection file
command: cat {{ __initscripts_connection_file_path | quote }}
changed_when: false
when: ansible_verbosity | int >= 2
- name: Slurp connection file
slurp:
src: "{{ __initscripts_connection_file_path }}"
register: __initscripts_connection_file
- name: Assert settings in initscripts connection file
assert:
that: __initscripts_connection_item in __initscripts_connection_file.content | b64decode
loop: "{{ lsr_connection_settings | selectattr('ifcfg_value', 'defined') | selectattr('ifcfg_value') |
map(attribute='ifcfg_value') | list }}"
loop_control:
loop_var: __initscripts_connection_item
- name: Slurp route file
when: __check_route
slurp:
src: "{{ __initscripts_route_file_path }}"
register: __initscripts_route_file
- name: Assert settings in initscripts route file
when: __check_route
assert:
that: __initscripts_route_item in __initscripts_route_file.content | b64decode
loop: "{{ lsr_connection_settings | selectattr('ifcfg_route_value', 'defined') | selectattr('ifcfg_route_value') |
map(attribute='ifcfg_route_value') | list }}"
loop_control:
loop_var: __initscripts_route_item
- name: Slurp route6 file
when: __check_route6
slurp:
src: "{{ __initscripts_route6_file_path }}"
register: __initscripts_route6_file
- name: Assert settings in initscripts route6 file
when: __check_route6
assert:
that: __initscripts_route6_item in __initscripts_route6_file.content | b64decode
loop: "{{ lsr_connection_settings | selectattr('ifcfg_route6_value', 'defined') | selectattr('ifcfg_route6_value') |
map(attribute='ifcfg_route6_value') | list }}"
loop_control:
loop_var: __initscripts_route6_item

View file

@ -3,4 +3,4 @@
- name: Import the task 'assert_device_present.yml'
import_tasks: tasks/assert_device_present.yml
vars:
interface: "{{ controller_device }}"
lsr_interface: "{{ controller_device }}"

View file

@ -2,7 +2,7 @@
---
- name: Include the task 'get_interface_stat.yml'
include_tasks: get_interface_stat.yml
- name: "Assert that the interface is absent - '{{ interface }}'"
- name: "Assert that the interface is absent - '{{ lsr_interface | d(interface) }}'"
assert:
that: not interface_stat.stat.exists
msg: "{{ interface }} exists"
msg: "{{ lsr_interface | d(interface) }} exists"

View file

@ -2,7 +2,9 @@
---
- name: Include the task 'get_interface_stat.yml'
include_tasks: get_interface_stat.yml
- name: "Assert that the interface is present - '{{ interface }}'"
when: ansible_connection != 'buildah'
- name: "Assert that the interface is present - '{{ lsr_interface | d(interface) }}'"
assert:
that: interface_stat.stat.exists
msg: "{{ interface }} does not exist"
msg: "{{ lsr_interface | d(interface) }} does not exist"
when: ansible_connection != 'buildah'

View file

@ -3,8 +3,8 @@
- name: Import the task 'assert_device_present.yml'
import_tasks: tasks/assert_device_present.yml
vars:
interface: "{{ dhcp_interface1 }}"
lsr_interface: "{{ dhcp_interface1 }}"
- name: Import the task 'assert_device_present.yml'
import_tasks: tasks/assert_device_present.yml
vars:
interface: "{{ dhcp_interface2 }}"
lsr_interface: "{{ dhcp_interface2 }}"

View file

@ -0,0 +1,21 @@
# SPDX-License-Identifier: BSD-3-Clause
# Inputs
# - lsr_connection_name: the connection name
# - lsr_connection_output: the output pattern to search for
# - network_provider: the network provider
---
- name: Assert NM connection status
when:
- lsr_connection_name is defined
- lsr_connection_output is defined
- network_provider == "nm"
- __network_is_booted
block:
- name: Show connection status
command: nmcli connection show {{ lsr_connection_name | quote }}
changed_when: false
register: __lsr_nm_connection_status
- name: Assert connection status
assert:
that: __lsr_nm_connection_status.stdout is search(lsr_connection_output)

View file

@ -20,6 +20,7 @@
ls -alrtF /etc/resolv.* || :
fi
changed_when: false
when: __network_is_booted | d(true) | bool
- name: Verify DNS and network connectivity
shell: |
@ -35,5 +36,7 @@
exit 1
fi
done
when: ansible_facts["distribution"] == "CentOS"
changed_when: false
when:
- ansible_facts["distribution"] == "CentOS"
- __network_is_booted | d(true) | bool

View file

@ -2,10 +2,10 @@
---
- name: Cleanup profile and device
shell: |
nmcli con delete {{ interface }}
nmcli con load /etc/sysconfig/network-scripts/ifcfg-{{ interface }}
rm -f /etc/sysconfig/network-scripts/ifcfg-{{ interface }}
ip link del {{ interface }}
nmcli con delete {{ lsr_interface | d(interface) }}
nmcli con load /etc/sysconfig/network-scripts/ifcfg-{{ lsr_interface | d(interface) }}
rm -f /etc/sysconfig/network-scripts/ifcfg-{{ lsr_interface | d(interface) }}
ip link del {{ lsr_interface | d(interface) }}
ignore_errors: true # noqa ignore-errors
changed_when: false
...

View file

@ -19,8 +19,8 @@
persistent_state: absent
state: down
failed_when: false
- name: Delete the device '{{ interface }}'
command: ip link del {{ interface }}
- name: Delete the device '{{ lsr_interface | d(interface) }}'
command: ip link del {{ lsr_interface | d(interface) }}
failed_when: false
changed_when: false
...

View file

@ -2,7 +2,7 @@
---
- name: Retrieve perm_hwaddr using ethtool
# wokeignore:rule=slave
command: cat /sys/class/net/{{ interface }}/bonding_slave/perm_hwaddr
command: cat /sys/class/net/{{ lsr_interface | d(interface) }}/bonding_slave/perm_hwaddr
register: mac_address_result
changed_when: false
failed_when: mac_address_result.rc != 0
@ -11,7 +11,7 @@
mac: "{{ mac_address_result.stdout_lines[-1].split(' ')[-1] }}"
- name: Display the retrieved MAC address
debug:
msg: "Retrieved MAC address for {{ interface }}: {{ mac }}"
msg: "Retrieved MAC address for {{ lsr_interface | d(interface) }}: {{ mac }}"
- name: Test matching the port device based on the perm_hwaddr
import_role:
name: linux-system-roles.network
@ -20,6 +20,6 @@
- name: "{{ profile }}"
state: up
type: ethernet
interface_name: "{{ interface }}"
interface_name: "{{ lsr_interface | d(interface) }}"
mac: "{{ mac }}"
...

View file

@ -1,49 +0,0 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- name: Include network role
include_role:
name: linux-system-roles.network
vars:
network_connections:
# Create a bond controller
- name: "{{ controller_profile }}"
state: up
type: bond
interface_name: "{{ controller_device }}"
bond:
mode: 802.3ad
ad_actor_sys_prio: 65535
ad_actor_system: 00:00:5e:00:53:5d
ad_select: stable
ad_user_port_key: 1023
all_ports_active: true
downdelay: 0
lacp_rate: slow
lp_interval: 128
miimon: 110
min_links: 0
num_grat_arp: 64
primary_reselect: better
resend_igmp: 225
updelay: 0
use_carrier: true
xmit_hash_policy: encap2+3
ip:
route_metric4: 65535
# add an ethernet to the bond
- name: "{{ port1_profile }}"
state: up
type: ethernet
interface_name: "{{ dhcp_interface1 }}"
controller: "{{ controller_profile }}"
# add a second ethernet to the bond
- name: "{{ port2_profile }}"
state: up
type: ethernet
interface_name: "{{ dhcp_interface2 }}"
controller: "{{ controller_profile }}"
- name: Show result
debug:
var: __network_connections_result
...

View file

@ -1,36 +0,0 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- name: Reconfigure the bond options
import_role:
name: linux-system-roles.network
vars:
network_connections:
# Create a bond controller
- name: "{{ controller_profile }}"
state: up
type: bond
interface_name: "{{ controller_device }}"
bond:
mode: active-backup
arp_interval: 60
arp_ip_target: 192.0.2.128
arp_validate: none
primary: "{{ dhcp_interface1 }}"
ip:
route_metric4: 65535
# add an ethernet to the bond
- name: "{{ port1_profile }}"
state: up
type: ethernet
interface_name: "{{ dhcp_interface1 }}"
controller: "{{ controller_profile }}"
# add a second ethernet to the bond
- name: "{{ port2_profile }}"
state: up
type: ethernet
interface_name: "{{ dhcp_interface2 }}"
controller: "{{ controller_profile }}"
- name: Show result
debug:
var: __network_connections_result
...

View file

@ -5,7 +5,7 @@
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
- name: "{{ lsr_interface | d(interface) }}"
persistent_state: present
type: bridge
ip:

View file

@ -5,7 +5,7 @@
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
- name: "{{ lsr_interface | d(interface) }}"
autoconnect: false
persistent_state: present
type: bridge

View file

@ -5,7 +5,7 @@
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
- name: "{{ lsr_interface | d(interface) }}"
autoconnect_retries: "{{ autocon_retries }}"
state: up
type: dummy

View file

@ -5,12 +5,12 @@
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
- name: "{{ lsr_interface | d(interface) }}"
state: up
persistent_state: present
autoconnect: true
type: ethernet
interface_name: "{{ interface }}"
interface_name: "{{ lsr_interface | d(interface) }}"
mac: "{{ mac }}"
ip:
dhcp4: false
@ -20,7 +20,7 @@
state: up
persistent_state: present
type: vlan
parent: "{{ interface }}"
parent: "{{ lsr_interface | d(interface) }}"
vlan:
id: 3732
autoconnect: true
@ -35,7 +35,7 @@
state: up
persistent_state: present
type: vlan
parent: "{{ interface }}"
parent: "{{ lsr_interface | d(interface) }}"
vlan:
id: 120
autoconnect: true

View file

@ -6,7 +6,7 @@
vars:
network_allow_restart: true
network_connections:
- name: "{{ interface }}"
- name: "{{ lsr_interface | d(interface) }}"
persistent_state: present
type: team
ip:

View file

@ -143,3 +143,17 @@
--dhcp-host 52:54:00:12:34:56,ignore --dhcp-host 52:54:00:12:34:57,ignore
fi
changed_when: false
when: ansible_connection != "buildah"
# When doing bootc validation, have to restart NetworkManager services
# to pick up newly created devices
- name: Restart NetworkManager services for testing
service:
name: "{{ item }}"
state: restarted
loop:
- NetworkManager.service
- NetworkManager-wait-online.service
when:
- network_provider == "nm"
- __bootc_validation | d(false)

View file

@ -8,7 +8,7 @@
vars:
network_allow_restart: '{{ wifi_restart_network }}'
network_connections:
- name: "{{ interface }}"
- name: "{{ lsr_interface | d(interface) }}"
type: wireless
wireless:
ssid: "My WPA2-PSK Network"

View file

@ -1,7 +1,10 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- name: Remove test interface if necessary
command: "ip link del {{ interface }}"
ignore_errors: true # noqa ignore-errors
changed_when: false
command: ip link del {{ lsr_interface | d(interface) | quote }}
changed_when: true
register: __delete_interface_result
failed_when:
- __delete_interface_result.rc != 0
- __delete_interface_result.stderr is not search("Cannot find device")
...

View file

@ -7,3 +7,4 @@
network_connections:
- name: "{{ profile }}"
state: down
persistent_state: "{{ lsr_persistent_state | d('present') }}"

View file

@ -1,15 +1,15 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- name: Get connection profile for '{{ interface }}'
- name: Get connection profile for '{{ lsr_interface | d(interface) }}'
shell:
executable: /bin/bash
cmd: |
set -euo pipefail
connection="$(nmcli -g GENERAL.CONNECTION device show {{ interface | quote }})" || :
connection="$(nmcli -g GENERAL.CONNECTION device show {{ lsr_interface | d(interface) | quote }})" || :
if [ -z "$connection" ]; then
nmcli device connect {{ interface | quote }} 1>&2
nmcli device connect {{ lsr_interface | d(interface) | quote }} 1>&2
fi
nmcli -g GENERAL.CONNECTION device show {{ interface | quote }}
nmcli -g GENERAL.CONNECTION device show {{ lsr_interface | d(interface) | quote }}
register: connection_name
changed_when: false
@ -22,7 +22,7 @@
nmcli device status || :
nmcli device show || :
nmcli connection show || :
nmcli connection show '{{ interface }}' || :
nmcli connection show '{{ lsr_interface | d(interface) }}' || :
ip a
echo connection_name: {{ connection_name | to_nice_json | quote }} || :
ls -alrtF /etc/sysconfig/network-scripts || :
@ -59,7 +59,7 @@
when: connection_name is failed or connection_name.stdout | length == 0
failed_when: connection_name is failed or connection_name.stdout | length == 0
- name: Bring down and delete the connection profile for '{{ interface }}'
- name: Bring down and delete the connection profile for '{{ lsr_interface | d(interface) }}'
include_role:
name: linux-system-roles.network
vars:

View file

@ -1,9 +1,9 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- name: "Get stat for interface {{ interface }}"
- name: "Get stat for interface {{ lsr_interface | d(interface) }}"
stat:
get_attributes: false
get_checksum: false
get_mime: false
path: "/sys/class/net/{{ interface }}"
path: "/sys/class/net/{{ lsr_interface | d(interface) }}"
register: interface_stat

View file

@ -22,8 +22,15 @@
# When certain profile is marked as absent but still up, the `nmcli connection`
# still show it with FILENAME starting with /run. Only consider profile exists
# when its FILENAME is in /etc folder
# in the non-booted case, we can predict the profile path from nm_offline backend
- name: Get NM profile info
shell: nmcli -f NAME,FILENAME connection show |grep {{ profile }} | grep /etc
vars:
nm_profile_cmd: >-
{{ "nmcli -f NAME,FILENAME connection show | grep " ~ profile ~ " | grep /etc"
if __network_is_booted
else "test -s /etc/NetworkManager/system-connections/" ~ profile ~ ".nmconnection" }}
# noqa command-instead-of-shell
shell: "{{ nm_profile_cmd }}"
register: nm_profile_exists
ignore_errors: true
changed_when: false

View file

@ -0,0 +1,25 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- name: Handle assert task file
include_tasks: "{{ lsr_assert_item }}"
when: lsr_assert_item is string
- name: Handle assert task with condition and variables
include_tasks: "{{ lsr_assert_item['what'] }}"
when:
- lsr_assert_item is mapping
- lsr_assert_item.get("condition", true)
vars:
lsr_connection_name: "{{ lsr_assert_item.get('lsr_connection_name', '') }}"
lsr_connection_settings: "{{ lsr_assert_item.get('lsr_connection_settings', []) }}"
lsr_connection_output: "{{ lsr_assert_item.get('lsr_connection_output', '') }}"
lsr_packages: "{{ lsr_assert_item.get('lsr_packages', []) }}"
lsr_command: "{{ lsr_assert_item.get('lsr_command', '') }}"
lsr_shell: "{{ lsr_assert_item.get('lsr_shell', '') }}"
lsr_stdout: "{{ lsr_assert_item.get('lsr_stdout', '') }}"
lsr_stdout_lines: "{{ lsr_assert_item.get('lsr_stdout_lines', []) }}"
lsr_stdout_regex_list: "{{ lsr_assert_item.get('lsr_stdout_regex_list', []) }}"
lsr_stderr: "{{ lsr_assert_item.get('lsr_stderr', '') }}"
lsr_not_stdout: "{{ lsr_assert_item.get('lsr_not_stdout', '') }}"
lsr_not_stderr: "{{ lsr_assert_item.get('lsr_not_stderr', '') }}"
profile: "{{ lsr_assert_item.get('profile', '') }}"

View file

@ -0,0 +1,15 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- name: Handle cleanup task file
include_tasks: "{{ lsr_cleanup_item }}"
when: lsr_cleanup_item is string
- name: Handle cleanup task with condition and variables
include_tasks: "{{ lsr_cleanup_item['what'] }}"
when:
- lsr_cleanup_item is mapping
- lsr_cleanup_item.get("condition", true)
vars:
profile: "{{ lsr_cleanup_item.get('profile', interface | d('')) }}"
state: "{{ lsr_cleanup_item.get('state', 'present') }}"
lsr_persistent_state: "{{ lsr_cleanup_item.get('lsr_persistent_state', '') }}"

View file

@ -0,0 +1,23 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- name: Handle setup task file
include_tasks: "{{ lsr_setup_item }}"
when: lsr_setup_item is string
- name: Handle setup task with condition and variables
include_tasks: "{{ lsr_setup_item['what'] }}"
when:
- lsr_setup_item is mapping
- lsr_setup_item.get("condition", true)
vars:
state: "{{ lsr_setup_item.get('state', 'present') }}"
lsr_interface: "{{ lsr_setup_item.get('lsr_interface', interface | d('')) }}"
lsr_packages: "{{ lsr_setup_item.get('lsr_packages', []) }}"
lsr_command: "{{ lsr_setup_item.get('lsr_command', '') }}"
lsr_shell: "{{ lsr_setup_item.get('lsr_shell', '') }}"
lsr_stdout: "{{ lsr_setup_item.get('lsr_stdout', '') }}"
lsr_stdout_lines: "{{ lsr_setup_item.get('lsr_stdout_lines', []) }}"
lsr_stdout_regex_list: "{{ lsr_setup_item.get('lsr_stdout_regex_list', []) }}"
lsr_stderr: "{{ lsr_setup_item.get('lsr_stderr', '') }}"
lsr_not_stdout: "{{ lsr_setup_item.get('lsr_not_stdout', '') }}"
lsr_not_stderr: "{{ lsr_setup_item.get('lsr_not_stderr', '') }}"

View file

@ -0,0 +1,21 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- name: Handle test task file
include_tasks: "{{ lsr_test_item }}"
when: lsr_test_item is string
- name: Handle test task with network role
when:
- lsr_test_item is mapping
- lsr_test_item.get("network_connections") is not none
- lsr_test_item.get("condition", true)
block:
- name: Include network role
include_role:
name: linux-system-roles.network
vars:
network_connections: "{{ lsr_test_item['network_connections'] }}"
- name: Show result
debug:
var: __network_connections_result

View file

@ -25,51 +25,73 @@
delay: 10
# veth
- name: Create veth interface {{ interface }}
- name: Create veth interface {{ lsr_interface | d(interface) }}
command: "{{ item }}"
with_items:
- ip link add {{ interface }} type veth peer name peer{{ interface }}
- ip link set peer{{ interface }} up
- ip link set {{ interface }} up
when: "type == 'veth' and state == 'present' and
interface not in current_interfaces"
- ip link add {{ lsr_interface | d(interface) }} type veth peer name peer{{ lsr_interface | d(interface) }}
- ip link set peer{{ lsr_interface | d(interface) }} up
- ip link set {{ lsr_interface | d(interface) }} up
when:
- ansible_connection != 'buildah'
- type == 'veth'
- state == 'present'
- lsr_interface | d(interface) not in current_interfaces
changed_when: false
- name: Set up veth as managed by NetworkManager
command: nmcli d set {{ interface }} managed true
command: nmcli d set {{ lsr_interface | d(interface) }} managed true
# The variable for `network_provider` is not exists yet,
# just ignore error for initscripts
ignore_errors: true # noqa ignore-errors
when: "type == 'veth' and state == 'present'"
when:
- ansible_connection != 'buildah'
- type == 'veth'
- state == 'present'
changed_when: false
- name: Delete veth interface {{ interface }}
command: ip link del {{ interface }} type veth
when: "type == 'veth' and state == 'absent' and
interface in current_interfaces"
- name: Delete veth interface {{ lsr_interface | d(interface) }}
command: ip link del {{ lsr_interface | d(interface) }} type veth
when:
- ansible_connection != 'buildah'
- type == 'veth'
- state == 'absent'
- lsr_interface | d(interface) in current_interfaces
changed_when: false
# dummy
- name: Create dummy interface {{ interface }}
command: ip link add "{{ interface }}" type dummy
when: "type == 'dummy' and state == 'present' and
interface not in current_interfaces"
- name: Create dummy interface {{ lsr_interface | d(interface) }}
command: ip link add "{{ lsr_interface | d(interface) }}" type dummy
when:
- ansible_connection != 'buildah'
- type == 'dummy'
- state == 'present'
- lsr_interface | d(interface) not in current_interfaces
changed_when: false
- name: Delete dummy interface {{ interface }}
command: ip link del "{{ interface }}" type dummy
when: "type == 'dummy' and state == 'absent' and
interface in current_interfaces"
- name: Delete dummy interface {{ lsr_interface | d(interface) }}
command: ip link del "{{ lsr_interface | d(interface) }}" type dummy
when:
- ansible_connection != 'buildah'
- type == 'dummy'
- state == 'absent'
- lsr_interface | d(interface) in current_interfaces
changed_when: false
# tap
- name: Create tap interface {{ interface }}
command: ip tuntap add dev {{ interface }} mode tap
when: "type == 'tap' and state == 'present'
and interface not in current_interfaces"
- name: Create tap interface {{ lsr_interface | d(interface) }}
command: ip tuntap add dev {{ lsr_interface | d(interface) }} mode tap
when:
- ansible_connection != 'buildah'
- type == 'tap'
- state == 'present'
- lsr_interface | d(interface) not in current_interfaces
changed_when: false
- name: Delete tap interface {{ interface }}
command: ip tuntap del dev {{ interface }} mode tap
when: "type == 'tap' and state == 'absent' and
interface in current_interfaces"
- name: Delete tap interface {{ lsr_interface | d(interface) }}
command: ip tuntap del dev {{ lsr_interface | d(interface) }} mode tap
when:
- ansible_connection != 'buildah'
- type == 'tap'
- state == 'absent'
- lsr_interface | d(interface) in current_interfaces
changed_when: false

View file

@ -5,7 +5,7 @@
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
- name: "{{ lsr_interface | d(interface) }}"
persistent_state: absent
state: down
...

View file

@ -4,3 +4,4 @@
package:
name: "{{ package }}"
state: absent
when: not __network_is_ostree | d(false)

View file

@ -6,9 +6,16 @@
debug:
msg: "########## {{ lsr_description }} ##########"
- name: Include network role vars used by tests
include_role:
name: linux-system-roles.network
tasks_from: set_facts.yml
public: true
when: __network_is_booted is not defined
- name: Show item
debug:
var: "{{ item }}"
msg: item {{ item | default("UNDEFINED") | to_nice_json }}
loop:
- lsr_description
- lsr_setup
@ -22,27 +29,50 @@
include_tasks: tasks/show_interfaces.yml
- name: Setup
include_tasks: "{{ item }}"
include_tasks: tasks/handle_setup_task.yml
loop: "{{ lsr_setup }}"
loop_control:
loop_var: lsr_setup_item
tags:
- "tests::setup"
- name: Test
include_tasks: "{{ item }}"
include_tasks: tasks/handle_test_task.yml
loop: "{{ lsr_test }}"
loop_control:
loop_var: lsr_test_item
when: not __bootc_validation | default(false)
tags:
- "tests::test"
- name: Asserts
include_tasks: "{{ item }}"
loop: "{{ lsr_assert }}"
tags:
- "tests::assert"
# When validation is enabled, we need to load the role variables
# and set the result because we aren't running the role to set
# the network connections - that was already done at build time
- name: Handle case where validation is enabled
when: __bootc_validation | default(false)
block:
- name: Load role variables
include_role:
name: linux-system-roles.network
tasks_from: set_facts.yml
public: true
- name: Conditional asserts
include_tasks: "{{ item['what'] }}"
when: item['condition']
loop: "{{ lsr_assert_when | default([]) }}"
- name: Set result
set_fact:
__network_connections_result:
failed: false
stderr: ""
stdout: ""
changed: true
stdout_lines: []
stderr_lines: []
# You can use either lsr_assert or lsr_assert_when - but not both
- name: Asserts
include_tasks: tasks/handle_assert_task.yml
loop: "{{ (lsr_assert | default([])) + (lsr_assert_when | default([])) }}"
loop_control:
loop_var: lsr_assert_item
- name: "Success in test '{{ lsr_description }}'"
debug:
@ -55,7 +85,7 @@
- name: Show item that failed
debug:
var: "{{ item }}"
var: "{{ item | d('UNDEFINED') }}"
loop: "{{ lsr_fail_debug | default([]) }}"
- name: Issue failed message
@ -63,9 +93,19 @@
msg: "!!!!! Failure in test '{{ lsr_description }}' !!!!!"
always:
- name: Create QEMU deployment during bootc end-to-end test
delegate_to: localhost
command: "{{ lsr_scriptdir | quote }}/bootc-buildah-qcow.sh {{ ansible_host | quote }}"
changed_when: true
when: ansible_connection == "buildah"
# skip cleanup if building with buildah
- name: Cleanup
include_tasks: "{{ item }}"
include_tasks: tasks/handle_cleanup_task.yml
loop: "{{ lsr_cleanup }}"
loop_control:
loop_var: lsr_cleanup_item
when: ansible_connection != "buildah"
tags:
- "tests::cleanup"
...

View file

@ -3,6 +3,7 @@
- name: Debug
debug:
msg: facts {{ ansible_facts | to_nice_json }}
when: ansible_verbosity | default(0) >= 3
# This task can be removed once the RHEL-8.5 is not tested anymore
- name: Install hostapd via CentOS Stream
@ -66,6 +67,7 @@
# Enable forwarding of EAP 802.1x messages through software bridge "br1".
echo 8 > /sys/class/net/br1/bridge/group_fwd_mask
changed_when: false
when: __network_is_booted
- name: Create hostapd config
copy:
@ -98,3 +100,20 @@
- name: Run hostapd in namespace
shell: ip netns exec ns1 hostapd -B /etc/hostapd/wired.conf && sleep 5
changed_when: false
when: __network_is_booted
# Reload test connection - nm tries to start the connection at boot
# but fails because the devices are not created yet - so restart the connection
# here after the devices are created and hostapd is running
- name: Reload test connection
shell:
executable: /bin/bash
cmd: |
set -euo pipefail
exec 1>&2
nmcli connection down {{ lsr_interface | d(interface) }} || :
nmcli connection up {{ lsr_interface | d(interface) }}
changed_when: false
when:
- network_provider == "nm"
- __bootc_validation | default(false)

View file

@ -2,6 +2,8 @@
---
- name: Include the task 'get_current_interfaces.yml'
include_tasks: get_current_interfaces.yml
when: ansible_connection != 'buildah'
- name: Show current_interfaces
debug:
msg: "current_interfaces: {{ current_interfaces }}"
when: ansible_connection != 'buildah'

View file

@ -55,7 +55,7 @@
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface | default('802-1x-test') }}"
- name: "{{ lsr_interface | d(interface | d('802-1x-test')) }}"
interface_name: veth2
state: up
type: ethernet