CSIT-610 HC Test: add test cases for unnumbered interface 64/6764/5
authorselias <samelias@cisco.com>
Thu, 18 May 2017 16:07:46 +0000 (18:07 +0200)
committerTibor Frank <tifrank@cisco.com>
Mon, 5 Jun 2017 11:25:06 +0000 (11:25 +0000)
 - 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 <samelias@cisco.com>
resources/libraries/python/honeycomb/HcAPIKwInterfaces.py
resources/libraries/python/honeycomb/HoneycombSetup.py
resources/libraries/python/honeycomb/Lisp.py
resources/libraries/python/honeycomb/ProxyARP.py [moved from resources/libraries/python/honeycomb/proxyARP.py with 100% similarity]
resources/libraries/robot/honeycomb/honeycomb.robot
resources/libraries/robot/honeycomb/interfaces.robot
resources/libraries/robot/honeycomb/proxyarp.robot
tests/func/honeycomb/__init__.robot
tests/func/honeycomb/mgmt-cfg-int-subint-apihc-apivat-func.robot
tests/func/honeycomb/mgmt-cfg-intip4-intip6-apihc-apivat-func.robot

index e78696c..1e0b1a5 100644 (file)
@@ -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
index aecb022..5026cb4 100644 (file)
@@ -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
index 8c124d1..f89ffed 100644 (file)
@@ -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"
             }
         }
 
index 336039e..e868ecd 100644 (file)
 | | [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
index 2ab97e0..3eef9f1 100644 (file)
 | | ... | *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}
 
 | | ... | *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
 | | ...                 | --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}
index 745507a..209e213 100644 (file)
@@ -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 ***
index e247180..128f19f 100644 (file)
@@ -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
index 9fb858a..c7e0737 100644 (file)
@@ -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
 | | ... | ${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
index 1d2b4ae..edc1713 100644 (file)
 | | ... | ${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}