From 0b4ceb8d40f0b667eb6083298a4f133b8ae9adaa Mon Sep 17 00:00:00 2001 From: selias Date: Wed, 8 Feb 2017 11:17:16 +0100 Subject: CSIT-523 HC Test: routing - add routing test suite, variables and keywords Change-Id: I57e180350c30221befe8d1fc4e3b146d394c4f5d Signed-off-by: selias --- .../python/honeycomb/HcAPIKwInterfaces.py | 14 +- resources/libraries/python/honeycomb/Routing.py | 201 +++++++++++++++++++++ 2 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 resources/libraries/python/honeycomb/Routing.py (limited to 'resources/libraries/python') diff --git a/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py b/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py index 3a32cbe5ff..eff0719e26 100644 --- a/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py +++ b/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 Cisco and/or its affiliates. +# Copyright (c) 2017 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: @@ -555,6 +555,9 @@ class InterfaceKeywords(object): :rtype: bytearray """ + interface = Topology.convert_interface_reference( + node, interface, "name") + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4", "neighbor") neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ] @@ -626,6 +629,9 @@ class InterfaceKeywords(object): :rtype: bytearray """ + interface = Topology.convert_interface_reference( + node, interface, "name") + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6") address = {"address": [{"ip": ip_addr, "prefix-length": prefix_len}, ]} return InterfaceKeywords._set_interface_properties( @@ -686,6 +692,9 @@ class InterfaceKeywords(object): :rtype: bytearray """ + interface = Topology.convert_interface_reference( + node, interface, "name") + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6", "neighbor") neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ] @@ -752,6 +761,9 @@ class InterfaceKeywords(object): :raises HoneycombError: If the parameter is not valid. """ + interface = Topology.convert_interface_reference( + node, interface, "name") + if param not in InterfaceKeywords.ROUTING_PARAMS: raise HoneycombError("The parameter {0} is invalid.".format(param)) diff --git a/resources/libraries/python/honeycomb/Routing.py b/resources/libraries/python/honeycomb/Routing.py new file mode 100644 index 0000000000..d0f23892af --- /dev/null +++ b/resources/libraries/python/honeycomb/Routing.py @@ -0,0 +1,201 @@ +# Copyright (c) 2017 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This module implements keywords to manipulate routing tables using +Honeycomb REST API.""" + +from robot.api import logger + +from resources.libraries.python.HTTPRequest import HTTPCodes +from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError +from resources.libraries.python.honeycomb.HoneycombUtil \ + import HoneycombUtil as HcUtil +from resources.libraries.python.honeycomb.HoneycombUtil \ + import DataRepresentation +from resources.libraries.python.VatExecutor import VatTerminal + + +class RoutingKeywords(object): + """Implementation of keywords which make it possible to: + - add/remove routing tables, + - add/remove routing table entries + - get operational data about routing tables, + """ + + def __init__(self): + pass + + @staticmethod + def _set_routing_table_properties(node, path, data=None): + """Set routing table properties and check the return code. + + :param node: Honeycomb node. + :param path: Path which is added to the base path to identify the data. + :param data: The new data to be set. If None, the item will be removed. + :type node: dict + :type path: str + :type data: dict + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If the status code in response is not + 200 = OK. + """ + + if data: + status_code, resp = HcUtil.\ + put_honeycomb_data(node, "config_routing_table", data, path, + data_representation=DataRepresentation.JSON) + else: + status_code, resp = HcUtil.\ + delete_honeycomb_data(node, "config_routing_table", path) + + if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): + if data is None and '"error-tag":"data-missing"' in resp: + logger.debug("data does not exist in path.") + else: + raise HoneycombError( + "The configuration of routing table was not successful. " + "Status code: {0}.".format(status_code)) + return resp + + @staticmethod + def configure_routing_table(node, name, ip_version, data, vrf=1, + special=False): + """Configure a routing table according to the data provided. + + :param node: Honeycomb node. + :param name: Name for the table. + :param ip_version: IP protocol version, ipv4 or ipv6. + :param data: Route configuration that should be set. + :param vrf: vrf-id to attach configuration to. + :param special: Must be True if the configuration is a special route. + :type node: dict + :type name: str + :type ip_version: str + :type data: dict + :type vrf: int + :type special: bool + :returns: Content of response. + :rtype: bytearray + """ + if special: + ip_version = "hc2vpp-ietf-{0}-unicast-routing:{0}".format( + ip_version) + protocol = "vpp-routing-ra:vpp-protocol-attributes" + else: + ip_version = ip_version + protocol = "vpp-protocol-attributes" + + full_data = { + "routing-protocol": [ + { + "name": name, + "description": "hc2vpp-csit test route", + "enabled": "true", + "type": "static", + protocol: { + "primary-vrf": vrf + }, + "static-routes": { + ip_version: { + "route": data + } + } + } + ] + } + + path = "/routing-protocol/{0}".format(name) + return RoutingKeywords._set_routing_table_properties( + node, path, full_data) + + @staticmethod + def delete_routing_table(node, name): + """Delete the specified routing table from configuration data. + + :param node: Honeycomb node. + :param name: Name of the table. + :type node: dict + :type name: str + :returns: Content of response. + :rtype: bytearray + """ + + path = "/routing-protocol/{0}".format(name) + return RoutingKeywords._set_routing_table_properties(node, path) + + @staticmethod + def get_routing_table_oper(node, name, ip_version): + """Retrieve operational data about the specified routing table. + + :param node: Honeycomb node. + :param name: Name of the routing table. + :param ip_version: IP protocol version, ipv4 or ipv6. + :type node: dict + :type name: str + :type ip_version: str + :returns: Routing table operational data. + :rtype: list + :raises HoneycombError: If the operation fails. + """ + + path = "/routing-protocol/{0}".format(name) + status_code, resp = HcUtil.\ + get_honeycomb_data(node, "oper_routing_table", path) + + if status_code != HTTPCodes.OK: + raise HoneycombError( + "Not possible to get operational information about the " + "classify tables. Status code: {0}.".format(status_code)) + + data = RoutingKeywords.clean_routing_oper_data( + resp['routing-protocol'][0]['static-routes'] + ['hc2vpp-ietf-{0}-unicast-routing:{0}'.format(ip_version)]['route']) + + return data + + @staticmethod + def clean_routing_oper_data(data): + """Prepare received routing operational data to be verified against + expected data. + + :param data: Routing operational data. + :type data: list + :returns: Routing operational data without entry ID numbers. + :rtype: list + """ + + for item in data: + # ID values are auto-incremented based on existing routes in VPP + item.pop("id", None) + if "next-hop-list" in item.keys(): + for item2 in item["next-hop-list"]["next-hop"]: + item2.pop("id", None) + + if "next-hop-list" in item.keys(): + # List items come in random order + item["next-hop-list"]["next-hop"].sort() + + return data + + @staticmethod + def log_routing_configuration(node): + """Retrieve route configuration using VAT and print the response + to robot log. + + :param node: VPP node. + :type node: dict + """ + + with VatTerminal(node) as vat: + vat.vat_terminal_exec_cmd("ip_fib_dump") -- cgit 1.2.3-korg