From 59dcf3f27743ecbecfadc037515d0fa33ae3045a Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Thu, 13 Dec 2018 09:36:09 +0530 Subject: [PATCH] nmcli: Introduce SIT Tunnel (#45937) This work enables to add sit tunnel via nmcli module Signed-off-by: Susant Sahani susant@redhat.com SUMMARY ISSUE TYPE Feature Pull Request COMPONENT NAME nmcli ANSIBLE VERSION 2.8 ADDITIONAL INFORMATION - nmcli: state: present type: sit conn_name: sit_test1 autoconnect: yes ip_tunnel_dev: enp0s8 ip_tunnel_local: 192.168.1.2 ip_tunnel_remote: 192.168.1.5 --- lib/ansible/modules/net_tools/nmcli.py | 72 ++++++++++++++++++++-- test/units/modules/net_tools/test_nmcli.py | 71 ++++++++++++++++++++- 2 files changed, 137 insertions(+), 6 deletions(-) diff --git a/lib/ansible/modules/net_tools/nmcli.py b/lib/ansible/modules/net_tools/nmcli.py index 0a81d05e379..c91b3c9be80 100644 --- a/lib/ansible/modules/net_tools/nmcli.py +++ b/lib/ansible/modules/net_tools/nmcli.py @@ -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, ipip, generic ] + choices: [ ethernet, team, team-slave, bond, bond-slave, bridge, bridge-slave, vlan, vxlan, ipip, sit, generic ] mode: description: - This is the type of device or network connection that you wish to create for a bond, team or bridge. @@ -188,15 +188,15 @@ options: version_added: "2.8" ip_tunnel_dev: description: - - This is only used with IPIP - parent device this IPIP tunnel, can use ifname. + - This is used with IPIP/SIT - parent device this IPIP/SIT tunnel, can use ifname. version_added: "2.8" ip_tunnel_remote: description: - - This is only used with IPIP - IPIP destination IP address. + - This is used with IPIP/SIT - IPIP/SIT destination IP address. version_added: "2.8" ip_tunnel_local: description: - - This is only used with IPIP - IPIP local IP address. + - This is used with IPIP/SIT - IPIP/SIT local IP address. version_added: "2.8" ''' @@ -471,6 +471,14 @@ EXAMPLES = ''' ip_tunnel_local: 192.168.1.2 ip_tunnel_remote: 192.168.1.5 +# To add sit, issue a command as follows: + - nmcli: + type: sit + conn_name: sit_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: @@ -545,6 +553,7 @@ class Nmcli(object): 15: "Team", 16: "VxLan", 17: "ipip", + 18: "sit", } STATES = { 0: "Unknown", @@ -1213,6 +1222,55 @@ class Nmcli(object): cmd.extend([k, v]) return cmd + def create_connection_sit(self): + cmd = [self.nmcli_bin, 'con', 'add', 'type', 'ip-tunnel', 'mode', 'sit', '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('sit%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('sit%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_sit(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('sit%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': @@ -1262,6 +1320,8 @@ class Nmcli(object): cmd = self.create_connection_vxlan() elif self.type == 'ipip': cmd = self.create_connection_ipip() + elif self.type == 'sit': + cmd = self.create_connection_sit() elif self.type == 'generic': cmd = self.create_connection_ethernet(conn_type='generic') @@ -1298,6 +1358,8 @@ class Nmcli(object): cmd = self.modify_connection_vxlan() elif self.type == 'ipip': cmd = self.modify_connection_ipip() + elif self.type == 'sit': + cmd = self.modify_connection_sit() elif self.type == 'generic': cmd = self.modify_connection_ethernet(conn_type='generic') if cmd: @@ -1319,7 +1381,7 @@ def main(): type=dict(required=False, default=None, choices=['ethernet', 'team', 'team-slave', 'bond', 'bond-slave', 'bridge', 'bridge-slave', - 'vlan', 'vxlan', 'ipip', 'generic'], + 'vlan', 'vxlan', 'ipip', 'sit', 'generic'], type='str'), ip4=dict(required=False, default=None, type='str'), gw4=dict(required=False, default=None, type='str'), diff --git a/test/units/modules/net_tools/test_nmcli.py b/test/units/modules/net_tools/test_nmcli.py index 45ec7ae2dda..31b067aa558 100644 --- a/test/units/modules/net_tools/test_nmcli.py +++ b/test/units/modules/net_tools/test_nmcli.py @@ -64,7 +64,12 @@ TESTCASE_CONNECTION = [ 'state': 'absent', '_ansible_check_mode': True, }, - + { + 'type': 'sit', + 'conn_name': 'non_existent_nw_device', + 'state': 'absent', + '_ansible_check_mode': True, + }, ] TESTCASE_GENERIC = [ @@ -170,6 +175,19 @@ TESTCASE_IPIP = [ } ] +TESTCASE_SIT = [ + { + 'type': 'sit', + 'conn_name': 'non_existent_nw_device', + 'ifname': 'sit-existent_nw_device', + 'ip_tunnel_dev': 'non_existent_sit_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', @@ -571,6 +589,57 @@ def test_ipip_mod(mocked_generic_connection_modify): assert param in args[0] +@pytest.mark.parametrize('patch_ansible_module', TESTCASE_SIT, indirect=['patch_ansible_module']) +def test_create_sit(mocked_generic_connection_create): + """ + Test if sit 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] == 'sit' + assert args[0][7] == 'con-name' + assert args[0][8] == 'non_existent_nw_device' + assert args[0][9] == 'ifname' + assert args[0][10] == 'sit-existent_nw_device' + assert args[0][11] == 'dev' + assert args[0][12] == 'non_existent_sit_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_SIT, indirect=['patch_ansible_module']) +def test_sit_mod(mocked_generic_connection_modify): + """ + Test if sit 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): """