mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
add support to create L2TP and PPTP VPN connection (#4746)
* add support to create L2TP and PPTP VPN connection * Update plugins/modules/net_tools/nmcli.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/net_tools/nmcli.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/net_tools/nmcli.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/net_tools/nmcli.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/net_tools/nmcli.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/net_tools/nmcli.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/net_tools/nmcli.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/net_tools/nmcli.py Co-authored-by: Felix Fontein <felix@fontein.de> * apply changes pointed on tests and review - add changelog fragment - change example code to use jinja2 in place of shell command * removes trailing whitespace * Update plugins/modules/net_tools/nmcli.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/net_tools/nmcli.py Co-authored-by: Felix Fontein <felix@fontein.de> * removes linux command from examples * remove unnecessary brakets Co-authored-by: Felix Fontein <felix@fontein.de> * remove unnecessary brakets Co-authored-by: Felix Fontein <felix@fontein.de> * simplify psk encoding on example Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/net_tools/nmcli.py Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/net_tools/nmcli.py Co-authored-by: Felix Fontein <felix@fontein.de> * add unit tests - test unchenged l2tp and pptp vpn connections - test create l2tp and pptp vpn connections - fix is_connection_changed to remove default ifname attribuition * improve tests on vpn.data param - fix _compare_conn_params to handle vpn.data as lists * removes block and set_fact from example Co-authored-by: Felix Fontein <felix@fontein.de> * makes line shortter to better reading Co-authored-by: Felix Fontein <felix@fontein.de> * Update plugins/modules/net_tools/nmcli.py Co-authored-by: Felix Fontein <felix@fontein.de> Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
8ba3d94740
commit
e5e485390d
3 changed files with 304 additions and 4 deletions
2
changelogs/fragments/4746-add-vpn-support-nmcli.yaml
Normal file
2
changelogs/fragments/4746-add-vpn-support-nmcli.yaml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- nmcli - adds ``vpn`` type and parameter for supporting VPN with service type L2TP and PPTP (https://github.com/ansible-collections/community.general/pull/4746).
|
|
@ -45,8 +45,8 @@ options:
|
||||||
- The interface to bind the connection to.
|
- The interface to bind the connection to.
|
||||||
- The connection will only be applicable to this interface name.
|
- The connection will only be applicable to this interface name.
|
||||||
- A special value of C('*') can be used for interface-independent connections.
|
- A special value of C('*') can be used for interface-independent connections.
|
||||||
- The ifname argument is mandatory for all connection types except bond, team, bridge and vlan.
|
- The ifname argument is mandatory for all connection types except bond, team, bridge, vlan and vpn.
|
||||||
- This parameter defaults to C(conn_name) when left unset.
|
- This parameter defaults to C(conn_name) when left unset for all connection types except vpn that removes it.
|
||||||
type: str
|
type: str
|
||||||
type:
|
type:
|
||||||
description:
|
description:
|
||||||
|
@ -55,10 +55,11 @@ options:
|
||||||
- Type C(generic) is added in Ansible 2.5.
|
- Type C(generic) is added in Ansible 2.5.
|
||||||
- Type C(infiniband) is added in community.general 2.0.0.
|
- Type C(infiniband) is added in community.general 2.0.0.
|
||||||
- Type C(gsm) is added in community.general 3.7.0.
|
- Type C(gsm) is added in community.general 3.7.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: str
|
type: str
|
||||||
choices: [ bond, bond-slave, bridge, bridge-slave, dummy, ethernet, generic, gre, infiniband, ipip, sit, team, team-slave, vlan, vxlan, wifi, gsm,
|
choices: [ bond, bond-slave, bridge, bridge-slave, dummy, ethernet, generic, gre, infiniband, ipip, sit, team, team-slave, vlan, vxlan, wifi, gsm,
|
||||||
wireguard ]
|
wireguard, vpn ]
|
||||||
mode:
|
mode:
|
||||||
description:
|
description:
|
||||||
- This is the type of device or network connection that you wish to create for a bond or bridge.
|
- This is the type of device or network connection that you wish to create for a bond or bridge.
|
||||||
|
@ -905,6 +906,58 @@ options:
|
||||||
description: C(NMSettingSecretFlags) indicating how to handle the I(wireguard.private-key) property.
|
description: C(NMSettingSecretFlags) indicating how to handle the I(wireguard.private-key) property.
|
||||||
type: int
|
type: int
|
||||||
choices: [ 0, 1, 2 ]
|
choices: [ 0, 1, 2 ]
|
||||||
|
vpn:
|
||||||
|
description:
|
||||||
|
- Configuration of a VPN connection (PPTP and L2TP).
|
||||||
|
- In order to use L2TP you need to be sure that C(network-manager-l2tp) - and C(network-manager-l2tp-gnome)
|
||||||
|
if host has UI - are installed on the host.
|
||||||
|
type: dict
|
||||||
|
version_added: 5.1.0
|
||||||
|
suboptions:
|
||||||
|
permissions:
|
||||||
|
description: User that will have permission to use the connection.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
service-type:
|
||||||
|
description: This defines the service type of connection.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
choices: [ pptp, l2tp ]
|
||||||
|
gateway:
|
||||||
|
description: The gateway to connection. It can be an IP address (for example C(192.0.2.1))
|
||||||
|
or a FQDN address (for example C(vpn.example.com)).
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
password-flags:
|
||||||
|
description:
|
||||||
|
- NMSettingSecretFlags indicating how to handle the I(password) property.
|
||||||
|
- 'Following choices are allowed:
|
||||||
|
C(0) B(NONE): The system is responsible for providing and storing this secret (default);
|
||||||
|
C(1) B(AGENT_OWNED): A user secret agent is responsible for providing and storing this secret; when it is required agents will be
|
||||||
|
asked to retrieve it;
|
||||||
|
C(2) B(NOT_SAVED): This secret should not be saved, but should be requested from the user each time it is needed;
|
||||||
|
C(4) B(NOT_REQUIRED): In situations where it cannot be automatically determined that the secret is required
|
||||||
|
(some VPNs and PPP providers do not require all secrets) this flag indicates that the specific secret is not required.'
|
||||||
|
type: int
|
||||||
|
choices: [ 0, 1, 2 , 4 ]
|
||||||
|
default: 0
|
||||||
|
user:
|
||||||
|
description: Username provided by VPN administrator.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
ipsec-enabled:
|
||||||
|
description:
|
||||||
|
- Enable or disable IPSec tunnel to L2TP host.
|
||||||
|
- This option is need when C(service-type) is C(l2tp).
|
||||||
|
type: bool
|
||||||
|
choices: [ yes, no ]
|
||||||
|
ipsec-psk:
|
||||||
|
description:
|
||||||
|
- The pre-shared key in base64 encoding.
|
||||||
|
- >
|
||||||
|
You can encode using this Ansible jinja2 expression: C("0s{{ '[YOUR PRE-SHARED KEY]' | ansible.builtin.b64encode }}").
|
||||||
|
- This is only used when I(ipsec-enabled=true).
|
||||||
|
type: str
|
||||||
'''
|
'''
|
||||||
|
|
||||||
EXAMPLES = r'''
|
EXAMPLES = r'''
|
||||||
|
@ -1288,6 +1341,23 @@ EXAMPLES = r'''
|
||||||
autoconnect: true
|
autoconnect: true
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
|
- name: >-
|
||||||
|
Create a VPN L2TP connection for ansible_user to connect on vpn.example.com
|
||||||
|
authenticating with user 'brittany' and pre-shared key as 'Brittany123'
|
||||||
|
community.general.nmcli:
|
||||||
|
type: vpn
|
||||||
|
conn_name: my-vpn-connection
|
||||||
|
vpn:
|
||||||
|
permissions: "{{ ansible_user }}"
|
||||||
|
service-type: l2tp
|
||||||
|
gateway: vpn.example.com
|
||||||
|
password-flags: 2
|
||||||
|
user: brittany
|
||||||
|
ipsec-enabled: true
|
||||||
|
ipsec-psk: "0s{{ 'Brittany123' | ansible.builtin.b64encode }}"
|
||||||
|
autoconnect: false
|
||||||
|
state: present
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
RETURN = r"""#
|
RETURN = r"""#
|
||||||
|
@ -1404,6 +1474,7 @@ class Nmcli(object):
|
||||||
self.wifi_sec = module.params['wifi_sec']
|
self.wifi_sec = module.params['wifi_sec']
|
||||||
self.gsm = module.params['gsm']
|
self.gsm = module.params['gsm']
|
||||||
self.wireguard = module.params['wireguard']
|
self.wireguard = module.params['wireguard']
|
||||||
|
self.vpn = module.params['vpn']
|
||||||
|
|
||||||
if self.method4:
|
if self.method4:
|
||||||
self.ipv4_method = self.method4
|
self.ipv4_method = self.method4
|
||||||
|
@ -1592,6 +1663,29 @@ class Nmcli(object):
|
||||||
options.update({
|
options.update({
|
||||||
'wireguard.%s' % name: value,
|
'wireguard.%s' % name: value,
|
||||||
})
|
})
|
||||||
|
elif self.type == 'vpn':
|
||||||
|
if self.vpn:
|
||||||
|
vpn_data_values = ''
|
||||||
|
for name, value in self.vpn.items():
|
||||||
|
if name == 'service-type':
|
||||||
|
options.update({
|
||||||
|
'vpn-type': value,
|
||||||
|
})
|
||||||
|
elif name == 'permissions':
|
||||||
|
options.update({
|
||||||
|
'connection.permissions': value,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
if vpn_data_values != '':
|
||||||
|
vpn_data_values += ', '
|
||||||
|
|
||||||
|
if isinstance(value, bool):
|
||||||
|
value = self.bool_to_string(value)
|
||||||
|
|
||||||
|
vpn_data_values += '%s=%s' % (name, value)
|
||||||
|
options.update({
|
||||||
|
'vpn.data': vpn_data_values,
|
||||||
|
})
|
||||||
# Convert settings values based on the situation.
|
# Convert settings values based on the situation.
|
||||||
for setting, value in options.items():
|
for setting, value in options.items():
|
||||||
setting_type = self.settings_type(setting)
|
setting_type = self.settings_type(setting)
|
||||||
|
@ -1832,6 +1926,10 @@ class Nmcli(object):
|
||||||
'connection.interface-name': ifname,
|
'connection.interface-name': ifname,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# VPN doesn't need an interface but if sended it must be a valid interface.
|
||||||
|
if self.type == 'vpn' and self.ifname is None:
|
||||||
|
del options['connection.interface-name']
|
||||||
|
|
||||||
options.update(self.connection_options())
|
options.update(self.connection_options())
|
||||||
|
|
||||||
# Constructing the command.
|
# Constructing the command.
|
||||||
|
@ -1997,6 +2095,9 @@ class Nmcli(object):
|
||||||
current_value = current_value.strip('"')
|
current_value = current_value.strip('"')
|
||||||
if key == self.mtu_setting and self.mtu is None:
|
if key == self.mtu_setting and self.mtu is None:
|
||||||
self.mtu = 0
|
self.mtu = 0
|
||||||
|
if key == 'vpn.data':
|
||||||
|
current_value = list(map(str.strip, current_value.split(',')))
|
||||||
|
value = list(map(str.strip, value.split(',')))
|
||||||
else:
|
else:
|
||||||
# parameter does not exist
|
# parameter does not exist
|
||||||
current_value = None
|
current_value = None
|
||||||
|
@ -2025,6 +2126,10 @@ class Nmcli(object):
|
||||||
'connection.interface-name': self.ifname,
|
'connection.interface-name': self.ifname,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# VPN doesn't need an interface but if sended it must be a valid interface.
|
||||||
|
if self.type == 'vpn' and self.ifname is None:
|
||||||
|
del options['connection.interface-name']
|
||||||
|
|
||||||
if not self.type:
|
if not self.type:
|
||||||
current_con_type = self.show_connection().get('connection.type')
|
current_con_type = self.show_connection().get('connection.type')
|
||||||
if current_con_type:
|
if current_con_type:
|
||||||
|
@ -2064,6 +2169,7 @@ def main():
|
||||||
'wifi',
|
'wifi',
|
||||||
'gsm',
|
'gsm',
|
||||||
'wireguard',
|
'wireguard',
|
||||||
|
'vpn',
|
||||||
]),
|
]),
|
||||||
ip4=dict(type='list', elements='str'),
|
ip4=dict(type='list', elements='str'),
|
||||||
gw4=dict(type='str'),
|
gw4=dict(type='str'),
|
||||||
|
@ -2163,6 +2269,7 @@ def main():
|
||||||
wifi_sec=dict(type='dict', no_log=True),
|
wifi_sec=dict(type='dict', no_log=True),
|
||||||
gsm=dict(type='dict'),
|
gsm=dict(type='dict'),
|
||||||
wireguard=dict(type='dict'),
|
wireguard=dict(type='dict'),
|
||||||
|
vpn=dict(type='dict'),
|
||||||
),
|
),
|
||||||
mutually_exclusive=[['never_default4', 'gw4'],
|
mutually_exclusive=[['never_default4', 'gw4'],
|
||||||
['routes4_extended', 'routes4'],
|
['routes4_extended', 'routes4'],
|
||||||
|
|
|
@ -98,6 +98,12 @@ TESTCASE_CONNECTION = [
|
||||||
'state': 'absent',
|
'state': 'absent',
|
||||||
'_ansible_check_mode': True,
|
'_ansible_check_mode': True,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'type': 'vpn',
|
||||||
|
'conn_name': 'non_existent_nw_device',
|
||||||
|
'state': 'absent',
|
||||||
|
'_ansible_check_mode': True,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
TESTCASE_GENERIC = [
|
TESTCASE_GENERIC = [
|
||||||
|
@ -1177,6 +1183,69 @@ wireguard.ip4-auto-default-route: -1 (default)
|
||||||
wireguard.ip6-auto-default-route: -1 (default)
|
wireguard.ip6-auto-default-route: -1 (default)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
TESTCASE_VPN_L2TP = [
|
||||||
|
{
|
||||||
|
'type': 'vpn',
|
||||||
|
'conn_name': 'vpn_l2tp',
|
||||||
|
'vpn': {
|
||||||
|
'permissions': 'brittany',
|
||||||
|
'service-type': 'l2tp',
|
||||||
|
'gateway': 'vpn.example.com',
|
||||||
|
'password-flags': '2',
|
||||||
|
'user': 'brittany',
|
||||||
|
'ipsec-enabled': 'true',
|
||||||
|
'ipsec-psk': 'QnJpdHRhbnkxMjM=',
|
||||||
|
},
|
||||||
|
'autoconnect': 'false',
|
||||||
|
'state': 'present',
|
||||||
|
'_ansible_check_mode': False,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
TESTCASE_VPN_L2TP_SHOW_OUTPUT = """\
|
||||||
|
connection.id: vpn_l2tp
|
||||||
|
connection.type: vpn
|
||||||
|
connection.autoconnect: no
|
||||||
|
connection.permissions: brittany
|
||||||
|
ipv4.method: auto
|
||||||
|
ipv6.method: auto
|
||||||
|
vpn-type: l2tp
|
||||||
|
vpn.service-type: org.freedesktop.NetworkManager.l2tp
|
||||||
|
vpn.data: gateway=vpn.example.com, password-flags=2, user=brittany, ipsec-enabled=true, ipsec-psk=QnJpdHRhbnkxMjM=
|
||||||
|
vpn.secrets: ipsec-psk = QnJpdHRhbnkxMjM=
|
||||||
|
vpn.persistent: no
|
||||||
|
vpn.timeout: 0
|
||||||
|
"""
|
||||||
|
|
||||||
|
TESTCASE_VPN_PPTP = [
|
||||||
|
{
|
||||||
|
'type': 'vpn',
|
||||||
|
'conn_name': 'vpn_pptp',
|
||||||
|
'vpn': {
|
||||||
|
'permissions': 'brittany',
|
||||||
|
'service-type': 'pptp',
|
||||||
|
'gateway': 'vpn.example.com',
|
||||||
|
'password-flags': '2',
|
||||||
|
'user': 'brittany',
|
||||||
|
},
|
||||||
|
'autoconnect': 'false',
|
||||||
|
'state': 'present',
|
||||||
|
'_ansible_check_mode': False,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
TESTCASE_VPN_PPTP_SHOW_OUTPUT = """\
|
||||||
|
connection.id: vpn_pptp
|
||||||
|
connection.type: vpn
|
||||||
|
connection.autoconnect: no
|
||||||
|
connection.permissions: brittany
|
||||||
|
ipv4.method: auto
|
||||||
|
ipv6.method: auto
|
||||||
|
vpn-type: pptp
|
||||||
|
vpn.service-type: org.freedesktop.NetworkManager.pptp
|
||||||
|
vpn.data: password-flags=2, gateway=vpn.example.com, user=brittany
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def mocker_set(mocker,
|
def mocker_set(mocker,
|
||||||
connection_exists=False,
|
connection_exists=False,
|
||||||
|
@ -1547,6 +1616,20 @@ def mocked_wireguard_connection_unchanged(mocker):
|
||||||
execute_return=(0, TESTCASE_WIREGUARD_SHOW_OUTPUT, ""))
|
execute_return=(0, TESTCASE_WIREGUARD_SHOW_OUTPUT, ""))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mocked_vpn_l2tp_connection_unchanged(mocker):
|
||||||
|
mocker_set(mocker,
|
||||||
|
connection_exists=True,
|
||||||
|
execute_return=(0, TESTCASE_VPN_L2TP_SHOW_OUTPUT, ""))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mocked_vpn_pptp_connection_unchanged(mocker):
|
||||||
|
mocker_set(mocker,
|
||||||
|
connection_exists=True,
|
||||||
|
execute_return=(0, TESTCASE_VPN_PPTP_SHOW_OUTPUT, ""))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_BOND, indirect=['patch_ansible_module'])
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_BOND, indirect=['patch_ansible_module'])
|
||||||
def test_bond_connection_create(mocked_generic_connection_create, capfd):
|
def test_bond_connection_create(mocked_generic_connection_create, capfd):
|
||||||
"""
|
"""
|
||||||
|
@ -3456,3 +3539,111 @@ def test_wireguard_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']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_VPN_L2TP, indirect=['patch_ansible_module'])
|
||||||
|
def test_vpn_l2tp_connection_unchanged(mocked_vpn_l2tp_connection_unchanged, capfd):
|
||||||
|
"""
|
||||||
|
Test : L2TP VPN 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_VPN_PPTP, indirect=['patch_ansible_module'])
|
||||||
|
def test_vpn_pptp_connection_unchanged(mocked_vpn_pptp_connection_unchanged, capfd):
|
||||||
|
"""
|
||||||
|
Test : PPTP VPN 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_VPN_L2TP, indirect=['patch_ansible_module'])
|
||||||
|
def test_create_vpn_l2tp(mocked_generic_connection_create, capfd):
|
||||||
|
"""
|
||||||
|
Test : Create L2TP VPN connection
|
||||||
|
"""
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
|
nmcli.main()
|
||||||
|
|
||||||
|
assert nmcli.Nmcli.execute_command.call_count == 1
|
||||||
|
arg_list = nmcli.Nmcli.execute_command.call_args_list
|
||||||
|
add_args, add_kw = arg_list[0]
|
||||||
|
|
||||||
|
assert add_args[0][0] == '/usr/bin/nmcli'
|
||||||
|
assert add_args[0][1] == 'con'
|
||||||
|
assert add_args[0][2] == 'add'
|
||||||
|
assert add_args[0][3] == 'type'
|
||||||
|
assert add_args[0][4] == 'vpn'
|
||||||
|
assert add_args[0][5] == 'con-name'
|
||||||
|
assert add_args[0][6] == 'vpn_l2tp'
|
||||||
|
|
||||||
|
add_args_text = list(map(to_text, add_args[0]))
|
||||||
|
|
||||||
|
for param in ['connection.autoconnect', 'no',
|
||||||
|
'connection.permissions', 'brittany',
|
||||||
|
'vpn.data', 'vpn-type', 'l2tp',
|
||||||
|
]:
|
||||||
|
assert param in add_args_text
|
||||||
|
|
||||||
|
vpn_data_index = add_args_text.index('vpn.data') + 1
|
||||||
|
args_vpn_data = add_args_text[vpn_data_index]
|
||||||
|
for vpn_data in ['gateway=vpn.example.com', 'password-flags=2', 'user=brittany', 'ipsec-enabled=true', 'ipsec-psk=QnJpdHRhbnkxMjM=']:
|
||||||
|
assert vpn_data in args_vpn_data
|
||||||
|
|
||||||
|
out, err = capfd.readouterr()
|
||||||
|
results = json.loads(out)
|
||||||
|
assert not results.get('failed')
|
||||||
|
assert results['changed']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_VPN_PPTP, indirect=['patch_ansible_module'])
|
||||||
|
def test_create_vpn_pptp(mocked_generic_connection_create, capfd):
|
||||||
|
"""
|
||||||
|
Test : Create PPTP VPN connection
|
||||||
|
"""
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
|
nmcli.main()
|
||||||
|
|
||||||
|
assert nmcli.Nmcli.execute_command.call_count == 1
|
||||||
|
arg_list = nmcli.Nmcli.execute_command.call_args_list
|
||||||
|
add_args, add_kw = arg_list[0]
|
||||||
|
|
||||||
|
assert add_args[0][0] == '/usr/bin/nmcli'
|
||||||
|
assert add_args[0][1] == 'con'
|
||||||
|
assert add_args[0][2] == 'add'
|
||||||
|
assert add_args[0][3] == 'type'
|
||||||
|
assert add_args[0][4] == 'vpn'
|
||||||
|
assert add_args[0][5] == 'con-name'
|
||||||
|
assert add_args[0][6] == 'vpn_pptp'
|
||||||
|
|
||||||
|
add_args_text = list(map(to_text, add_args[0]))
|
||||||
|
|
||||||
|
for param in ['connection.autoconnect', 'no',
|
||||||
|
'connection.permissions', 'brittany',
|
||||||
|
'vpn.data', 'vpn-type', 'pptp',
|
||||||
|
]:
|
||||||
|
assert param in add_args_text
|
||||||
|
|
||||||
|
vpn_data_index = add_args_text.index('vpn.data') + 1
|
||||||
|
args_vpn_data = add_args_text[vpn_data_index]
|
||||||
|
for vpn_data in ['password-flags=2', 'gateway=vpn.example.com', 'user=brittany']:
|
||||||
|
assert vpn_data in args_vpn_data
|
||||||
|
|
||||||
|
out, err = capfd.readouterr()
|
||||||
|
results = json.loads(out)
|
||||||
|
assert not results.get('failed')
|
||||||
|
assert results['changed']
|
||||||
|
|
Loading…
Reference in a new issue