ebc35bd79f
* nmcli: fix vlan connection modification Fixes #42322 (#42415)
* ensure optional items are set to empty strings rather than not presented
fix syntax of vlan modification command
* extended tests for nmcli
(cherry picked from commit fb72a5424c
)
* Changelog fragment for nmcli fix
451 lines
13 KiB
Python
451 lines
13 KiB
Python
# Copyright: (c) 2017 Ansible Project
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
import json
|
|
|
|
import pytest
|
|
|
|
from ansible.modules.net_tools import nmcli
|
|
|
|
pytestmark = pytest.mark.usefixtures('patch_ansible_module')
|
|
|
|
TESTCASE_CONNECTION = [
|
|
{
|
|
'type': 'ethernet',
|
|
'conn_name': 'non_existent_nw_device',
|
|
'state': 'absent',
|
|
'_ansible_check_mode': True,
|
|
},
|
|
{
|
|
'type': 'generic',
|
|
'conn_name': 'non_existent_nw_device',
|
|
'state': 'absent',
|
|
'_ansible_check_mode': True,
|
|
},
|
|
{
|
|
'type': 'team',
|
|
'conn_name': 'non_existent_nw_device',
|
|
'state': 'absent',
|
|
'_ansible_check_mode': True,
|
|
},
|
|
{
|
|
'type': 'bond',
|
|
'conn_name': 'non_existent_nw_device',
|
|
'state': 'absent',
|
|
'_ansible_check_mode': True,
|
|
},
|
|
{
|
|
'type': 'bond-slave',
|
|
'conn_name': 'non_existent_nw_device',
|
|
'state': 'absent',
|
|
'_ansible_check_mode': True,
|
|
},
|
|
{
|
|
'type': 'bridge',
|
|
'conn_name': 'non_existent_nw_device',
|
|
'state': 'absent',
|
|
'_ansible_check_mode': True,
|
|
},
|
|
{
|
|
'type': 'vlan',
|
|
'conn_name': 'non_existent_nw_device',
|
|
'state': 'absent',
|
|
'_ansible_check_mode': True,
|
|
},
|
|
]
|
|
|
|
TESTCASE_GENERIC = [
|
|
{
|
|
'type': 'generic',
|
|
'conn_name': 'non_existent_nw_device',
|
|
'ifname': 'generic_non_existant',
|
|
'ip4': '10.10.10.10',
|
|
'gw4': '10.10.10.1',
|
|
'state': 'present',
|
|
'_ansible_check_mode': False,
|
|
},
|
|
]
|
|
|
|
TESTCASE_GENERIC_DNS4_SEARCH = [
|
|
{
|
|
'type': 'generic',
|
|
'conn_name': 'non_existent_nw_device',
|
|
'ifname': 'generic_non_existant',
|
|
'ip4': '10.10.10.10',
|
|
'gw4': '10.10.10.1',
|
|
'state': 'present',
|
|
'dns4_search': 'search.redhat.com',
|
|
'dns6_search': 'search6.redhat.com',
|
|
'_ansible_check_mode': False,
|
|
}
|
|
]
|
|
|
|
TESTCASE_BOND = [
|
|
{
|
|
'type': 'bond',
|
|
'conn_name': 'non_existent_nw_device',
|
|
'ifname': 'bond_non_existant',
|
|
'mode': 'active-backup',
|
|
'ip4': '10.10.10.10',
|
|
'gw4': '10.10.10.1',
|
|
'state': 'present',
|
|
'primary': 'non_existent_primary',
|
|
'_ansible_check_mode': False,
|
|
}
|
|
]
|
|
|
|
TESTCASE_BRIDGE = [
|
|
{
|
|
'type': 'bridge',
|
|
'conn_name': 'non_existent_nw_device',
|
|
'ifname': 'br0_non_existant',
|
|
'ip4': '10.10.10.10',
|
|
'gw4': '10.10.10.1',
|
|
'maxage': '100',
|
|
'stp': True,
|
|
'state': 'present',
|
|
'_ansible_check_mode': False,
|
|
}
|
|
]
|
|
|
|
TESTCASE_BRIDGE_SLAVE = [
|
|
{
|
|
'type': 'bridge-slave',
|
|
'conn_name': 'non_existent_nw_device',
|
|
'ifname': 'br0_non_existant',
|
|
'path_cost': 100,
|
|
'state': 'present',
|
|
'_ansible_check_mode': False,
|
|
}
|
|
]
|
|
|
|
TESTCASE_VLAN = [
|
|
{
|
|
'type': 'vlan',
|
|
'conn_name': 'non_existent_nw_device',
|
|
'ifname': 'vlan_not_exists',
|
|
'ip4': '10.10.10.10',
|
|
'gw4': '10.10.10.1',
|
|
'state': 'present',
|
|
'_ansible_check_mode': False,
|
|
}
|
|
]
|
|
|
|
|
|
TESTCASE_ETHERNET_DHCP = [
|
|
{
|
|
'type': 'ethernet',
|
|
'conn_name': 'non_existent_nw_device',
|
|
'ifname': 'ethernet_non_existant',
|
|
'ip4': '10.10.10.10',
|
|
'gw4': '10.10.10.1',
|
|
'state': 'present',
|
|
'_ansible_check_mode': False,
|
|
'dhcp_client_id': '00:11:22:AA:BB:CC:DD',
|
|
}
|
|
]
|
|
|
|
|
|
def mocker_set(mocker, connection_exists=False):
|
|
"""
|
|
Common mocker object
|
|
"""
|
|
mocker.patch('ansible.modules.net_tools.nmcli.HAVE_DBUS', True)
|
|
mocker.patch('ansible.modules.net_tools.nmcli.HAVE_NM_CLIENT', True)
|
|
get_bin_path = mocker.patch('ansible.module_utils.basic.AnsibleModule.get_bin_path')
|
|
get_bin_path.return_value = '/usr/bin/nmcli'
|
|
connection = mocker.patch.object(nmcli.Nmcli, 'connection_exists')
|
|
connection.return_value = connection_exists
|
|
return connection
|
|
|
|
|
|
@pytest.fixture
|
|
def mocked_generic_connection_create(mocker):
|
|
mocker_set(mocker)
|
|
command_result = mocker.patch.object(nmcli.Nmcli, 'execute_command')
|
|
command_result.return_value = {"rc": 100, "out": "aaa", "err": "none"}
|
|
return command_result
|
|
|
|
|
|
@pytest.fixture
|
|
def mocked_generic_connection_modify(mocker):
|
|
mocker_set(mocker, connection_exists=True)
|
|
command_result = mocker.patch.object(nmcli.Nmcli, 'execute_command')
|
|
command_result.return_value = {"rc": 100, "out": "aaa", "err": "none"}
|
|
return command_result
|
|
|
|
|
|
@pytest.fixture
|
|
def mocked_connection_exists(mocker):
|
|
connection = mocker_set(mocker, connection_exists=True)
|
|
return connection
|
|
|
|
|
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_BOND, indirect=['patch_ansible_module'])
|
|
def test_bond_connection_create(mocked_generic_connection_create):
|
|
"""
|
|
Test : Bond 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] == 'bond'
|
|
assert args[0][5] == 'con-name'
|
|
assert args[0][6] == 'non_existent_nw_device'
|
|
assert args[0][7] == 'ifname'
|
|
assert args[0][8] == 'bond_non_existant'
|
|
|
|
for param in ['ipv4.gateway', 'primary', 'autoconnect', 'mode', 'active-backup', 'ipv4.address']:
|
|
assert param in args[0]
|
|
|
|
|
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_GENERIC, indirect=['patch_ansible_module'])
|
|
def test_generic_connection_create(mocked_generic_connection_create):
|
|
"""
|
|
Test : Generic 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] == 'generic'
|
|
assert args[0][5] == 'con-name'
|
|
assert args[0][6] == 'non_existent_nw_device'
|
|
|
|
for param in ['autoconnect', 'ipv4.gateway', 'ipv4.address']:
|
|
assert param in args[0]
|
|
|
|
|
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_GENERIC, indirect=['patch_ansible_module'])
|
|
def test_generic_connection_modify(mocked_generic_connection_modify):
|
|
"""
|
|
Test : Generic connection modify
|
|
"""
|
|
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] == 'mod'
|
|
assert args[0][3] == 'non_existent_nw_device'
|
|
|
|
for param in ['ipv4.gateway', 'ipv4.address']:
|
|
assert param in args[0]
|
|
|
|
|
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_GENERIC_DNS4_SEARCH, indirect=['patch_ansible_module'])
|
|
def test_generic_connection_create_dns_search(mocked_generic_connection_create):
|
|
"""
|
|
Test : Generic connection created with dns search
|
|
"""
|
|
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 'ipv4.dns-search' in args[0]
|
|
assert 'ipv6.dns-search' in args[0]
|
|
|
|
|
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_GENERIC_DNS4_SEARCH, indirect=['patch_ansible_module'])
|
|
def test_generic_connection_modify_dns_search(mocked_generic_connection_create):
|
|
"""
|
|
Test : Generic connection modified with dns search
|
|
"""
|
|
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 'ipv4.dns-search' in args[0]
|
|
assert 'ipv6.dns-search' in args[0]
|
|
|
|
|
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_CONNECTION, indirect=['patch_ansible_module'])
|
|
def test_dns4_none(mocked_connection_exists, capfd):
|
|
"""
|
|
Test if DNS4 param is None
|
|
"""
|
|
with pytest.raises(SystemExit):
|
|
nmcli.main()
|
|
|
|
out, err = capfd.readouterr()
|
|
results = json.loads(out)
|
|
assert results['changed']
|
|
|
|
|
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_BRIDGE, indirect=['patch_ansible_module'])
|
|
def test_create_bridge(mocked_generic_connection_create):
|
|
"""
|
|
Test if Bridge 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] == 'bridge'
|
|
assert args[0][5] == 'con-name'
|
|
assert args[0][6] == 'non_existent_nw_device'
|
|
|
|
for param in ['ip4', '10.10.10.10', 'gw4', '10.10.10.1', 'bridge.max-age', '100', 'bridge.stp', 'yes']:
|
|
assert param in args[0]
|
|
|
|
|
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_BRIDGE, indirect=['patch_ansible_module'])
|
|
def test_mod_bridge(mocked_generic_connection_modify):
|
|
"""
|
|
Test if Bridge modified
|
|
"""
|
|
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] == 'mod'
|
|
assert args[0][3] == 'non_existent_nw_device'
|
|
for param in ['ip4', '10.10.10.10', 'gw4', '10.10.10.1', 'bridge.max-age', '100', 'bridge.stp', 'yes']:
|
|
assert param in args[0]
|
|
|
|
|
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_BRIDGE_SLAVE, indirect=['patch_ansible_module'])
|
|
def test_create_bridge_slave(mocked_generic_connection_create):
|
|
"""
|
|
Test if Bridge_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] == 'bridge-slave'
|
|
assert args[0][5] == 'con-name'
|
|
assert args[0][6] == 'non_existent_nw_device'
|
|
|
|
for param in ['bridge-port.path-cost', '100']:
|
|
assert param in args[0]
|
|
|
|
|
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_BRIDGE_SLAVE, indirect=['patch_ansible_module'])
|
|
def test_mod_bridge_slave(mocked_generic_connection_modify):
|
|
"""
|
|
Test if Bridge_slave modified
|
|
"""
|
|
|
|
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] == 'mod'
|
|
assert args[0][3] == 'non_existent_nw_device'
|
|
|
|
for param in ['bridge-port.path-cost', '100']:
|
|
assert param in args[0]
|
|
|
|
|
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_VLAN, indirect=['patch_ansible_module'])
|
|
def test_create_vlan_con(mocked_generic_connection_create):
|
|
"""
|
|
Test if VLAN 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] == 'vlan'
|
|
assert args[0][5] == 'con-name'
|
|
assert args[0][6] == 'non_existent_nw_device'
|
|
|
|
for param in ['ip4', '10.10.10.10', 'gw4', '10.10.10.1']:
|
|
assert param in args[0]
|
|
|
|
|
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_VLAN, indirect=['patch_ansible_module'])
|
|
def test_mod_vlan_conn(mocked_generic_connection_modify):
|
|
"""
|
|
Test if VLAN modified
|
|
"""
|
|
|
|
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] == 'mod'
|
|
assert args[0][3] == 'non_existent_nw_device'
|
|
|
|
for param in ['ipv4.address', '10.10.10.10', 'ipv4.gateway', '10.10.10.1']:
|
|
assert param in args[0]
|
|
|
|
|
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_ETHERNET_DHCP, indirect=['patch_ansible_module'])
|
|
def test_eth_dhcp_client_id_con_create(mocked_generic_connection_create):
|
|
"""
|
|
Test : Ethernet connection created with DHCP_CLIENT_ID
|
|
"""
|
|
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 'ipv4.dhcp-client-id' in args[0]
|