From 54021405af918f9b6ee2fc8c0d531903f579e930 Mon Sep 17 00:00:00 2001 From: selias Date: Thu, 18 May 2017 18:07:46 +0200 Subject: [PATCH] CSIT-610 HC Test: add test cases for unnumbered interface - add interface and sub-interface tests with unnumbered config - modify interface IPv4 address assignment to handle custom interfaces and sub-interfaces - pylint and style fixes Change-Id: Ic39df1655b4d44f0025a2acef9f7f968929aeff5 Signed-off-by: selias --- .../python/honeycomb/HcAPIKwInterfaces.py | 103 ++++++++++++++++++--- .../libraries/python/honeycomb/HoneycombSetup.py | 2 +- resources/libraries/python/honeycomb/Lisp.py | 4 +- .../python/honeycomb/{proxyARP.py => ProxyARP.py} | 0 .../libraries/robot/honeycomb/honeycomb.robot | 4 +- .../libraries/robot/honeycomb/interfaces.robot | 38 +++++++- resources/libraries/robot/honeycomb/proxyarp.robot | 4 +- tests/func/honeycomb/__init__.robot | 2 +- .../mgmt-cfg-int-subint-apihc-apivat-func.robot | 77 +++++++++++++++ .../mgmt-cfg-intip4-intip6-apihc-apivat-func.robot | 47 +++++++++- 10 files changed, 255 insertions(+), 26 deletions(-) rename resources/libraries/python/honeycomb/{proxyARP.py => ProxyARP.py} (100%) diff --git a/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py b/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py index e78696cd15..1e0b1a5d14 100644 --- a/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py +++ b/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py @@ -483,22 +483,32 @@ class InterfaceKeywords(object): :type network: str or int :returns: Content of response. :rtype: bytearray - :raises HoneycombError: If the provided netmask or prefix is not valid. + :raises ValueError: If the provided netmask or prefix is not valid. + :raises HoneycombError: If the operation fails. """ - interface = Topology.convert_interface_reference( - node, interface, "name") + interface = InterfaceKeywords.handle_interface_reference( + node, interface) - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4") + path = "/interface/{0}/ietf-ip:ipv4".format(interface) if isinstance(network, basestring): - address = {"address": [{"ip": ip_addr, "netmask": network}, ]} + data = { + "ietf-ip:ipv4": { + "address": [{"ip": ip_addr, "netmask": network}, ]}} elif isinstance(network, int) and (0 < network < 33): - address = {"address": [{"ip": ip_addr, "prefix-length": network}, ]} + data = { + "ietf-ip:ipv4": { + "address": [{"ip": ip_addr, "prefix-length": network}, ]}} else: - raise HoneycombError("Value {0} is not a valid netmask or network " - "prefix length.".format(network)) - return InterfaceKeywords._set_interface_properties( - node, interface, path, address) + raise ValueError("Value {0} is not a valid netmask or network " + "prefix length.".format(network)) + status_code, _ = HcUtil.put_honeycomb_data( + node, "config_vpp_interfaces", data, path) + + if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): + raise HoneycombError( + "Configuring IPv4 address failed. " + "Status code:{0}".format(status_code)) @staticmethod def add_ipv4_address(node, interface, ip_addr, network): @@ -1555,10 +1565,8 @@ class InterfaceKeywords(object): :param node: Honeycomb node. :param interface: The interface where policer will be disabled. - :param table_name: Name of the classify table. :type node: dict :type interface: str - :type table_name: str :returns: Content of response. :rtype: bytearray :raises HoneycombError: If the configuration of interface is not @@ -1780,7 +1788,7 @@ class InterfaceKeywords(object): for src_interface in src_interfaces: src_interface["iface-ref"] = Topology. \ convert_interface_reference( - node, src_interface["iface-ref"], "name") + node, src_interface["iface-ref"], "name") data = { "span": { "mirrored-interfaces": { @@ -1809,3 +1817,72 @@ class InterfaceKeywords(object): local0_key = Topology.add_new_port(node, "localzero") Topology.update_interface_sw_if_index(node, local0_key, 0) Topology.update_interface_name(node, local0_key, "local0") + + @staticmethod + def configure_interface_unnumbered(node, interface, interface_src=None): + """Configure the specified interface as unnumbered. The interface + borrows IP address from the specified source interface. If not source + interface is provided, unnumbered configuration will be removed. + + :param node: Honeycomb node. + :param interface: Name, link name or sw_if_index of an interface. + :param interface_src: Name of source interface. + :type node: dict + :type interface: str or int + :type interface_src: str + :raises HoneycombError: If the configuration fails. + """ + + interface = InterfaceKeywords.handle_interface_reference( + node, interface) + + path = "/interface/{0}/unnumbered-interfaces:unnumbered"\ + .format(interface) + + if interface_src: + data = { + "unnumbered": { + "use": interface_src + } + } + status_code, _ = HcUtil.put_honeycomb_data( + node, "config_vpp_interfaces", data, path) + else: + status_code, _ = HcUtil.delete_honeycomb_data( + node, "config_vpp_interfaces", path) + + if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): + raise HoneycombError( + "Configuring unnumbered interface failed. " + "Status code:{0}".format(status_code)) + + @staticmethod + def handle_interface_reference(node, interface): + """Convert any interface reference to interface name used by Honeycomb. + + :param node: Honeycomb node. + :param interface: Name, link name or sw_if_index of an interface, + name of a custom interface or name of a sub-interface. + :type node: Honeycomb node. + :type interface: str or int + :returns: Name of interface that can be used in Honeycomb requests. + :rtype: str + """ + + try: + interface = Topology.convert_interface_reference( + node, interface, "name") + interface = interface.replace("/", "%2F") + except RuntimeError: + # interface is not in topology + if "." in interface: + # Assume it's the name of a sub-interface + interface, index = interface.split(".") + interface = interface.replace("/", "%2F") + interface = "{0}/vpp-vlan:sub-interfaces/sub-interface/{1}".\ + format(interface, index) + else: + # Assume it's the name of a custom interface (pbb, vxlan, etc.) + interface = interface.replace("/", "%2F") + + return interface diff --git a/resources/libraries/python/honeycomb/HoneycombSetup.py b/resources/libraries/python/honeycomb/HoneycombSetup.py index aecb022314..5026cb4868 100644 --- a/resources/libraries/python/honeycomb/HoneycombSetup.py +++ b/resources/libraries/python/honeycomb/HoneycombSetup.py @@ -438,7 +438,7 @@ class HoneycombSetup(object): "node {0}, {1}".format(node, stderr)) @staticmethod - def setup_odl_client(node, odl_name): + def configure_odl_client(node, odl_name): """Start ODL client on the specified node. Karaf should be located in /mnt/common, and VPP and Honeycomb should diff --git a/resources/libraries/python/honeycomb/Lisp.py b/resources/libraries/python/honeycomb/Lisp.py index 8c124d194c..f89ffed0b9 100644 --- a/resources/libraries/python/honeycomb/Lisp.py +++ b/resources/libraries/python/honeycomb/Lisp.py @@ -148,7 +148,7 @@ class LispKeywords(object): if ret_code == HTTPCodes.OK: data["lisp"]["enable"] = bool(state) elif ret_code == HTTPCodes.NOT_FOUND: - data = {"lisp": {"enable": bool(state)}} + data = {"lisp": {"enable": bool(state)}} else: raise HoneycombError("Unexpected return code when getting existing" " Lisp configuration.") @@ -340,7 +340,7 @@ class LispKeywords(object): data = { "map-request-mode": { "mode": "source-destination" if src_dst - else "target-destination" + else "target-destination" } } diff --git a/resources/libraries/python/honeycomb/proxyARP.py b/resources/libraries/python/honeycomb/ProxyARP.py similarity index 100% rename from resources/libraries/python/honeycomb/proxyARP.py rename to resources/libraries/python/honeycomb/ProxyARP.py diff --git a/resources/libraries/robot/honeycomb/honeycomb.robot b/resources/libraries/robot/honeycomb/honeycomb.robot index 336039e1fb..e868ecd50a 100644 --- a/resources/libraries/robot/honeycomb/honeycomb.robot +++ b/resources/libraries/robot/honeycomb/honeycomb.robot @@ -118,9 +118,9 @@ | | [Arguments] | ${node} | | Archive Honeycomb log | ${node} -| Setup ODL Client Service On DUT +| Configure ODL Client Service On DUT | | [Arguments] | ${node} | ${odl_name} -| | Setup ODL client | ${node} | ${odl_name} +| | Configure ODL client | ${node} | ${odl_name} | | Wait until keyword succeeds | 4min | 16sec | | ... | Mount Honeycomb on ODL | ${node} | | Wait until keyword succeeds | 2min | 16sec diff --git a/resources/libraries/robot/honeycomb/interfaces.robot b/resources/libraries/robot/honeycomb/interfaces.robot index 2ab97e0d96..3eef9f1b2d 100644 --- a/resources/libraries/robot/honeycomb/interfaces.robot +++ b/resources/libraries/robot/honeycomb/interfaces.robot @@ -718,7 +718,7 @@ | | ... | *Example:* | | ... | | ... | \| Honeycomb should show disabled interface in oper data \ -| | ... | \|${nodes['DUT1']} \| ${vx_interface} \| +| | ... | \| ${nodes['DUT1']} \| ${vx_interface} \| | | [Arguments] | ${node} | ${index} | | interfaceAPI.check disabled interface | ${node} | ${index} @@ -733,7 +733,7 @@ | | ... | *Example:* | | ... | | ... | \| Honeycomb should not show disabled interface in oper data \ -| | ... | \|${nodes['DUT1']} \| ${vx_interface} \| +| | ... | \| ${nodes['DUT1']} \| ${vx_interface} \| | | [Arguments] | ${node} | ${index} | | Run keyword and expect error | * | | ... | Honeycomb should show disabled interface in oper data @@ -775,3 +775,37 @@ | | ... | --timeout | ${5} | | Run Traffic Script On Node | send_icmp_wait_for_reply.py | | ... | ${tg_node} | ${args} + +| Honeycomb adds unnumbered configuration to interface +| | [Documentation] | Adds unnumbered configuration to interface, borrowing IP +| | ... | address from the other specified interface. +| | ... +| | ... | *Arguments:* +| | ... | - node - information about a DUT node. Type: dictionary +| | ... | - interface - Name of the interface to be configured. Type: string +| | ... | - interface_src - Name of the interface to borrow IP address from.\ +| | ... | Type: string +| | ... +| | ... | *Example:* +| | ... +| | ... | \| Honeycomb adds unnumbered configuration to interface \ +| | ... | \| ${nodes['DUT1']} \| GigabitEthernet0/8/0 \| GigabitEthernet0/9/0 \| +| | ... +| | [Arguments] | ${node} | ${Interface} | ${interface_src} +| | Configure interface unnumbered | ${node} | ${interface} | ${interface_src} + +| Honeycomb removes unnumbered configuration from interface +| | [Documentation] | Removes unnumbered configuration from the specified +| | ... | interface. +| | ... +| | ... | *Arguments:* +| | ... | - node - information about a DUT node. Type: dictionary +| | ... | - interface - Name of the interface to be configured. Type: string +| | ... +| | ... | *Example:* +| | ... +| | ... | \| Honeycomb adds unnumbered configuration to interface \ +| | ... | \| ${nodes['DUT1']} \| GigabitEthernet0/8/0 \| +| | ... +| | [Arguments] | ${node} | ${Interface} +| | Configure interface unnumbered | ${node} | ${interface} diff --git a/resources/libraries/robot/honeycomb/proxyarp.robot b/resources/libraries/robot/honeycomb/proxyarp.robot index 745507a4c3..209e213cf8 100644 --- a/resources/libraries/robot/honeycomb/proxyarp.robot +++ b/resources/libraries/robot/honeycomb/proxyarp.robot @@ -12,8 +12,8 @@ # limitations under the License. *** Settings *** -| Library | resources.libraries.python.honeycomb.proxyARP.ProxyARPKeywords -| Library | resources.libraries.python.honeycomb.proxyARP.IPv6NDProxyKeywords +| Library | resources.libraries.python.honeycomb.ProxyARP.ProxyARPKeywords +| Library | resources.libraries.python.honeycomb.ProxyARP.IPv6NDProxyKeywords | Documentation | Keywords used to test Honeycomb ARP proxy and IPv6ND proxy. *** Keywords *** diff --git a/tests/func/honeycomb/__init__.robot b/tests/func/honeycomb/__init__.robot index e247180b25..128f19f6a0 100644 --- a/tests/func/honeycomb/__init__.robot +++ b/tests/func/honeycomb/__init__.robot @@ -43,6 +43,6 @@ | | Run Keyword If | '${use_odl_client}' != '${NONE}' | | ... | Run Keywords | | ... | Set Global Variable | ${use_odl_client} | AND -| | ... | Setup ODL Client Service On DUT | ${node} | ${use_odl_client} +| | ... | Configure ODL Client Service On DUT | ${node} | ${use_odl_client} | | ... | ELSE | Log | Variable HC_ODL is not present. Not using ODL. | | ... | level=INFO diff --git a/tests/func/honeycomb/mgmt-cfg-int-subint-apihc-apivat-func.robot b/tests/func/honeycomb/mgmt-cfg-int-subint-apihc-apivat-func.robot index 9fb858ad25..c7e0737a6b 100644 --- a/tests/func/honeycomb/mgmt-cfg-int-subint-apihc-apivat-func.robot +++ b/tests/func/honeycomb/mgmt-cfg-int-subint-apihc-apivat-func.robot @@ -18,6 +18,7 @@ | Resource | resources/libraries/robot/honeycomb/bridge_domain.robot | Resource | resources/libraries/robot/honeycomb/interfaces.robot | Variables | resources/test_data/honeycomb/sub_interfaces.py +| Suite Setup | Add Interface local0 To Topology | ${node} | Suite Teardown | ... | Restart Honeycomb and VPP | ${node} | Force Tags | HC_FUNC @@ -458,6 +459,82 @@ | | ... | ${node} | ${sub_if_name} | | ... | ${ipv6_2['address']} | ${ipv6_2['prefix-length']} +| TC22: Honeycomb can configure unnumbered sub-interface +| | [Documentation] | Check if Honeycomb can configure an unnumbered interface\ +| | ... | on a sub-interface, borrowing the IP address of 'local0'. +| | Given sub-interface ipv4 address from Honeycomb should be empty +| | ... | ${node} | ${super_if} | ${sub_if_id} +| | And sub-interface ipv4 address from VAT should be empty +| | ... | ${node} | ${sub_if_name} +| | And Honeycomb sets interface ipv4 address | ${node} +| | ... | local0 | ${ipv4['address']} | ${ipv4['prefix-length']} +| | When Honeycomb adds unnumbered configuration to interface +| | ... | ${node} | ${super_if}.${sub_if_id} | local0 +| | Then IPv4 address from Honeycomb should be +| | ... | ${node} | local0 | ${ipv4['address']} | ${ipv4['prefix-length']} +| | And IPv4 address from VAT should be +| | ... | ${node} | local0 +| | ... | ${ipv4['address']} | ${ipv4['prefix-length']} | ${ipv4['netmask']} +| | And sub-interface ipv4 address from Honeycomb should be +| | ... | ${node} | ${super_if} | ${sub_if_id} +| | ... | ${ipv4['address']} | ${ipv4['prefix-length']} +| | And sub-interface ipv4 address from VAT should be +| | ... | ${node} | ${sub_if_name} +| | ... | ${ipv4['address']} | ${ipv4['prefix-length']} + +| TC23: Honeycomb removes sub-interface unnumbered configuration +| | [Documentation] | Check if Honeycomb can remove unnumbered configuration\ +| | ... | from a sub-interface. +| | [Teardown] | Honeycomb removes interface ipv4 addresses | ${node} +| | ... | local0 +| | Given IPv4 address from Honeycomb should be +| | ... | ${node} | local0 | ${ipv4['address']} | ${ipv4['prefix-length']} +| | And IPv4 address from VAT should be +| | ... | ${node} | local0 +| | ... | ${ipv4['address']} | ${ipv4['prefix-length']} | ${ipv4['netmask']} +| | And sub-interface ipv4 address from Honeycomb should be +| | ... | ${node} | ${super_if} | ${sub_if_id} +| | ... | ${ipv4['address']} | ${ipv4['prefix-length']} +| | And sub-interface ipv4 address from VAT should be +| | ... | ${node} | ${sub_if_name} +| | ... | ${ipv4['address']} | ${ipv4['prefix-length']} +| | When Honeycomb removes unnumbered configuration from interface +| | ... | ${node} | ${super_if}.${sub_if_id} +| | Then IPv4 address from Honeycomb should be +| | ... | ${node} | local0 | ${ipv4['address']} | ${ipv4['prefix-length']} +| | And IPv4 address from VAT should be +| | ... | ${node} | local0 +| | ... | ${ipv4['address']} | ${ipv4['prefix-length']} | ${ipv4['netmask']} +| | And sub-interface ipv4 address from Honeycomb should be empty +| | ... | ${node} | ${super_if} | ${sub_if_id} +| | And sub-interface ipv4 address from VAT should be empty +| | ... | ${node} | ${sub_if_name} + +| TC24: Honeycomb can configure unnumbered interface using a sub-interface +| | [Documentation] | Check if Honeycomb can configure an unnumbered interface\ +| | ... | on an interface, borrowing the IP address of a sub-interface. +| | Given IPv4 address from Honeycomb should be empty | ${node} | local0 +| | And ipv4 address from VAT should be empty | ${node} | local0 +| | And sub-interface ipv4 address from Honeycomb should be empty +| | ... | ${node} | ${super_if} | ${sub_if_id} +| | And sub-interface ipv4 address from VAT should be empty +| | ... | ${node} | ${sub_if_name} +| | And Honeycomb sets sub-interface ipv4 address +| | ... | ${node} | ${super_if} | ${sub_if_id} +| | ... | ${ipv4['address']} | ${ipv4['prefix-length']} +| | When Honeycomb adds unnumbered configuration to interface +| | ... | ${node} | local0 | ${super_if}.${sub_if_id} +| | Then IPv4 address from Honeycomb should be +| | ... | ${node} | local0 | ${ipv4['address']} | ${ipv4['prefix-length']} +| | And IPv4 address from VAT should be +| | ... | ${node} | local0 +| | ... | ${ipv4['address']} | ${ipv4['prefix-length']} | ${ipv4['netmask']} +| | And sub-interface ipv4 address from Honeycomb should be +| | ... | ${node} | ${super_if} | ${sub_if_id} +| | ... | ${ipv4['address']} | ${ipv4['prefix-length']} +| | And sub-interface ipv4 address from VAT should be +| | ... | ${node} | ${sub_if_name} +| | ... | ${ipv4['address']} | ${ipv4['prefix-length']} *** Keywords *** | Set super and sub interfaces up diff --git a/tests/func/honeycomb/mgmt-cfg-intip4-intip6-apihc-apivat-func.robot b/tests/func/honeycomb/mgmt-cfg-intip4-intip6-apihc-apivat-func.robot index 1d2b4ae7de..edc1713824 100644 --- a/tests/func/honeycomb/mgmt-cfg-intip4-intip6-apihc-apivat-func.robot +++ b/tests/func/honeycomb/mgmt-cfg-intip4-intip6-apihc-apivat-func.robot @@ -198,7 +198,7 @@ | | ... | ${tg_to_dut_if1} | ${tg_to_dut_if1_mac} | | ... | ${tg_to_dut_if1} | ${dut_to_tg_if1_mac} -TC11: Honeycomb fails to configure two IPv4 addresses from the same subnet +| TC11: Honeycomb fails to configure two IPv4 addresses from the same subnet | | [Documentation] | Check if Honeycomb can configure two IPv4 addresses in\ | | ... | the same subnet onto a single interface. It should not be possible. | | [Teardown] | Honeycomb removes interface ipv4 addresses | ${node} @@ -212,7 +212,7 @@ TC11: Honeycomb fails to configure two IPv4 addresses from the same subnet | | And Honeycomb fails to add interface ipv4 address | | ... | ${node} | ${interface} | 192.232.0.2 | ${9} -TC12: Honeycomb fails to configure two IPv6 addresses from the same subnet +| TC12: Honeycomb fails to configure two IPv6 addresses from the same subnet | | [Documentation] | Check if Honeycomb can configure two IPv6 addresses in\ | | ... | the same subnet onto a single interface. It should not be possible. | | [Tags] | EXPECTED_FAILING @@ -224,4 +224,45 @@ TC12: Honeycomb fails to configure two IPv6 addresses from the same subnet | | Then Honeycomb fails to add interface ipv6 address | | ... | ${node} | ${interface} | 10::FF11 | ${64} | | And Honeycomb fails to add interface ipv6 address -| | ... | ${node} | ${interface} | 10::FFFF | ${64} \ No newline at end of file +| | ... | ${node} | ${interface} | 10::FFFF | ${64} + +| TC13: Honeycomb can configure unnumbered interface +| | [Documentation] | Check if Honeycomb can configure an unnumbered interface\ +| | ... | on a physical interface, borrowing the IP address of 'local0'. +| | Given Honeycomb sets interface ipv4 address | ${node} +| | ... | local0 | ${ipv4_address} | ${ipv4_prefix} +| | When Honeycomb adds unnumbered configuration to interface +| | ... | ${node} | ${interface} | local0 +| | Then IPv4 address from Honeycomb should be +| | ... | ${node} | local0 | ${ipv4_address} | ${ipv4_prefix} +| | And IPv4 address from VAT should be +| | ... | ${node} | local0 | ${ipv4_address} +| | ... | ${ipv4_prefix} | ${ipv4_mask} +| | And IPv4 address from Honeycomb should be +| | ... | ${node} | ${interface} | ${ipv4_address} | ${ipv4_prefix} +| | And IPv4 address from VAT should be +| | ... | ${node} | ${interface} | ${ipv4_address} +| | ... | ${ipv4_prefix} | ${ipv4_mask} + +| TC14: Honeycomb removes interface unnumbered configuration +| | [Documentation] | Check if Honeycomb can remove unnumbered configuration\ +| | ... | from an interface. +| | Given IPv4 address from Honeycomb should be +| | ... | ${node} | local0 | ${ipv4_address} | ${ipv4_prefix} +| | And IPv4 address from VAT should be +| | ... | ${node} | local0 | ${ipv4_address} +| | ... | ${ipv4_prefix} | ${ipv4_mask} +| | And IPv4 address from Honeycomb should be +| | ... | ${node} | ${interface} | ${ipv4_address} | ${ipv4_prefix} +| | And IPv4 address from VAT should be +| | ... | ${node} | ${interface} | ${ipv4_address} +| | ... | ${ipv4_prefix} | ${ipv4_mask} +| | When Honeycomb removes unnumbered configuration from interface +| | ... | ${node} | ${interface} +| | Then IPv4 address from Honeycomb should be +| | ... | ${node} | local0 | ${ipv4_address} | ${ipv4_prefix} +| | And IPv4 address from VAT should be +| | ... | ${node} | local0 | ${ipv4_address} +| | ... | ${ipv4_prefix} | ${ipv4_mask} +| | And IPv4 address from Honeycomb should be empty | ${node} | ${interface} +| | And ipv4 address from VAT should be empty | ${node} | ${interface} -- 2.16.6