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:
José Roberto Emerich Junior 2022-06-06 16:16:27 -03:00 committed by GitHub
parent 8ba3d94740
commit e5e485390d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 304 additions and 4 deletions

View file

@ -45,8 +45,8 @@ options:
- The interface to bind the connection to.
- The connection will only be applicable to this interface name.
- 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.
- This parameter defaults to C(conn_name) when left unset.
- 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 for all connection types except vpn that removes it.
type: str
type:
description:
@ -55,10 +55,11 @@ options:
- Type C(generic) is added in Ansible 2.5.
- Type C(infiniband) is added in community.general 2.0.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
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:
description:
- 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.
type: int
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'''
@ -1288,6 +1341,23 @@ EXAMPLES = r'''
autoconnect: true
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"""#
@ -1404,6 +1474,7 @@ class Nmcli(object):
self.wifi_sec = module.params['wifi_sec']
self.gsm = module.params['gsm']
self.wireguard = module.params['wireguard']
self.vpn = module.params['vpn']
if self.method4:
self.ipv4_method = self.method4
@ -1592,6 +1663,29 @@ class Nmcli(object):
options.update({
'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.
for setting, value in options.items():
setting_type = self.settings_type(setting)
@ -1832,6 +1926,10 @@ class Nmcli(object):
'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())
# Constructing the command.
@ -1997,6 +2095,9 @@ class Nmcli(object):
current_value = current_value.strip('"')
if key == self.mtu_setting and self.mtu is None:
self.mtu = 0
if key == 'vpn.data':
current_value = list(map(str.strip, current_value.split(',')))
value = list(map(str.strip, value.split(',')))
else:
# parameter does not exist
current_value = None
@ -2025,6 +2126,10 @@ class Nmcli(object):
'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:
current_con_type = self.show_connection().get('connection.type')
if current_con_type:
@ -2064,6 +2169,7 @@ def main():
'wifi',
'gsm',
'wireguard',
'vpn',
]),
ip4=dict(type='list', elements='str'),
gw4=dict(type='str'),
@ -2163,6 +2269,7 @@ def main():
wifi_sec=dict(type='dict', no_log=True),
gsm=dict(type='dict'),
wireguard=dict(type='dict'),
vpn=dict(type='dict'),
),
mutually_exclusive=[['never_default4', 'gw4'],
['routes4_extended', 'routes4'],