mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
nmcli: added new module option 'slave_type' to allow create non-ethernet slave connections (#6108)
* nmcli: added new module option 'slave_type' to allow create non-ethernet slave connections * argument specs updated * documentation updated * examples updated * added warning message when using type='bridge-slave' * remove trailing whitespace * Added warnings about rewrite 'slave-type' property when using type one of 'bond-slave', 'bridge-slave', 'team-slave'. Added module fails when user sets contradicting values of 'slave-type' for types 'bond-slave', 'bridge-slave', 'team-slave'. Returned back checking for types that can be a slave to assign 'master' and 'slave-type' properties. * Extending list of slave-conn-types * Update plugins/modules/nmcli.py Version updated Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com> * Update plugins/modules/nmcli.py Updated documentation for `slave_type` Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com> * Updated argspec's 'required_by' for 'master' property. * Fixed mistake in property naming in module argspec. * changelog fragment and module docs updated * Validation of 'master', 'slave_type' options improved. (rebased) * Validation of 'master' and 'slave_type' separated to special method. * Wrote 6 tests for slave_type option behaviour * Removed erroneously added property 'hairpin' * Update version_added for 'slave_type' Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com> * Update changelogs/fragments/473-nmcli-slave-type-implemented.yml Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/nmcli.py Co-authored-by: Felix Fontein <felix@fontein.de> * Let master be without slave_type --------- Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com> Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
9f3c86a589
commit
c949f3a834
3 changed files with 389 additions and 8 deletions
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- nmcli - new module option ``slave_type`` added to allow creation of various types of slave devices (https://github.com/ansible-collections/community.general/issues/473, https://github.com/ansible-collections/community.general/pull/6108).
|
|
@ -66,6 +66,8 @@ options:
|
||||||
- Type C(macvlan) is added in community.general 6.6.0.
|
- Type C(macvlan) is added in community.general 6.6.0.
|
||||||
- Type C(wireguard) is added in community.general 4.3.0.
|
- Type C(wireguard) is added in community.general 4.3.0.
|
||||||
- Type C(vpn) is added in community.general 5.1.0.
|
- Type C(vpn) is added in community.general 5.1.0.
|
||||||
|
- Using C(bond-slave), C(bridge-slave) or C(team-slave) implies C(ethernet) connection type with corresponding I(slave_type) option.
|
||||||
|
- If you want to control non-ethernet connection attached to C(bond), C(bridge) or C(team) consider using C(slave_type) option.
|
||||||
type: str
|
type: str
|
||||||
choices: [ bond, bond-slave, bridge, bridge-slave, dummy, ethernet, generic, gre, infiniband, ipip, macvlan, sit, team, team-slave, vlan, vxlan,
|
choices: [ bond, bond-slave, bridge, bridge-slave, dummy, ethernet, generic, gre, infiniband, ipip, macvlan, sit, team, team-slave, vlan, vxlan,
|
||||||
wifi, gsm, wireguard, vpn ]
|
wifi, gsm, wireguard, vpn ]
|
||||||
|
@ -81,9 +83,16 @@ options:
|
||||||
type: str
|
type: str
|
||||||
choices: [ datagram, connected ]
|
choices: [ datagram, connected ]
|
||||||
version_added: 5.8.0
|
version_added: 5.8.0
|
||||||
|
slave_type:
|
||||||
|
description:
|
||||||
|
- Type of the device of this slave's master connection (for example C(bond)).
|
||||||
|
type: str
|
||||||
|
choices: [ 'bond', 'bridge', 'team' ]
|
||||||
|
version_added: 7.0.0
|
||||||
master:
|
master:
|
||||||
description:
|
description:
|
||||||
- Master <master (ifname, or connection UUID or conn_name) of bridge, team, bond master connection profile.
|
- Master <master (ifname, or connection UUID or conn_name) of bridge, team, bond master connection profile.
|
||||||
|
- Mandatory if I(slave_type) is defined.
|
||||||
type: str
|
type: str
|
||||||
ip4:
|
ip4:
|
||||||
description:
|
description:
|
||||||
|
@ -1429,6 +1438,39 @@ EXAMPLES = r'''
|
||||||
autoconnect: false
|
autoconnect: false
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
|
## Creating bond attached to bridge example
|
||||||
|
- name: Create bond attached to bridge
|
||||||
|
community.general.nmcli:
|
||||||
|
type: bond
|
||||||
|
conn_name: bond0
|
||||||
|
slave_type: bridge
|
||||||
|
master: br0
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create master bridge
|
||||||
|
community.general.nmcli:
|
||||||
|
type: bridge
|
||||||
|
conn_name: br0
|
||||||
|
method4: disabled
|
||||||
|
method6: disabled
|
||||||
|
state: present
|
||||||
|
|
||||||
|
## Creating vlan connection attached to bridge
|
||||||
|
- name: Create master bridge
|
||||||
|
community.general.nmcli:
|
||||||
|
type: bridge
|
||||||
|
conn_name: br0
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create VLAN 5
|
||||||
|
community.general.nmcli:
|
||||||
|
type: vlan
|
||||||
|
conn_name: eth0.5
|
||||||
|
slave_type: bridge
|
||||||
|
master: br0
|
||||||
|
vlandev: eth0
|
||||||
|
vlanid: 5
|
||||||
|
state: present
|
||||||
'''
|
'''
|
||||||
|
|
||||||
RETURN = r"""#
|
RETURN = r"""#
|
||||||
|
@ -1475,6 +1517,7 @@ class Nmcli(object):
|
||||||
self.ignore_unsupported_suboptions = module.params['ignore_unsupported_suboptions']
|
self.ignore_unsupported_suboptions = module.params['ignore_unsupported_suboptions']
|
||||||
self.autoconnect = module.params['autoconnect']
|
self.autoconnect = module.params['autoconnect']
|
||||||
self.conn_name = module.params['conn_name']
|
self.conn_name = module.params['conn_name']
|
||||||
|
self.slave_type = module.params['slave_type']
|
||||||
self.master = module.params['master']
|
self.master = module.params['master']
|
||||||
self.ifname = module.params['ifname']
|
self.ifname = module.params['ifname']
|
||||||
self.type = module.params['type']
|
self.type = module.params['type']
|
||||||
|
@ -1570,6 +1613,14 @@ class Nmcli(object):
|
||||||
|
|
||||||
self.edit_commands = []
|
self.edit_commands = []
|
||||||
|
|
||||||
|
self.extra_options_validation()
|
||||||
|
|
||||||
|
def extra_options_validation(self):
|
||||||
|
""" Additional validation of options set passed to module that cannot be implemented in module's argspecs. """
|
||||||
|
if self.type not in ("bridge-slave", "team-slave", "bond-slave"):
|
||||||
|
if self.master is None and self.slave_type is not None:
|
||||||
|
self.module.fail_json(msg="'master' option is required when 'slave_type' is specified.")
|
||||||
|
|
||||||
def execute_command(self, cmd, use_unsafe_shell=False, data=None):
|
def execute_command(self, cmd, use_unsafe_shell=False, data=None):
|
||||||
if isinstance(cmd, list):
|
if isinstance(cmd, list):
|
||||||
cmd = [to_text(item) for item in cmd]
|
cmd = [to_text(item) for item in cmd]
|
||||||
|
@ -1634,6 +1685,7 @@ class Nmcli(object):
|
||||||
if self.slave_conn_type:
|
if self.slave_conn_type:
|
||||||
options.update({
|
options.update({
|
||||||
'connection.master': self.master,
|
'connection.master': self.master,
|
||||||
|
'connection.slave-type': self.slave_type,
|
||||||
})
|
})
|
||||||
|
|
||||||
# Options specific to a connection type.
|
# Options specific to a connection type.
|
||||||
|
@ -1649,9 +1701,17 @@ class Nmcli(object):
|
||||||
'xmit_hash_policy': self.xmit_hash_policy,
|
'xmit_hash_policy': self.xmit_hash_policy,
|
||||||
})
|
})
|
||||||
elif self.type == 'bond-slave':
|
elif self.type == 'bond-slave':
|
||||||
options.update({
|
if self.slave_type and self.slave_type != 'bond':
|
||||||
'connection.slave-type': 'bond',
|
self.module.fail_json(msg="Connection type '%s' cannot be combined with '%s' slave-type. "
|
||||||
})
|
"Allowed slave-type for '%s' is 'bond'."
|
||||||
|
% (self.type, self.slave_type, self.type)
|
||||||
|
)
|
||||||
|
if not self.slave_type:
|
||||||
|
self.module.warn("Connection 'slave-type' property automatically set to 'bond' "
|
||||||
|
"because of using 'bond-slave' connection type.")
|
||||||
|
options.update({
|
||||||
|
'connection.slave-type': 'bond',
|
||||||
|
})
|
||||||
elif self.type == 'bridge':
|
elif self.type == 'bridge':
|
||||||
options.update({
|
options.update({
|
||||||
'bridge.ageing-time': self.ageingtime,
|
'bridge.ageing-time': self.ageingtime,
|
||||||
|
@ -1675,16 +1735,36 @@ class Nmcli(object):
|
||||||
'team.runner-fast-rate': self.runner_fast_rate,
|
'team.runner-fast-rate': self.runner_fast_rate,
|
||||||
})
|
})
|
||||||
elif self.type == 'bridge-slave':
|
elif self.type == 'bridge-slave':
|
||||||
|
if self.slave_type and self.slave_type != 'bridge':
|
||||||
|
self.module.fail_json(msg="Connection type '%s' cannot be combined with '%s' slave-type. "
|
||||||
|
"Allowed slave-type for '%s' is 'bridge'."
|
||||||
|
% (self.type, self.slave_type, self.type)
|
||||||
|
)
|
||||||
|
if not self.slave_type:
|
||||||
|
self.module.warn("Connection 'slave-type' property automatically set to 'bridge' "
|
||||||
|
"because of using 'bridge-slave' connection type.")
|
||||||
|
options.update({'connection.slave-type': 'bridge'})
|
||||||
|
self.module.warn(
|
||||||
|
"Connection type as 'bridge-slave' implies 'ethernet' connection with 'bridge' slave-type. "
|
||||||
|
"Consider using slave_type='bridge' with necessary type."
|
||||||
|
)
|
||||||
options.update({
|
options.update({
|
||||||
'connection.slave-type': 'bridge',
|
|
||||||
'bridge-port.path-cost': self.path_cost,
|
'bridge-port.path-cost': self.path_cost,
|
||||||
'bridge-port.hairpin-mode': self.hairpin,
|
'bridge-port.hairpin-mode': self.hairpin,
|
||||||
'bridge-port.priority': self.slavepriority,
|
'bridge-port.priority': self.slavepriority,
|
||||||
})
|
})
|
||||||
elif self.type == 'team-slave':
|
elif self.type == 'team-slave':
|
||||||
options.update({
|
if self.slave_type and self.slave_type != 'team':
|
||||||
'connection.slave-type': 'team',
|
self.module.fail_json(msg="Connection type '%s' cannot be combined with '%s' slave-type. "
|
||||||
})
|
"Allowed slave-type for '%s' is 'team'."
|
||||||
|
% (self.type, self.slave_type, self.type)
|
||||||
|
)
|
||||||
|
if not self.slave_type:
|
||||||
|
self.module.warn("Connection 'slave-type' property automatically set to 'team' "
|
||||||
|
"because of using 'team-slave' connection type.")
|
||||||
|
options.update({
|
||||||
|
'connection.slave-type': 'team',
|
||||||
|
})
|
||||||
elif self.tunnel_conn_type:
|
elif self.tunnel_conn_type:
|
||||||
options.update({
|
options.update({
|
||||||
'ip-tunnel.local': self.ip_tunnel_local,
|
'ip-tunnel.local': self.ip_tunnel_local,
|
||||||
|
@ -1869,6 +1949,12 @@ class Nmcli(object):
|
||||||
@property
|
@property
|
||||||
def slave_conn_type(self):
|
def slave_conn_type(self):
|
||||||
return self.type in (
|
return self.type in (
|
||||||
|
'ethernet',
|
||||||
|
'bridge',
|
||||||
|
'bond',
|
||||||
|
'vlan',
|
||||||
|
'team',
|
||||||
|
'wifi',
|
||||||
'bond-slave',
|
'bond-slave',
|
||||||
'bridge-slave',
|
'bridge-slave',
|
||||||
'team-slave',
|
'team-slave',
|
||||||
|
@ -2260,6 +2346,7 @@ def main():
|
||||||
state=dict(type='str', required=True, choices=['absent', 'present']),
|
state=dict(type='str', required=True, choices=['absent', 'present']),
|
||||||
conn_name=dict(type='str', required=True),
|
conn_name=dict(type='str', required=True),
|
||||||
master=dict(type='str'),
|
master=dict(type='str'),
|
||||||
|
slave_type=dict(type='str', choices=['bond', 'bridge', 'team']),
|
||||||
ifname=dict(type='str'),
|
ifname=dict(type='str'),
|
||||||
type=dict(type='str',
|
type=dict(type='str',
|
||||||
choices=[
|
choices=[
|
||||||
|
@ -2416,7 +2503,7 @@ def main():
|
||||||
if nmcli.runner_fast_rate is not None and nmcli.runner != "lacp":
|
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")
|
nmcli.module.fail_json(msg="runner-fast-rate is only allowed for runner lacp")
|
||||||
# team-slave checks
|
# team-slave checks
|
||||||
if nmcli.type == 'team-slave':
|
if nmcli.type == 'team-slave' or nmcli.slave_type == 'team':
|
||||||
if nmcli.master is None:
|
if nmcli.master is None:
|
||||||
nmcli.module.fail_json(msg="Please specify a name for the master when type is %s" % nmcli.type)
|
nmcli.module.fail_json(msg="Please specify a name for the master when type is %s" % nmcli.type)
|
||||||
if nmcli.ifname is None:
|
if nmcli.ifname is None:
|
||||||
|
|
|
@ -4031,6 +4031,7 @@ def test_bond_connection_unchanged(mocked_generic_connection_diff_check, capfd):
|
||||||
state=dict(type='str', required=True, choices=['absent', 'present']),
|
state=dict(type='str', required=True, choices=['absent', 'present']),
|
||||||
conn_name=dict(type='str', required=True),
|
conn_name=dict(type='str', required=True),
|
||||||
master=dict(type='str'),
|
master=dict(type='str'),
|
||||||
|
slave_type=dict(type=str, choices=['bond', 'bridge', 'team']),
|
||||||
ifname=dict(type='str'),
|
ifname=dict(type='str'),
|
||||||
type=dict(type='str',
|
type=dict(type='str',
|
||||||
choices=[
|
choices=[
|
||||||
|
@ -4258,3 +4259,294 @@ def test_macvlan_mod(mocked_generic_connection_modify, capfd):
|
||||||
results = json.loads(out)
|
results = json.loads(out)
|
||||||
assert not results.get('failed')
|
assert not results.get('failed')
|
||||||
assert results['changed']
|
assert results['changed']
|
||||||
|
|
||||||
|
|
||||||
|
TESTCASE_SLAVE_TYPE_BRIDGE_CONNECTION = [
|
||||||
|
{
|
||||||
|
'type': 'ethernet',
|
||||||
|
'conn_name': 'fake_conn',
|
||||||
|
'ifname': 'fake_eth0',
|
||||||
|
'state': 'present',
|
||||||
|
'slave_type': 'bridge',
|
||||||
|
'master': 'fake_br0',
|
||||||
|
'_ansible_check_mode': False,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
TESTCASE_SLAVE_TYPE_BRIDGE_CONNECTION_SHOW_OUTPUT = """\
|
||||||
|
connection.id: fake_conn
|
||||||
|
connection.type: 802-3-ethernet
|
||||||
|
connection.interface-name: fake_eth0
|
||||||
|
connection.autoconnect: yes
|
||||||
|
connection.master: --
|
||||||
|
connection.slave-type: --
|
||||||
|
802-3-ethernet.mtu: auto
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
TESTCASE_SLAVE_TYPE_BRIDGE_CONNECTION_UNCHANGED_SHOW_OUTPUT = """\
|
||||||
|
connection.id: fake_conn
|
||||||
|
connection.type: 802-3-ethernet
|
||||||
|
connection.interface-name: fake_eth0
|
||||||
|
connection.autoconnect: yes
|
||||||
|
connection.master: fake_br0
|
||||||
|
connection.slave-type: bridge
|
||||||
|
802-3-ethernet.mtu: auto
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mocked_slave_type_bridge_create(mocker):
|
||||||
|
mocker_set(mocker,
|
||||||
|
execute_return=None,
|
||||||
|
execute_side_effect=(
|
||||||
|
(0, TESTCASE_SLAVE_TYPE_BRIDGE_CONNECTION_SHOW_OUTPUT, ""),
|
||||||
|
(0, "", ""),
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_SLAVE_TYPE_BRIDGE_CONNECTION, indirect=['patch_ansible_module'])
|
||||||
|
def test_create_slave_type_bridge(mocked_slave_type_bridge_create, capfd):
|
||||||
|
"""
|
||||||
|
Test : slave for 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] == 'ethernet'
|
||||||
|
assert args[0][5] == 'con-name'
|
||||||
|
assert args[0][6] == 'fake_conn'
|
||||||
|
con_master_index = args[0].index('connection.master')
|
||||||
|
slave_type_index = args[0].index('connection.slave-type')
|
||||||
|
assert args[0][con_master_index + 1] == 'fake_br0'
|
||||||
|
assert args[0][slave_type_index + 1] == 'bridge'
|
||||||
|
|
||||||
|
out, err = capfd.readouterr()
|
||||||
|
results = json.loads(out)
|
||||||
|
assert not results.get('failed')
|
||||||
|
assert results['changed']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mocked_create_slave_type_bridge_unchanged(mocker):
|
||||||
|
mocker_set(mocker,
|
||||||
|
connection_exists=True,
|
||||||
|
execute_return=(0, TESTCASE_SLAVE_TYPE_BRIDGE_CONNECTION_UNCHANGED_SHOW_OUTPUT, ""))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_SLAVE_TYPE_BRIDGE_CONNECTION, indirect=['patch_ansible_module'])
|
||||||
|
def test_slave_type_bridge_unchanged(mocked_create_slave_type_bridge_unchanged, capfd):
|
||||||
|
"""
|
||||||
|
Test : Existent slave for bridge unchanged
|
||||||
|
"""
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
|
nmcli.main()
|
||||||
|
|
||||||
|
out, err = capfd.readouterr()
|
||||||
|
results = json.loads(out)
|
||||||
|
assert not results.get('failed')
|
||||||
|
assert not results['changed']
|
||||||
|
|
||||||
|
|
||||||
|
TESTCASE_SLAVE_TYPE_BOND_CONNECTION = [
|
||||||
|
{
|
||||||
|
'type': 'ethernet',
|
||||||
|
'conn_name': 'fake_conn',
|
||||||
|
'ifname': 'fake_eth0',
|
||||||
|
'state': 'present',
|
||||||
|
'slave_type': 'bond',
|
||||||
|
'master': 'fake_bond0',
|
||||||
|
'_ansible_check_mode': False,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
TESTCASE_SLAVE_TYPE_BOND_CONNECTION_SHOW_OUTPUT = """\
|
||||||
|
connection.id: fake_conn
|
||||||
|
connection.type: 802-3-ethernet
|
||||||
|
connection.interface-name: fake_eth0
|
||||||
|
connection.autoconnect: yes
|
||||||
|
connection.master: --
|
||||||
|
connection.slave-type: --
|
||||||
|
802-3-ethernet.mtu: auto
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
TESTCASE_SLAVE_TYPE_BOND_CONNECTION_UNCHANGED_SHOW_OUTPUT = """\
|
||||||
|
connection.id: fake_conn
|
||||||
|
connection.type: 802-3-ethernet
|
||||||
|
connection.interface-name: fake_eth0
|
||||||
|
connection.autoconnect: yes
|
||||||
|
connection.master: fake_bond0
|
||||||
|
connection.slave-type: bond
|
||||||
|
802-3-ethernet.mtu: auto
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mocked_slave_type_bond_create(mocker):
|
||||||
|
mocker_set(mocker,
|
||||||
|
execute_return=None,
|
||||||
|
execute_side_effect=(
|
||||||
|
(0, TESTCASE_SLAVE_TYPE_BOND_CONNECTION_SHOW_OUTPUT, ""),
|
||||||
|
(0, "", ""),
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_SLAVE_TYPE_BOND_CONNECTION, indirect=['patch_ansible_module'])
|
||||||
|
def test_create_slave_type_bond(mocked_slave_type_bond_create, capfd):
|
||||||
|
"""
|
||||||
|
Test : slave for bond 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] == 'ethernet'
|
||||||
|
assert args[0][5] == 'con-name'
|
||||||
|
assert args[0][6] == 'fake_conn'
|
||||||
|
con_master_index = args[0].index('connection.master')
|
||||||
|
slave_type_index = args[0].index('connection.slave-type')
|
||||||
|
assert args[0][con_master_index + 1] == 'fake_bond0'
|
||||||
|
assert args[0][slave_type_index + 1] == 'bond'
|
||||||
|
|
||||||
|
out, err = capfd.readouterr()
|
||||||
|
results = json.loads(out)
|
||||||
|
assert not results.get('failed')
|
||||||
|
assert results['changed']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mocked_create_slave_type_bond_unchanged(mocker):
|
||||||
|
mocker_set(mocker,
|
||||||
|
connection_exists=True,
|
||||||
|
execute_return=(0, TESTCASE_SLAVE_TYPE_BOND_CONNECTION_UNCHANGED_SHOW_OUTPUT, ""))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_SLAVE_TYPE_BOND_CONNECTION, indirect=['patch_ansible_module'])
|
||||||
|
def test_slave_type_bond_unchanged(mocked_create_slave_type_bond_unchanged, capfd):
|
||||||
|
"""
|
||||||
|
Test : Existent slave for bridge unchanged
|
||||||
|
"""
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
|
nmcli.main()
|
||||||
|
|
||||||
|
out, err = capfd.readouterr()
|
||||||
|
results = json.loads(out)
|
||||||
|
assert not results.get('failed')
|
||||||
|
assert not results['changed']
|
||||||
|
|
||||||
|
|
||||||
|
TESTCASE_SLAVE_TYPE_TEAM_CONNECTION = [
|
||||||
|
{
|
||||||
|
'type': 'ethernet',
|
||||||
|
'conn_name': 'fake_conn',
|
||||||
|
'ifname': 'fake_eth0',
|
||||||
|
'state': 'present',
|
||||||
|
'slave_type': 'team',
|
||||||
|
'master': 'fake_team0',
|
||||||
|
'_ansible_check_mode': False,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
TESTCASE_SLAVE_TYPE_TEAM_CONNECTION_SHOW_OUTPUT = """\
|
||||||
|
connection.id: fake_conn
|
||||||
|
connection.type: 802-3-ethernet
|
||||||
|
connection.interface-name: fake_eth0
|
||||||
|
connection.autoconnect: yes
|
||||||
|
connection.master: --
|
||||||
|
connection.slave-type: --
|
||||||
|
802-3-ethernet.mtu: auto
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
TESTCASE_SLAVE_TYPE_TEAM_CONNECTION_UNCHANGED_SHOW_OUTPUT = """\
|
||||||
|
connection.id: fake_conn
|
||||||
|
connection.type: 802-3-ethernet
|
||||||
|
connection.interface-name: fake_eth0
|
||||||
|
connection.autoconnect: yes
|
||||||
|
connection.master: fake_team0
|
||||||
|
connection.slave-type: team
|
||||||
|
802-3-ethernet.mtu: auto
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mocked_slave_type_team_create(mocker):
|
||||||
|
mocker_set(mocker,
|
||||||
|
execute_return=None,
|
||||||
|
execute_side_effect=(
|
||||||
|
(0, TESTCASE_SLAVE_TYPE_TEAM_CONNECTION_SHOW_OUTPUT, ""),
|
||||||
|
(0, "", ""),
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_SLAVE_TYPE_TEAM_CONNECTION, indirect=['patch_ansible_module'])
|
||||||
|
def test_create_slave_type_team(mocked_slave_type_team_create, capfd):
|
||||||
|
"""
|
||||||
|
Test : slave for bond 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] == 'ethernet'
|
||||||
|
assert args[0][5] == 'con-name'
|
||||||
|
assert args[0][6] == 'fake_conn'
|
||||||
|
con_master_index = args[0].index('connection.master')
|
||||||
|
slave_type_index = args[0].index('connection.slave-type')
|
||||||
|
assert args[0][con_master_index + 1] == 'fake_team0'
|
||||||
|
assert args[0][slave_type_index + 1] == 'team'
|
||||||
|
|
||||||
|
out, err = capfd.readouterr()
|
||||||
|
results = json.loads(out)
|
||||||
|
assert not results.get('failed')
|
||||||
|
assert results['changed']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mocked_create_slave_type_team_unchanged(mocker):
|
||||||
|
mocker_set(mocker,
|
||||||
|
connection_exists=True,
|
||||||
|
execute_return=(0, TESTCASE_SLAVE_TYPE_TEAM_CONNECTION_UNCHANGED_SHOW_OUTPUT, ""))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_SLAVE_TYPE_TEAM_CONNECTION, indirect=['patch_ansible_module'])
|
||||||
|
def test_slave_type_team_unchanged(mocked_create_slave_type_team_unchanged, capfd):
|
||||||
|
"""
|
||||||
|
Test : Existent slave for bridge unchanged
|
||||||
|
"""
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
|
nmcli.main()
|
||||||
|
|
||||||
|
out, err = capfd.readouterr()
|
||||||
|
results = json.loads(out)
|
||||||
|
assert not results.get('failed')
|
||||||
|
assert not results['changed']
|
||||||
|
|
Loading…
Reference in a new issue