From 3d06ce245a5bd433e63b309d0adbcec3750acbb4 Mon Sep 17 00:00:00 2001 From: Trishna Guha Date: Tue, 20 Feb 2018 20:54:27 +0530 Subject: [PATCH] fix vyos_l3_interface adding multiple addresses to interface (#36377) * fix vyos_l3_interface adding multiple addresses to interface Signed-off-by: Trishna Guha * add test Signed-off-by: Trishna Guha --- .../modules/network/vyos/vyos_l3_interface.py | 73 +++++++++++++------ .../vyos_l3_interface/tests/cli/basic.yaml | 6 ++ 2 files changed, 57 insertions(+), 22 deletions(-) diff --git a/lib/ansible/modules/network/vyos/vyos_l3_interface.py b/lib/ansible/modules/network/vyos/vyos_l3_interface.py index 684668ffdab..85c401f9d67 100644 --- a/lib/ansible/modules/network/vyos/vyos_l3_interface.py +++ b/lib/ansible/modules/network/vyos/vyos_l3_interface.py @@ -88,14 +88,39 @@ commands: sample: - set interfaces ethernet eth0 address '192.168.0.1/24' """ + +import socket +import re + from copy import deepcopy from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.network.common.utils import is_masklen, validate_ip_address from ansible.module_utils.network.common.utils import remove_default_spec from ansible.module_utils.network.vyos.vyos import load_config, run_commands from ansible.module_utils.network.vyos.vyos import vyos_argument_spec +def is_ipv4(value): + if value: + address = value.split('/') + if is_masklen(address[1]) and validate_ip_address(address[0]): + return True + return False + + +def is_ipv6(value): + if value: + address = value.split('/') + if 0 <= int(address[1]) <= 128: + try: + socket.inet_pton(socket.AF_INET6, address[0]) + except socket.error: + return False + return True + return False + + def search_obj_in_list(name, lst): for o in lst: if o['name'] == name: @@ -115,6 +140,7 @@ def map_obj_to_commands(updates, module): state = w['state'] obj_in_have = search_obj_in_list(name, have) + if state == 'absent' and obj_in_have: if not ipv4 and not ipv6 and (obj_in_have['ipv4'] or obj_in_have['ipv6']): if name == "lo": @@ -122,24 +148,24 @@ def map_obj_to_commands(updates, module): else: commands.append('delete interfaces ethernet ' + name + ' address') else: - if ipv4 and obj_in_have['ipv4']: + if ipv4 and ipv4 in obj_in_have['ipv4']: if name == "lo": commands.append('delete interfaces loopback lo address ' + ipv4) else: commands.append('delete interfaces ethernet ' + name + ' address ' + ipv4) - if ipv6 and obj_in_have['ipv6']: + if ipv6 and ipv6 in obj_in_have['ipv6']: if name == "lo": commands.append('delete interfaces loopback lo address ' + ipv6) else: commands.append('delete interfaces ethernet ' + name + ' address ' + ipv6) elif (state == 'present' and obj_in_have): - if ipv4 and ipv4 != obj_in_have['ipv4']: + if ipv4 and ipv4 not in obj_in_have['ipv4']: if name == "lo": commands.append('set interfaces loopback lo address ' + ipv4) else: commands.append('set interfaces ethernet ' + name + ' address ' + ipv4) - if ipv6 and ipv6 != obj_in_have['ipv6']: + if ipv6 and ipv6 not in obj_in_have['ipv6']: if name == "lo": commands.append('set interfaces loopback lo address ' + ipv6) else: @@ -151,29 +177,32 @@ def map_obj_to_commands(updates, module): def map_config_to_obj(module): obj = [] output = run_commands(module, ['show interfaces']) - lines = output[0].splitlines() + lines = re.split(r'\n[e|l]', output[0])[1:] - if len(lines) > 3: - for line in lines[3:]: + if len(lines) > 0: + for line in lines: splitted_line = line.split() - if len(splitted_line) > 1: - name = splitted_line[0] - address = splitted_line[1] + if len(splitted_line) > 0: + ipv4 = [] + ipv6 = [] - if address == '-': - address = None + if splitted_line[0].lower().startswith('th'): + name = 'e' + splitted_line[0].lower() + elif splitted_line[0].lower().startswith('o'): + name = 'l' + splitted_line[0].lower() - if address is not None and ':' not in address: - obj.append({'name': name, - 'ipv4': address, - 'ipv6': None}) - else: - obj.append({'name': name, - 'ipv6': address, - 'ipv4': None}) - else: - obj[-1]['ipv6'] = splitted_line[0] + for i in splitted_line[1:]: + if (('.' in i or ':' in i) and '/' in i): + value = i.split(r'\n')[0] + if is_ipv4(value): + ipv4.append(value) + elif is_ipv6(value): + ipv6.append(value) + + obj.append({'name': name, + 'ipv4': ipv4, + 'ipv6': ipv6}) return obj diff --git a/test/integration/targets/vyos_l3_interface/tests/cli/basic.yaml b/test/integration/targets/vyos_l3_interface/tests/cli/basic.yaml index ac9e9d9c1b0..73feadc3228 100644 --- a/test/integration/targets/vyos_l3_interface/tests/cli/basic.yaml +++ b/test/integration/targets/vyos_l3_interface/tests/cli/basic.yaml @@ -149,6 +149,7 @@ aggregate: - { name: eth1, ipv4: 192.168.2.10/24 } - { name: eth2, ipv4: 192.168.3.10/24, ipv6: "fd5d:12c9:2201:1::1/64" } + - { name: eth2, ipv4: 192.168.4.10/24 } register: result - assert: @@ -157,12 +158,14 @@ - '"set interfaces ethernet eth1 address 192.168.2.10/24" in result.commands' - '"set interfaces ethernet eth2 address 192.168.3.10/24" in result.commands' - '"set interfaces ethernet eth2 address fd5d:12c9:2201:1::1/64" in result.commands' + - '"set interfaces ethernet eth2 address 192.168.4.10/24" in result.commands' - name: Set IP addresses on aggregate (idempotent) vyos_l3_interface: aggregate: - { name: eth1, ipv4: 192.168.2.10/24 } - { name: eth2, ipv4: 192.168.3.10/24, ipv6: "fd5d:12c9:2201:1::1/64" } + - { name: eth2, ipv4: 192.168.4.10/24 } register: result - assert: @@ -174,6 +177,7 @@ aggregate: - { name: eth1, ipv4: 192.168.2.10/24 } - { name: eth2, ipv4: 192.168.3.10/24, ipv6: "fd5d:12c9:2201:1::1/64" } + - { name: eth2, ipv4: 192.168.4.10/24 } state: absent register: result @@ -183,12 +187,14 @@ - '"delete interfaces ethernet eth1 address 192.168.2.10/24" in result.commands' - '"delete interfaces ethernet eth2 address 192.168.3.10/24" in result.commands' - '"delete interfaces ethernet eth2 address fd5d:12c9:2201:1::1/64" in result.commands' + - '"delete interfaces ethernet eth2 address 192.168.4.10/24" in result.commands' - name: Remove IP addresses on aggregate (idempotent) vyos_l3_interface: aggregate: - { name: eth1, ipv4: 192.168.2.10/24 } - { name: eth2, ipv4: 192.168.3.10/24, ipv6: "fd5d:12c9:2201:1::1/64" } + - { name: eth2, ipv4: 192.168.4.10/24 } state: absent register: result