feat: support this role in container builds

Feature: Support running the timesync role during container builds.

Reason: This is particularly useful for building bootc derivative OSes.

Result: These flags enable running the bootc container scenarios in CI,
which ensures that the role works in buildah build environment. This
allows us to officially support this role for image mode builds.

Signed-off-by: Rich Megginson <rmeggins@redhat.com>
This commit is contained in:
Martin Pitt 2025-06-26 14:57:59 +02:00 committed by Rich Megginson
parent 3df2be4e86
commit e8a3ff4881
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