From d4f272ba52840a752e09ccb6b21aca0aa94ce007 Mon Sep 17 00:00:00 2001 From: Alex Groshev <38885591+haddystuff@users.noreply.github.com> Date: Sun, 26 Mar 2023 09:27:00 +0200 Subject: [PATCH] nmcli: add runner_fast_rate option (#6148) * add runner_fast_rate option * unset default value for runner_fast_rate parameter * add some commas * Remove default in copy of argspec. Co-authored-by: Sam Potekhin --------- Co-authored-by: Felix Fontein Co-authored-by: Sam Potekhin --- ...6065-nmcli-add-runner-fast-rate-option.yml | 2 + plugins/modules/nmcli.py | 20 ++- tests/unit/plugins/modules/test_nmcli.py | 132 ++++++++++++++++++ 3 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/6065-nmcli-add-runner-fast-rate-option.yml diff --git a/changelogs/fragments/6065-nmcli-add-runner-fast-rate-option.yml b/changelogs/fragments/6065-nmcli-add-runner-fast-rate-option.yml new file mode 100644 index 0000000000..f49a10bc9e --- /dev/null +++ b/changelogs/fragments/6065-nmcli-add-runner-fast-rate-option.yml @@ -0,0 +1,2 @@ +minor_changes: + - nmcli - add support for ``team.runner-fast-rate`` parameter for ``team`` connections (https://github.com/ansible-collections/community.general/issues/6065). diff --git a/plugins/modules/nmcli.py b/plugins/modules/nmcli.py index b163b387a1..fa57a71675 100644 --- a/plugins/modules/nmcli.py +++ b/plugins/modules/nmcli.py @@ -412,6 +412,14 @@ options: type: str choices: [ same_all, by_active, only_active ] version_added: 3.4.0 + runner_fast_rate: + description: + - Option specifies the rate at which our link partner is asked to transmit LACPDU + packets. If this is C(true) then packets will be sent once per second. Otherwise they + will be sent every 30 seconds. + - Only allowed for C(lacp) runner. + type: bool + version_added: 6.5.0 vlanid: description: - This is only used with VLAN - VLAN ID in range <0-4095>. @@ -1472,6 +1480,7 @@ class Nmcli(object): self.mac = module.params['mac'] self.runner = module.params['runner'] self.runner_hwaddr_policy = module.params['runner_hwaddr_policy'] + self.runner_fast_rate = module.params['runner_fast_rate'] self.vlanid = module.params['vlanid'] self.vlandev = module.params['vlandev'] self.flags = module.params['flags'] @@ -1620,6 +1629,10 @@ class Nmcli(object): 'team.runner': self.runner, 'team.runner-hwaddr-policy': self.runner_hwaddr_policy, }) + if self.runner_fast_rate is not None: + options.update({ + 'team.runner-fast-rate': self.runner_fast_rate, + }) elif self.type == 'bridge-slave': options.update({ 'connection.slave-type': 'bridge', @@ -1880,7 +1893,8 @@ class Nmcli(object): 'ipv4.may-fail', 'ipv6.ignore-auto-dns', 'ipv6.ignore-auto-routes', - '802-11-wireless.hidden'): + '802-11-wireless.hidden', + 'team.runner-fast-rate'): return bool elif setting in ('ipv4.addresses', 'ipv6.addresses', @@ -2295,6 +2309,8 @@ def main(): choices=['broadcast', 'roundrobin', 'activebackup', 'loadbalance', 'lacp']), # team active-backup runner specific options runner_hwaddr_policy=dict(type='str', choices=['same_all', 'by_active', 'only_active']), + # team lacp runner specific options + runner_fast_rate=dict(type='bool'), # vlan specific vars vlanid=dict(type='int'), vlandev=dict(type='str'), @@ -2341,6 +2357,8 @@ def main(): if nmcli.type == "team": if nmcli.runner_hwaddr_policy and not nmcli.runner == "activebackup": nmcli.module.fail_json(msg="Runner-hwaddr-policy is only allowed for runner activebackup") + if nmcli.runner_fast_rate is not None and nmcli.runner != "lacp": + nmcli.module.fail_json(msg="runner-fast-rate is only allowed for runner lacp") # team-slave checks if nmcli.type == 'team-slave': if nmcli.master is None: diff --git a/tests/unit/plugins/modules/test_nmcli.py b/tests/unit/plugins/modules/test_nmcli.py index c19b4d4d9e..6cf7304316 100644 --- a/tests/unit/plugins/modules/test_nmcli.py +++ b/tests/unit/plugins/modules/test_nmcli.py @@ -602,6 +602,7 @@ ipv6.method: auto ipv6.ignore-auto-dns: no ipv6.ignore-auto-routes: no team.runner: roundrobin +team.runner-fast-rate: no """ TESTCASE_TEAM_HWADDR_POLICY_FAILS = [ @@ -615,6 +616,71 @@ TESTCASE_TEAM_HWADDR_POLICY_FAILS = [ } ] +TESTCASE_TEAM_RUNNER_FAST_RATE = [ + { + 'type': 'team', + 'conn_name': 'non_existent_nw_device', + 'ifname': 'team0_non_existant', + 'runner': 'lacp', + 'runner_fast_rate': True, + 'state': 'present', + '_ansible_check_mode': False, + } +] + +TESTCASE_TEAM_RUNNER_FAST_RATE_FAILS = [ + { + 'type': 'team', + 'conn_name': 'non_existent_nw_device', + 'ifname': 'team0_non_existant', + 'runner_fast_rate': True, + 'state': 'present', + '_ansible_check_mode': False, + }, + { + 'type': 'team', + 'conn_name': 'non_existent_nw_device', + 'ifname': 'team0_non_existant', + 'state': 'present', + 'runner_fast_rate': False, + '_ansible_check_mode': False, + }, + { + 'type': 'team', + 'conn_name': 'non_existent_nw_device', + 'ifname': 'team0_non_existant', + 'state': 'present', + 'runner': 'activebackup', + 'runner_fast_rate': False, + '_ansible_check_mode': False, + }, + { + 'type': 'team', + 'conn_name': 'non_existent_nw_device', + 'ifname': 'team0_non_existant', + 'state': 'present', + 'runner': 'activebackup', + 'runner_fast_rate': True, + '_ansible_check_mode': False, + } +] + +TESTCASE_TEAM_RUNNER_FAST_RATE_SHOW_OUTPUT = """\ +connection.id: non_existent_nw_device +connection.interface-name: team0_non_existant +connection.autoconnect: yes +connection.type: team +ipv4.ignore-auto-dns: no +ipv4.ignore-auto-routes: no +ipv4.never-default: no +ipv4.may-fail: yes +ipv6.method: auto +ipv6.ignore-auto-dns: no +ipv6.ignore-auto-routes: no +team.runner: lacp +team.runner-fast-rate: yes +""" + TESTCASE_TEAM_SLAVE = [ { 'type': 'team-slave', @@ -1436,6 +1502,13 @@ def mocked_team_connection_unchanged(mocker): execute_return=(0, TESTCASE_TEAM_SHOW_OUTPUT, "")) +@pytest.fixture +def mocked_team_runner_fast_rate_connection_unchanged(mocker): + mocker_set(mocker, + connection_exists=True, + execute_return=(0, TESTCASE_TEAM_RUNNER_FAST_RATE_SHOW_OUTPUT, "")) + + @pytest.fixture def mocked_team_slave_connection_unchanged(mocker): mocker_set(mocker, @@ -2247,6 +2320,63 @@ def test_team_connection_create_hwaddr_policy_fails(mocked_generic_connection_cr assert results['msg'] == "Runner-hwaddr-policy is only allowed for runner activebackup" +@pytest.mark.parametrize('patch_ansible_module', TESTCASE_TEAM_RUNNER_FAST_RATE, indirect=['patch_ansible_module']) +def test_team_runner_fast_rate_connection_create(mocked_generic_connection_create, capfd): + """ + Test : Team connection created with runner_fast_rate parameter + """ + with pytest.raises(SystemExit): + nmcli.main() + + assert nmcli.Nmcli.execute_command.call_count == 1 + arg_list = nmcli.Nmcli.execute_command.call_args_list + args, kwargs = arg_list[0] + + assert args[0][0] == '/usr/bin/nmcli' + assert args[0][1] == 'con' + assert args[0][2] == 'add' + assert args[0][3] == 'type' + assert args[0][4] == 'team' + assert args[0][5] == 'con-name' + assert args[0][6] == 'non_existent_nw_device' + + for param in ['connection.autoconnect', 'connection.interface-name', 'team0_non_existant', 'team.runner', 'lacp', 'team.runner-fast-rate', 'yes']: + assert param in args[0] + + out, err = capfd.readouterr() + results = json.loads(out) + assert not results.get('failed') + assert results['changed'] + + +@pytest.mark.parametrize('patch_ansible_module', TESTCASE_TEAM_RUNNER_FAST_RATE, indirect=['patch_ansible_module']) +def test_team_runner_fast_rate_connection_unchanged(mocked_team_runner_fast_rate_connection_unchanged, capfd): + """ + Test : Team connection unchanged with runner_fast_rate parameter + """ + with pytest.raises(SystemExit): + nmcli.main() + + out, err = capfd.readouterr() + results = json.loads(out) + assert not results.get('failed') + assert not results['changed'] + + +@pytest.mark.parametrize('patch_ansible_module', TESTCASE_TEAM_RUNNER_FAST_RATE_FAILS, indirect=['patch_ansible_module']) +def test_team_connection_create_runner_fast_rate_fails(mocked_generic_connection_create, capfd): + """ + Test : Team connection with runner_fast_rate enabled + """ + with pytest.raises(SystemExit): + nmcli.main() + + out, err = capfd.readouterr() + results = json.loads(out) + assert results.get('failed') + assert results['msg'] == "runner-fast-rate is only allowed for runner lacp" + + @pytest.mark.parametrize('patch_ansible_module', TESTCASE_TEAM_SLAVE, indirect=['patch_ansible_module']) def test_create_team_slave(mocked_generic_connection_create, capfd): """ @@ -3947,6 +4077,8 @@ def test_bond_connection_unchanged(mocked_generic_connection_diff_check, capfd): choices=['broadcast', 'roundrobin', 'activebackup', 'loadbalance', 'lacp']), # team active-backup runner specific options runner_hwaddr_policy=dict(type='str', choices=['same_all', 'by_active', 'only_active']), + # team lacp runner specific options + runner_fast_rate=dict(type='bool'), # vlan specific vars vlanid=dict(type='int'), vlandev=dict(type='str'),