nmcli: Introduce IPIP Tunnel (#45933)

This work enables to add ipip tunnel via nmcli module

```
  - nmcli:
       state: present
       type: ipip
       conn_name: ipip_test1
       autoconnect: yes
       ip_tunnel_dev: enp0s8
       ip_tunnel_local: 192.168.1.2
       ip_tunnel_remote: 192.168.1.5
```

version2: Added tests
Signed-off-by: Susant Sahani <susant@redhat.com>

Rebase
This commit is contained in:
Susant Sahani 2018-11-17 10:27:11 +05:30 committed by ansibot
parent a4921cd5d9
commit 88dcb11695
2 changed files with 154 additions and 2 deletions

View file

@ -53,7 +53,7 @@ options:
description:
- This is the type of device or network connection that you wish to create or modify.
- "type C(generic) is added in version 2.5."
choices: [ ethernet, team, team-slave, bond, bond-slave, bridge, bridge-slave, vlan, vxlan, generic ]
choices: [ ethernet, team, team-slave, bond, bond-slave, bridge, bridge-slave, vlan, vxlan, ipip, generic ]
mode:
description:
- This is the type of device or network connection that you wish to create for a bond, team or bridge.
@ -186,6 +186,18 @@ options:
description:
- This is only used with VXLAN - VXLAN local IP address.
version_added: "2.8"
ip_tunnel_dev:
description:
- This is only used with IPIP - parent device this IPIP tunnel, can use ifname.
version_added: "2.8"
ip_tunnel_remote:
description:
- This is only used with IPIP - IPIP destination IP address.
version_added: "2.8"
ip_tunnel_local:
description:
- This is only used with IPIP - IPIP local IP address.
version_added: "2.8"
'''
EXAMPLES = '''
@ -453,6 +465,14 @@ EXAMPLES = '''
vxlan_local: 192.168.1.2
vxlan_remote: 192.168.1.5
# To add ipip, issue a command as follows:
- nmcli:
type: ipip
conn_name: ipip_test1
ip_tunnel_dev: eth0
ip_tunnel_local: 192.168.1.2
ip_tunnel_remote: 192.168.1.5
# nmcli exits with status 0 if it succeeds and exits with a status greater
# than zero when there is a failure. The following list of status codes may be
# returned:
@ -526,6 +546,7 @@ class Nmcli(object):
14: "Generic",
15: "Team",
16: "VxLan",
17: "ipip",
}
STATES = {
0: "Unknown",
@ -585,6 +606,9 @@ class Nmcli(object):
self.vxlan_id = module.params['vxlan_id']
self.vxlan_local = module.params['vxlan_local']
self.vxlan_remote = module.params['vxlan_remote']
self.ip_tunnel_dev = module.params['ip_tunnel_dev']
self.ip_tunnel_local = module.params['ip_tunnel_local']
self.ip_tunnel_remote = module.params['ip_tunnel_remote']
self.nmcli_bin = self.module.get_bin_path('nmcli', True)
self.dhcp_client_id = module.params['dhcp_client_id']
@ -1142,6 +1166,55 @@ class Nmcli(object):
cmd.extend([k, v])
return cmd
def create_connection_ipip(self):
cmd = [self.nmcli_bin, 'con', 'add', 'type', 'ip-tunnel', 'mode', 'ipip', 'con-name']
if self.conn_name is not None:
cmd.append(self.conn_name)
elif self.ifname is not None:
cmd.append(self.ifname)
elif self.ip_tunnel_dev is not None:
cmd.append('ipip%s' % self.ip_tunnel_dev)
cmd.append('ifname')
if self.ifname is not None:
cmd.append(self.ifname)
elif self.conn_name is not None:
cmd.append(self.conn_name)
else:
cmd.append('ipip%s' % self.ipip_dev)
if self.ip_tunnel_dev is not None:
cmd.append('dev')
cmd.append(self.ip_tunnel_dev)
params = {'ip-tunnel.local': self.ip_tunnel_local,
'ip-tunnel.remote': self.ip_tunnel_remote,
'autoconnect': self.bool_to_string(self.autoconnect)
}
for k, v in params.items():
cmd.extend([k, v])
return cmd
def modify_connection_ipip(self):
cmd = [self.nmcli_bin, 'con', 'mod']
if self.conn_name is not None:
cmd.append(self.conn_name)
elif self.ifname is not None:
cmd.append(self.ifname)
elif self.ip_tunnel_dev is not None:
cmd.append('ipip%s' % self.ip_tunnel_dev)
params = {'ip-tunnel.local': self.ip_tunnel_local,
'ip-tunnel.remote': self.ip_tunnel_remote,
'autoconnect': self.bool_to_string(self.autoconnect)
}
for k, v in params.items():
cmd.extend([k, v])
return cmd
def create_connection(self):
cmd = []
if self.type == 'team':
@ -1189,6 +1262,8 @@ class Nmcli(object):
cmd = self.create_connection_vlan()
elif self.type == 'vxlan':
cmd = self.create_connection_vxlan()
elif self.type == 'ipip':
cmd = self.create_connection_ipip()
elif self.type == 'generic':
cmd = self.create_connection_ethernet(conn_type='generic')
@ -1223,6 +1298,8 @@ class Nmcli(object):
cmd = self.modify_connection_vlan()
elif self.type == 'vxlan':
cmd = self.modify_connection_vxlan()
elif self.type == 'ipip':
cmd = self.modify_connection_ipip()
elif self.type == 'generic':
cmd = self.modify_connection_ethernet(conn_type='generic')
if cmd:
@ -1244,7 +1321,7 @@ def main():
type=dict(required=False, default=None,
choices=['ethernet', 'team', 'team-slave', 'bond',
'bond-slave', 'bridge', 'bridge-slave',
'vlan', 'vxlan', 'generic'],
'vlan', 'vxlan', 'ipip', 'generic'],
type='str'),
ip4=dict(required=False, default=None, type='str'),
gw4=dict(required=False, default=None, type='str'),
@ -1287,6 +1364,10 @@ def main():
vxlan_id=dict(required=False, default=None, type='str'),
vxlan_local=dict(required=False, default=None, type='str'),
vxlan_remote=dict(required=False, default=None, type='str'),
# ip-tunnel specific vars
ip_tunnel_dev=dict(required=False, default=None, type='str'),
ip_tunnel_local=dict(required=False, default=None, type='str'),
ip_tunnel_remote=dict(required=False, default=None, type='str'),
),
supports_check_mode=True
)

View file

@ -58,6 +58,13 @@ TESTCASE_CONNECTION = [
'state': 'absent',
'_ansible_check_mode': True,
},
{
'type': 'ipip',
'conn_name': 'non_existent_nw_device',
'state': 'absent',
'_ansible_check_mode': True,
},
]
TESTCASE_GENERIC = [
@ -150,6 +157,19 @@ TESTCASE_VXLAN = [
}
]
TESTCASE_IPIP = [
{
'type': 'ipip',
'conn_name': 'non_existent_nw_device',
'ifname': 'ipip-existent_nw_device',
'ip_tunnel_dev': 'non_existent_ipip_device',
'ip_tunnel_local': '192.168.225.5',
'ip_tunnel_remote': '192.168.225.6',
'state': 'present',
'_ansible_check_mode': False,
}
]
TESTCASE_ETHERNET_DHCP = [
{
'type': 'ethernet',
@ -500,6 +520,57 @@ def test_vxlan_mod(mocked_generic_connection_modify):
assert param in args[0]
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_IPIP, indirect=['patch_ansible_module'])
def test_create_ipip(mocked_generic_connection_create):
"""
Test if ipip 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] == 'ip-tunnel'
assert args[0][5] == 'mode'
assert args[0][6] == 'ipip'
assert args[0][7] == 'con-name'
assert args[0][8] == 'non_existent_nw_device'
assert args[0][9] == 'ifname'
assert args[0][10] == 'ipip-existent_nw_device'
assert args[0][11] == 'dev'
assert args[0][12] == 'non_existent_ipip_device'
for param in ['ip-tunnel.local', '192.168.225.5', 'ip-tunnel.remote', '192.168.225.6']:
assert param in args[0]
@pytest.mark.parametrize('patch_ansible_module', TESTCASE_IPIP, indirect=['patch_ansible_module'])
def test_ipip_mod(mocked_generic_connection_modify):
"""
Test if ipip 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 ['ip-tunnel.local', '192.168.225.5', 'ip-tunnel.remote', '192.168.225.6']:
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):
"""