diff --git a/changelogs/fragments/2827-nmcli_fix_team_slave.yml b/changelogs/fragments/2827-nmcli_fix_team_slave.yml new file mode 100644 index 0000000000..02f001c4f5 --- /dev/null +++ b/changelogs/fragments/2827-nmcli_fix_team_slave.yml @@ -0,0 +1,2 @@ +bugfixes: + - nmcli - fixes team-slave configuration by adding connection.slave-type (https://github.com/ansible-collections/community.general/issues/766). diff --git a/plugins/modules/net_tools/nmcli.py b/plugins/modules/net_tools/nmcli.py index 657df3bd2a..7ed515fc75 100644 --- a/plugins/modules/net_tools/nmcli.py +++ b/plugins/modules/net_tools/nmcli.py @@ -833,6 +833,10 @@ class Nmcli(object): 'bridge-port.hairpin-mode': self.hairpin, 'bridge-port.priority': self.slavepriority, }) + elif self.type == 'team-slave': + options.update({ + 'connection.slave-type': 'team', + }) elif self.tunnel_conn_type: options.update({ 'ip-tunnel.local': self.ip_tunnel_local, diff --git a/tests/unit/plugins/modules/net_tools/test_nmcli.py b/tests/unit/plugins/modules/net_tools/test_nmcli.py index 911ffd1217..ba526b1d65 100644 --- a/tests/unit/plugins/modules/net_tools/test_nmcli.py +++ b/tests/unit/plugins/modules/net_tools/test_nmcli.py @@ -257,6 +257,50 @@ bridge-port.hairpin-mode: yes bridge-port.priority: 32 """ +TESTCASE_TEAM = [ + { + 'type': 'team', + 'conn_name': 'non_existent_nw_device', + 'ifname': 'team0_non_existant', + 'state': 'present', + '_ansible_check_mode': False, + } +] + +TESTCASE_TEAM_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 +""" + +TESTCASE_TEAM_SLAVE = [ + { + 'type': 'team-slave', + 'conn_name': 'non_existent_nw_slaved_device', + 'ifname': 'generic_slaved_non_existant', + 'master': 'team0_non_existant', + 'state': 'present', + '_ansible_check_mode': False, + } +] + +TESTCASE_TEAM_SLAVE_SHOW_OUTPUT = """\ +connection.id: non_existent_nw_slaved_device +connection.interface-name: generic_slaved_non_existant +connection.autoconnect: yes +connection.master: team0_non_existant +connection.slave-type: team +802-3-ethernet.mtu: auto +""" + TESTCASE_VLAN = [ { 'type': 'vlan', @@ -495,6 +539,20 @@ def mocked_bridge_slave_unchanged(mocker): execute_return=(0, TESTCASE_BRIDGE_SLAVE_SHOW_OUTPUT, "")) +@pytest.fixture +def mocked_team_connection_unchanged(mocker): + mocker_set(mocker, + connection_exists=True, + execute_return=(0, TESTCASE_TEAM_SHOW_OUTPUT, "")) + + +@pytest.fixture +def mocked_team_slave_connection_unchanged(mocker): + mocker_set(mocker, + connection_exists=True, + execute_return=(0, TESTCASE_TEAM_SLAVE_SHOW_OUTPUT, "")) + + @pytest.fixture def mocked_vlan_connection_unchanged(mocker): mocker_set(mocker, @@ -952,6 +1010,93 @@ def test_bridge_slave_unchanged(mocked_bridge_slave_unchanged, capfd): assert not results['changed'] +@pytest.mark.parametrize('patch_ansible_module', TESTCASE_TEAM, indirect=['patch_ansible_module']) +def test_team_connection_create(mocked_generic_connection_create, capfd): + """ + Test : Team connection created + """ + 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']: + 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, indirect=['patch_ansible_module']) +def test_team_connection_unchanged(mocked_team_connection_unchanged, capfd): + """ + Test : Team connection unchanged + """ + 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_SLAVE, indirect=['patch_ansible_module']) +def test_create_team_slave(mocked_generic_connection_create, capfd): + """ + Test if Team_slave created + """ + + 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-slave' + assert args[0][5] == 'con-name' + assert args[0][6] == 'non_existent_nw_slaved_device' + + for param in ['connection.autoconnect', 'connection.interface-name', 'connection.master', 'team0_non_existant', 'connection.slave-type']: + 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_SLAVE, indirect=['patch_ansible_module']) +def test_team_slave_connection_unchanged(mocked_team_slave_connection_unchanged, capfd): + """ + Test : Team slave connection unchanged + """ + 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_VLAN, indirect=['patch_ansible_module']) def test_create_vlan_con(mocked_generic_connection_create, capfd): """