diff --git a/README.md b/README.md index 0c69004..506aa32 100644 --- a/README.md +++ b/README.md @@ -378,6 +378,15 @@ By default, profiles are created with autoconnect enabled. - For `initscripts`, this corresponds to the `ONBOOT` property. +### `autoconnect_retries` + +The number of times a connection should be tried when autoactivating before giving up. +Zero means forever, -1 means the global default in NetworkManager (4 times if not +overridden). Setting this to 1 means to try activation only once before blocking +autoconnect. Note that after a timeout, NetworkManager will try to autoconnect again. + +- For `NetworkManager`, this corresponds to the `connection.autoconnect-retries` property. + ### `mac` The `mac` address is optional and restricts the profile to be usable only on diff --git a/examples/eth_simple_auto.yml b/examples/eth_simple_auto.yml index 5c7e9ea..2de85a4 100644 --- a/examples/eth_simple_auto.yml +++ b/examples/eth_simple_auto.yml @@ -11,6 +11,7 @@ state: up type: ethernet autoconnect: true + autoconnect_retries: 2 mac: "{{ network_mac1 }}" mtu: 1450 diff --git a/library/network_connections.py b/library/network_connections.py index fa7cf7b..4627bd1 100644 --- a/library/network_connections.py +++ b/library/network_connections.py @@ -906,6 +906,9 @@ class NMUtil: s_con.set_property(NM.SETTING_CONNECTION_ID, connection["name"]) s_con.set_property(NM.SETTING_CONNECTION_UUID, connection["nm.uuid"]) s_con.set_property(NM.SETTING_CONNECTION_AUTOCONNECT, connection["autoconnect"]) + s_con.set_property( + NM.SETTING_CONNECTION_AUTOCONNECT_RETRIES, connection["autoconnect_retries"] + ) s_con.set_property( NM.SETTING_CONNECTION_INTERFACE_NAME, connection["interface_name"] ) diff --git a/module_utils/network_lsr/argument_validator.py b/module_utils/network_lsr/argument_validator.py index 8209b76..4baa321 100644 --- a/module_utils/network_lsr/argument_validator.py +++ b/module_utils/network_lsr/argument_validator.py @@ -1866,6 +1866,12 @@ class ArgValidator_DictConnection(ArgValidatorDict): "type", enum_values=ArgValidator_DictConnection.VALID_TYPES ), ArgValidatorBool("autoconnect", default_value=True), + ArgValidatorNum( + "autoconnect_retries", + val_min=0, + val_max=UINT32_MAX, + default_value=-1, + ), ArgValidatorStr( "port_type", enum_values=ArgValidator_DictConnection.VALID_PORT_TYPES, diff --git a/tests/playbooks/tests_dummy.yml b/tests/playbooks/tests_dummy.yml index 518795d..e484856 100644 --- a/tests/playbooks/tests_dummy.yml +++ b/tests/playbooks/tests_dummy.yml @@ -3,6 +3,7 @@ - name: Play for testing dummy connection hosts: all vars: + autocon_retries: 2 interface: dummy0 profile: "{{ interface }}" lsr_fail_debug: @@ -30,6 +31,7 @@ lsr_assert: - tasks/assert_profile_present.yml - tasks/assert_device_present.yml + - tasks/assert_autoconnect_retries.yml lsr_cleanup: - tasks/cleanup_profile+device.yml - tasks/check_network_dns.yml diff --git a/tests/tasks/assert_autoconnect_retries.yml b/tests/tasks/assert_autoconnect_retries.yml new file mode 100644 index 0000000..8ebea27 --- /dev/null +++ b/tests/tasks/assert_autoconnect_retries.yml @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: BSD-3-Clause +--- +- name: Get autoconnect retries + command: > + nmcli -f connection.autoconnect-retries connection show {{ profile }} + register: autoconnect_retries + ignore_errors: true + changed_when: false +- name: "Assert that autoconnect-retries is configured as specified" + assert: + that: + - autoconnect_retries.stdout.split(":")[1] | trim + == autocon_retries | string + msg: "autoconnect-retries is configured as + {{ autoconnect_retries.stdout.split(':')[1] | trim }} + but specified as {{ autocon_retries }}" diff --git a/tests/tasks/create_dummy_profile.yml b/tests/tasks/create_dummy_profile.yml index a1b9655..9b914eb 100644 --- a/tests/tasks/create_dummy_profile.yml +++ b/tests/tasks/create_dummy_profile.yml @@ -6,6 +6,7 @@ vars: network_connections: - name: "{{ interface }}" + autoconnect_retries: "{{ autocon_retries }}" state: up type: dummy ip: diff --git a/tests/unit/test_network_connections.py b/tests/unit/test_network_connections.py index cfdc01f..16fd046 100644 --- a/tests/unit/test_network_connections.py +++ b/tests/unit/test_network_connections.py @@ -177,6 +177,7 @@ class TestValidator(Python26CompatTestCase): # default values when "type" is specified and state is not self.default_connection_settings = { "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -591,6 +592,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -651,6 +653,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -706,6 +709,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": False, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -798,6 +802,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -870,6 +875,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -939,6 +945,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -1047,6 +1054,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -1105,6 +1113,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -1209,6 +1218,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -1290,6 +1300,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -1389,6 +1400,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -1447,6 +1459,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -1551,6 +1564,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -1604,6 +1618,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethtool": ETHTOOL_DEFAULTS, "force_state_change": None, @@ -1668,6 +1683,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethtool": ETHTOOL_DEFAULTS, "force_state_change": None, @@ -1781,6 +1797,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -1828,6 +1845,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -1898,6 +1916,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "bond": { "mode": "balance-rr", "ad_actor_sys_prio": None, @@ -1981,6 +2000,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "bond": { "mode": "active-backup", "ad_actor_sys_prio": None, @@ -2076,6 +2096,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -2129,6 +2150,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": {"autoneg": False, "duplex": "half", "speed": 400}, "ethtool": ETHTOOL_DEFAULTS, @@ -2211,6 +2233,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -2258,6 +2281,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -2321,6 +2345,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethtool": ETHTOOL_DEFAULTS, "force_state_change": None, @@ -2401,6 +2426,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethtool": ETHTOOL_DEFAULTS, "force_state_change": None, @@ -2488,6 +2514,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethtool": ETHTOOL_DEFAULTS, "ignore_errors": None, @@ -2533,6 +2560,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethtool": ETHTOOL_DEFAULTS, "force_state_change": None, @@ -2644,6 +2672,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -2752,6 +2781,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -2911,6 +2941,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -3071,6 +3102,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -3155,6 +3187,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -3239,6 +3272,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethernet": ETHERNET_DEFAULTS, "ethtool": ETHTOOL_DEFAULTS, @@ -3322,6 +3356,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethtool": ETHTOOL_DEFAULTS, "force_state_change": None, @@ -3394,6 +3429,7 @@ class TestValidator(Python26CompatTestCase): { "actions": ["present", "up"], "autoconnect": True, + "autoconnect_retries": -1, "check_iface_exists": True, "ethtool": ETHTOOL_DEFAULTS, "force_state_change": None,