From c37f394a29165f839c3032e7f9485e35fb3307f2 Mon Sep 17 00:00:00 2001 From: Tibor Frank Date: Tue, 10 May 2016 14:50:41 +0200 Subject: Move Honeycomb libraries to honeycomb subdirectory. - move all Honeycomb related libraries written in python to new directory resources/libraries/python/honeycomb - update all related includes in all source files Change-Id: Ifa96b8f670b456b14421929d6020ddf8e02d9cbc Signed-off-by: Tibor Frank --- resources/libraries/python/HcAPIKwBridgeDomain.py | 329 ---------- resources/libraries/python/HcAPIKwInterfaces.py | 712 -------------------- resources/libraries/python/HoneycombSetup.py | 186 ------ resources/libraries/python/HoneycombUtil.py | 387 ----------- .../python/honeycomb/HcAPIKwBridgeDomain.py | 330 ++++++++++ .../python/honeycomb/HcAPIKwInterfaces.py | 713 +++++++++++++++++++++ .../libraries/python/honeycomb/HoneycombSetup.py | 187 ++++++ .../libraries/python/honeycomb/HoneycombUtil.py | 387 +++++++++++ resources/libraries/python/honeycomb/__init__.py | 16 + .../libraries/robot/honeycomb/bridge_domain.robot | 6 +- .../libraries/robot/honeycomb/honeycomb.robot | 5 +- .../libraries/robot/honeycomb/interfaces.robot | 8 +- 12 files changed, 1642 insertions(+), 1624 deletions(-) delete mode 100644 resources/libraries/python/HcAPIKwBridgeDomain.py delete mode 100644 resources/libraries/python/HcAPIKwInterfaces.py delete mode 100644 resources/libraries/python/HoneycombSetup.py delete mode 100644 resources/libraries/python/HoneycombUtil.py create mode 100644 resources/libraries/python/honeycomb/HcAPIKwBridgeDomain.py create mode 100644 resources/libraries/python/honeycomb/HcAPIKwInterfaces.py create mode 100644 resources/libraries/python/honeycomb/HoneycombSetup.py create mode 100644 resources/libraries/python/honeycomb/HoneycombUtil.py create mode 100644 resources/libraries/python/honeycomb/__init__.py diff --git a/resources/libraries/python/HcAPIKwBridgeDomain.py b/resources/libraries/python/HcAPIKwBridgeDomain.py deleted file mode 100644 index 2f7c149684..0000000000 --- a/resources/libraries/python/HcAPIKwBridgeDomain.py +++ /dev/null @@ -1,329 +0,0 @@ -# Copyright (c) 2016 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. - -"""Keywords to manipulate bridge domain configuration using Honeycomb REST API. - -The keywords make possible to put and get configuration data and to get -operational data. -""" - - -from resources.libraries.python.HTTPRequest import HTTPCodes -from resources.libraries.python.HoneycombSetup import HoneycombError -from resources.libraries.python.HoneycombUtil import HoneycombUtil as HcUtil -from resources.libraries.python.HoneycombUtil import DataRepresentation - - -class BridgeDomainKeywords(object): - """Keywords to manipulate bridge domain configuration. - - Implements keywords which get configuration and operational data about - bridge domains and put the bridge domains' parameters using Honeycomb REST - API. - """ - - PARAMS = ("flood", "forward", "learn", "unknown-unicast-flood", - "arp-termination") - - def __init__(self): - pass - - @staticmethod - def _configure_bd(node, bd_name, data, - data_representation=DataRepresentation.JSON): - """Send bridge domain configuration data and check the response. - - :param node: Honeycomb node. - :param bd_name: The name of bridge domain. - :param data: Configuration data to be sent in PUT request. - :param data_representation: How the data is represented. - :type node: dict - :type bd_name: str - :type data: dict - :type data_representation: DataRepresentation - :return: Content of response. - :rtype: bytearray - :raises HoneycombError: If the status code in response on PUT is not - 200 = OK. - """ - - status_code, resp = HcUtil.\ - put_honeycomb_data(node, "config_bridge_domain", data, - data_representation=data_representation) - if status_code != HTTPCodes.OK: - raise HoneycombError( - "The configuration of bridge domain '{0}' was not successful. " - "Status code: {1}.".format(bd_name, status_code)) - return resp - - @staticmethod - def _set_bd_properties(node, bd_name, path, new_value=None): - """Set bridge domain properties. - - This method reads bridge domain configuration data, creates, changes or - removes the requested data and puts it back to Honeycomb. - - :param node: Honeycomb node. - :param bd_name: The name of bridge domain. - :param path: Path to data we want to change, create or remove. - :param new_value: The new value to be set. If None, the item will be - removed. - :type node: dict - :type bd_name: str - :type path: tuple - :type new_value: str, dict or list - :return: Content of response. - :rtype: bytearray - :raises HoneycombError: If it is not possible to get or set the data. - """ - - status_code, resp = HcUtil.\ - get_honeycomb_data(node, "config_bridge_domain") - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get configuration information about the " - "bridge domains. Status code: {0}.".format(status_code)) - - if new_value: - new_data = HcUtil.set_item_value(resp, path, new_value) - else: - new_data = HcUtil.remove_item(resp, path) - return BridgeDomainKeywords._configure_bd(node, bd_name, new_data) - - @staticmethod - def _create_bd_structure(bd_name, **kwargs): - """Create the bridge domain data structure as it is expected by - Honeycomb REST API. - - :param bd_name: Bridge domain name. - :param kwargs: Parameters and their values. The accepted parameters are - defined in BridgeDomainKeywords.PARAMS. - :type bd_name: str - :type kwargs: dict - :return: Bridge domain data structure. - :rtype: dict - """ - - bd_structure = {"name": bd_name} - - for param, value in kwargs.items(): - if param not in BridgeDomainKeywords.PARAMS: - raise HoneycombError("The parameter {0} is invalid.". - format(param)) - bd_structure[param] = str(value) - - return bd_structure - - @staticmethod - def get_all_bds_cfg_data(node): - """Get configuration data about all bridge domains from Honeycomb. - - :param node: Honeycomb node. - :type node: dict - :return: Configuration data about all bridge domains from Honeycomb. - :rtype: list - :raises HoneycombError: If it is not possible to get configuration data. - """ - - status_code, resp = HcUtil.\ - get_honeycomb_data(node, "config_bridge_domain") - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get configuration information about the " - "bridge domains. Status code: {0}.".format(status_code)) - try: - return resp["bridge-domains"]["bridge-domain"] - - except (KeyError, TypeError): - return [] - - @staticmethod - def get_bd_cfg_data(node, bd_name): - """Get configuration data about the given bridge domain from Honeycomb. - - :param node: Honeycomb node. - :param bd_name: The name of bridge domain. - :type node: dict - :type bd_name: str - :return: Configuration data about the given bridge domain from - Honeycomb. - :rtype: dict - """ - - intfs = BridgeDomainKeywords.get_all_bds_cfg_data(node) - for intf in intfs: - if intf["name"] == bd_name: - return intf - return {} - - @staticmethod - def get_all_bds_oper_data(node): - """Get operational data about all bridge domains from Honeycomb. - - :param node: Honeycomb node. - :type node: dict - :return: Operational data about all bridge domains from Honeycomb. - :rtype: list - :raises HoneycombError: If it is not possible to get operational data. - """ - - status_code, resp = HcUtil.\ - get_honeycomb_data(node, "oper_bridge_domains") - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get operational information about the " - "bridge domains. Status code: {0}.".format(status_code)) - try: - return resp["bridge-domains"]["bridge-domain"] - - except (KeyError, TypeError): - return [] - - @staticmethod - def get_bd_oper_data(node, bd_name): - """Get operational data about the given bridge domain from Honeycomb. - - :param node: Honeycomb node. - :param bd_name: The name of bridge domain. - :type node: dict - :type bd_name: str - :return: Operational data about the given bridge domain from Honeycomb. - :rtype: dict - """ - - intfs = BridgeDomainKeywords.get_all_bds_oper_data(node) - for intf in intfs: - if intf["name"] == bd_name: - return intf - return {} - - @staticmethod - def add_first_bd(node, bd_name, **kwargs): - """Add the first bridge domain. - - If there are any other bridge domains configured, they will be removed. - - :param node: Honeycomb node. - :param bd_name: Bridge domain name. - :param kwargs: Parameters and their values. The accepted parameters are - defined in BridgeDomainKeywords.PARAMS - :type node: dict - :type bd_name: str - :type kwargs: dict - :return: Bridge domain data structure. - :rtype: dict - """ - - path = ("bridge-domains", ) - new_bd = BridgeDomainKeywords._create_bd_structure(bd_name, **kwargs) - bridge_domain = {"bridge-domain": [new_bd, ]} - return BridgeDomainKeywords._set_bd_properties(node, bd_name, path, - bridge_domain) - - @staticmethod - def add_bd(node, bd_name, **kwargs): - """Add a bridge domain. - - :param node: Honeycomb node. - :param bd_name: Bridge domain name. - :param kwargs: Parameters and their values. The accepted parameters are - defined in BridgeDomainKeywords.PARAMS - :type node: dict - :type bd_name: str - :type kwargs: dict - :return: Bridge domain data structure. - :rtype: dict - """ - - path = ("bridge-domains", "bridge-domain") - new_bd = BridgeDomainKeywords._create_bd_structure(bd_name, **kwargs) - bridge_domain = [new_bd, ] - return BridgeDomainKeywords._set_bd_properties(node, bd_name, path, - bridge_domain) - - @staticmethod - def remove_all_bds(node): - """Remove all bridge domains. - - :param node: Honeycomb node. - :type node: dict - :return: Content of response. - :rtype: bytearray - :raises HoneycombError: If it is not possible to remove all bridge - domains. - """ - - data = {"bridge-domains": {"bridge-domain": []}} - status_code, resp = HcUtil.\ - put_honeycomb_data(node, "config_bridge_domain", data) - if status_code != HTTPCodes.OK: - raise HoneycombError("Not possible to remove all bridge domains. " - "Status code: {0}.".format(status_code)) - return resp - - @staticmethod - def remove_bridge_domain(node, bd_name): - """Remove a bridge domain. - - :param node: Honeycomb node. - :param bd_name: The name of bridge domain to be removed. - :type node: dict - :type bd_name: str - :return: Content of response. - :rtype: bytearray - :raises HoneycombError:If it is not possible to remove the bridge - domain. - """ - - path = ("bridge-domains", ("bridge-domain", "name", bd_name)) - - status_code, resp = HcUtil.\ - get_honeycomb_data(node, "config_bridge_domain") - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get configuration information about the " - "bridge domains. Status code: {0}.".format(status_code)) - - new_data = HcUtil.remove_item(resp, path) - status_code, resp = HcUtil.\ - put_honeycomb_data(node, "config_bridge_domain", new_data) - if status_code != HTTPCodes.OK: - raise HoneycombError("Not possible to remove bridge domain {0}. " - "Status code: {1}.". - format(bd_name, status_code)) - return resp - - @staticmethod - def configure_bridge_domain(node, bd_name, param, value): - """Configure a bridge domain. - - :param node: Honeycomb node. - :param bd_name: Bridge domain name. - :param param: Parameter to set, change or remove. The accepted - parameters are defined in BridgeDomainKeywords.PARAMS - :param value: The new value to be set, change or remove. If None, the - item will be removed. - :type node: dict - :type bd_name: str - :type param: str - :type value: str - :return: Content of response. - :rtype: bytearray - """ - - if param not in BridgeDomainKeywords.PARAMS: - raise HoneycombError("The parameter {0} is invalid.".format(param)) - - path = ("bridge-domains", ("bridge-domain", "name", bd_name), param) - return BridgeDomainKeywords.\ - _set_bd_properties(node, bd_name, path, value) diff --git a/resources/libraries/python/HcAPIKwInterfaces.py b/resources/libraries/python/HcAPIKwInterfaces.py deleted file mode 100644 index ccdb5ddefd..0000000000 --- a/resources/libraries/python/HcAPIKwInterfaces.py +++ /dev/null @@ -1,712 +0,0 @@ -# Copyright (c) 2016 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. - -"""Keywords to manipulate interface configuration using Honeycomb REST API. - -The keywords make possible to put and get configuration data and to get -operational data. -""" - - -from resources.libraries.python.HTTPRequest import HTTPCodes -from resources.libraries.python.HoneycombSetup import HoneycombError -from resources.libraries.python.HoneycombUtil import HoneycombUtil as HcUtil -from resources.libraries.python.HoneycombUtil import DataRepresentation - - -class InterfaceKeywords(object): - """Keywords for Interface manipulation. - - Implements keywords which get configuration and operational data about - vpp interfaces and set the interface's parameters using Honeycomb REST API. - """ - - INTF_PARAMS = ("name", "description", "type", "enabled", - "link-up-down-trap-enable") - IPV4_PARAMS = ("enabled", "forwarding", "mtu") - IPV6_PARAMS = ("enabled", "forwarding", "mtu", "dup-addr-detect-transmits") - IPV6_AUTOCONF_PARAMS = ("create-global-addresses", - "create-temporary-addresses", - "temporary-valid-lifetime", - "temporary-preferred-lifetime") - ETH_PARAMS = ("mtu", ) - ROUTING_PARAMS = ("vrf-id", ) - VXLAN_PARAMS = ("src", "dst", "vni", "encap-vrf-id") - L2_PARAMS = ("bridge-domain", "split-horizon-group", - "bridged-virtual-interface") - - def __init__(self): - pass - - @staticmethod - def _configure_interface(node, interface, data, - data_representation=DataRepresentation.JSON): - """Send interface configuration data and check the response. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param data: Configuration data to be sent in PUT request. - :param data_representation: How the data is represented. - :type node: dict - :type interface: str - :type data: dict - :type data_representation: DataRepresentation - :return: Content of response. - :rtype: bytearray - :raises HoneycombError: If the status code in response on PUT is not - 200 = OK. - """ - - status_code, resp = HcUtil.\ - put_honeycomb_data(node, "config_vpp_interfaces", data, - data_representation=data_representation) - if status_code != HTTPCodes.OK: - raise HoneycombError( - "The configuration of interface '{0}' was not successful. " - "Status code: {1}.".format(interface, status_code)) - return resp - - @staticmethod - def get_all_interfaces_cfg_data(node): - """Get configuration data about all interfaces from Honeycomb. - - :param node: Honeycomb node. - :type node: dict - :return: Configuration data about all interfaces from Honeycomb. - :rtype: list - :raises HoneycombError: If it is not possible to get configuration data. - """ - - status_code, resp = HcUtil.\ - get_honeycomb_data(node, "config_vpp_interfaces") - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get configuration information about the " - "interfaces. Status code: {0}.".format(status_code)) - try: - return resp["interfaces"]["interface"] - - except (KeyError, TypeError): - return [] - - @staticmethod - def get_interface_cfg_data(node, interface): - """Get configuration data about the given interface from Honeycomb. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :return: Configuration data about the given interface from Honeycomb. - :rtype: dict - """ - - intfs = InterfaceKeywords.get_all_interfaces_cfg_data(node) - for intf in intfs: - if intf["name"] == interface: - return intf - return {} - - @staticmethod - def get_all_interfaces_oper_data(node): - """Get operational data about all interfaces from Honeycomb. - - :param node: Honeycomb node. - :type node: dict - :return: Operational data about all interfaces from Honeycomb. - :rtype: list - :raises HoneycombError: If it is not possible to get operational data. - """ - - status_code, resp = HcUtil.\ - get_honeycomb_data(node, "oper_vpp_interfaces") - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get operational information about the " - "interfaces. Status code: {0}.".format(status_code)) - try: - return resp["interfaces-state"]["interface"] - - except (KeyError, TypeError): - return [] - - @staticmethod - def get_interface_oper_data(node, interface): - """Get operational data about the given interface from Honeycomb. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :return: Operational data about the given interface from Honeycomb. - :rtype: dict - """ - - intfs = InterfaceKeywords.get_all_interfaces_oper_data(node) - for intf in intfs: - if intf["name"] == interface: - return intf - return {} - - @staticmethod - def _set_interface_properties(node, interface, path, new_value=None): - """Set interface properties. - - This method reads interface configuration data, creates, changes or - removes the requested data and puts it back to Honeycomb. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param path: Path to data we want to change / create / remove. - :param new_value: The new value to be set. If None, the item will be - removed. - :type node: dict - :type interface: str - :type path: tuple - :type new_value: str, dict or list - :return: Content of response. - :rtype: bytearray - :raises HoneycombError: If it is not possible to get or set the data. - """ - - status_code, resp = HcUtil.\ - get_honeycomb_data(node, "config_vpp_interfaces") - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get configuration information about the " - "interfaces. Status code: {0}.".format(status_code)) - - if new_value: - new_data = HcUtil.set_item_value(resp, path, new_value) - else: - new_data = HcUtil.remove_item(resp, path) - return InterfaceKeywords._configure_interface(node, interface, new_data) - - @staticmethod - def set_interface_state(node, interface, state="up"): - """Set VPP interface state. - - The keyword changes the administration state of interface to up or down - depending on the parameter "state". - - :param node: Honeycomb node. - :param interface: The name of interface. - :param state: The requested state, only "up" and "down" are valid - values. - :type node: dict - :type interface: str - :type state: str - :return: Content of response. - :rtype: bytearray - :raises KeyError: If the argument "state" is nor "up" or "down". - :raises HoneycombError: If the interface is not present on the node. - """ - - intf_state = {"up": "true", - "down": "false"} - - path = ("interfaces", ("interface", "name", str(interface)), "enabled") - return InterfaceKeywords._set_interface_properties( - node, interface, path, intf_state[state.lower()]) - - @staticmethod - def set_interface_up(node, interface): - """Set the administration state of VPP interface to up. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :return: Content of response - :rtype: bytearray - """ - - return InterfaceKeywords.set_interface_state(node, interface, "up") - - @staticmethod - def set_interface_down(node, interface): - """Set the administration state of VPP interface to down. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :return: Content of response. - :rtype: bytearray - """ - - return InterfaceKeywords.set_interface_state(node, interface, "down") - - @staticmethod - def add_bridge_domain_to_interface(node, interface, bd_name, - split_horizon_group=None, bvi=None): - """Add a new bridge domain to an interface and set its parameters. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param bd_name: Bridge domain name. - :param split_horizon_group: Split-horizon group name. - :param bvi: The bridged virtual interface. - :type node: dict - :type interface: str - :type bd_name: str - :type split_horizon_group: str - :type bvi: str - :return: Content of response. - :rtype: bytearray - :raises HoneycombError: If the interface is not present on the node. - """ - - v3po_l2 = {"bridge-domain": str(bd_name)} - if split_horizon_group: - v3po_l2["split-horizon-group"] = str(split_horizon_group) - if bvi: - v3po_l2["bridged-virtual-interface"] = str(bvi) - - path = ("interfaces", ("interface", "name", str(interface)), "v3po:l2") - - return InterfaceKeywords._set_interface_properties( - node, interface, path, v3po_l2) - - @staticmethod - def configure_interface_base(node, interface, param, value): - """Configure the base parameters of interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param param: Parameter to configure (set, change, remove) - :param value: The value of parameter. If None, the parameter will be - removed. - :type node: dict - :type interface: str - :type param: str - :type value: str - :return: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - if param not in InterfaceKeywords.INTF_PARAMS: - raise HoneycombError("The parameter {0} is invalid.".format(param)) - - path = ("interfaces", ("interface", "name", interface), param) - return InterfaceKeywords._set_interface_properties( - node, interface, path, value) - - @staticmethod - def configure_interface_ipv4(node, interface, param, value): - """Configure IPv4 parameters of interface - - :param node: Honeycomb node. - :param interface: The name of interface. - :param param: Parameter to configure (set, change, remove) - :param value: The value of parameter. If None, the parameter will be - removed. - :type node: dict - :type interface: str - :type param: str - :type value: str - :return: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - if param not in InterfaceKeywords.IPV4_PARAMS: - raise HoneycombError("The parameter {0} is invalid.".format(param)) - - path = ("interfaces", ("interface", "name", interface), - "ietf-ip:ipv4", param) - return InterfaceKeywords._set_interface_properties( - node, interface, path, value) - - @staticmethod - def add_first_ipv4_address(node, interface, ip_addr, netmask): - """Add the first IPv4 address. - - If there are any other addresses configured, they will be removed. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param ip_addr: IPv4 address to be set. - :param netmask: Netmask. - :type node: dict - :type interface: str - :type ip_addr: str - :type netmask: str - :return: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4") - address = {"address": [{"ip": ip_addr, "netmask": netmask}, ]} - return InterfaceKeywords._set_interface_properties( - node, interface, path, address) - - @staticmethod - def add_ipv4_address(node, interface, ip_addr, netmask): - """Add IPv4 address. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param ip_addr: IPv4 address to be set. - :param netmask: Netmask. - :type node: dict - :type interface: str - :type ip_addr: str - :type netmask: str - :return: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4", - "address") - address = [{"ip": ip_addr, "prefix-length": netmask}, ] - return InterfaceKeywords._set_interface_properties( - node, interface, path, address) - - @staticmethod - def remove_all_ipv4_addresses(node, interface): - """Remove all IPv4 addresses from interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :return: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4", - "address") - return InterfaceKeywords._set_interface_properties( - node, interface, path, None) - - @staticmethod - def add_first_ipv4_neighbor(node, interface, ip_addr, link_layer_address): - """Add the first IPv4 neighbour. - - If there are any other neighbours configured, they will be removed. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param ip_addr: IPv4 address of neighbour to be set. - :param link_layer_address: Link layer address. - :type node: dict - :type interface: str - :type ip_addr: str - :type link_layer_address: str - :return: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4") - neighbor = {"neighbor": [{"ip": ip_addr, - "link-layer-address": link_layer_address}, ]} - return InterfaceKeywords._set_interface_properties( - node, interface, path, neighbor) - - @staticmethod - def add_ipv4_neighbor(node, interface, ip_addr, link_layer_address): - """Add the IPv4 neighbour. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param ip_addr: IPv4 address of neighbour to be set. - :param link_layer_address: Link layer address. - :type node: dict - :type interface: str - :type ip_addr: str - :type link_layer_address: str - :return: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4", - "neighbor") - neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ] - return InterfaceKeywords._set_interface_properties( - node, interface, path, neighbor) - - @staticmethod - def remove_all_ipv4_neighbors(node, interface): - """Remove all IPv4 neighbours. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :return: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4", - "neighbor") - return InterfaceKeywords._set_interface_properties( - node, interface, path, None) - - @staticmethod - def configure_interface_ipv6(node, interface, param, value): - """Configure IPv6 parameters of interface - - :param node: Honeycomb node. - :param interface: The name of interface. - :param param: Parameter to configure (set, change, remove) - :param value: The value of parameter. If None, the parameter will be - removed. - :type node: dict - :type interface: str - :type param: str - :type value: str - :return: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - if param in InterfaceKeywords.IPV6_PARAMS: - path = ("interfaces", ("interface", "name", interface), - "ietf-ip:ipv6", param) - elif param in InterfaceKeywords.IPV6_AUTOCONF_PARAMS: - path = ("interfaces", ("interface", "name", interface), - "ietf-ip:ipv6", "autoconf", param) - else: - raise HoneycombError("The parameter {0} is invalid.".format(param)) - - return InterfaceKeywords._set_interface_properties( - node, interface, path, value) - - @staticmethod - def add_first_ipv6_address(node, interface, ip_addr, prefix_len): - """Add the first IPv6 address. - - If there are any other addresses configured, they will be removed. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param ip_addr: IPv6 address to be set. - :param prefix_len: Prefix length. - :type node: dict - :type interface: str - :type ip_addr: str - :type prefix_len: str - :return: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6") - address = {"address": [{"ip": ip_addr, "prefix-length": prefix_len}, ]} - return InterfaceKeywords._set_interface_properties( - node, interface, path, address) - - @staticmethod - def add_ipv6_address(node, interface, ip_addr, prefix_len): - """Add IPv6 address. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param ip_addr: IPv6 address to be set. - :param prefix_len: Prefix length. - :type node: dict - :type interface: str - :type ip_addr: str - :type prefix_len: str - :return: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6", - "address") - address = [{"ip": ip_addr, "prefix-length": prefix_len}, ] - return InterfaceKeywords._set_interface_properties( - node, interface, path, address) - - @staticmethod - def remove_all_ipv6_addresses(node, interface): - """Remove all IPv6 addresses from interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :return: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6", - "address") - return InterfaceKeywords._set_interface_properties( - node, interface, path, None) - - @staticmethod - def add_first_ipv6_neighbor(node, interface, ip_addr, link_layer_address): - """Add the first IPv6 neighbour. - - If there are any other neighbours configured, they will be removed. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param ip_addr: IPv6 address of neighbour to be set. - :param link_layer_address: Link layer address. - :type node: dict - :type interface: str - :type ip_addr: str - :type link_layer_address: str - :return: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6") - neighbor = {"neighbor": [{"ip": ip_addr, - "link-layer-address": link_layer_address}, ]} - return InterfaceKeywords._set_interface_properties( - node, interface, path, neighbor) - - @staticmethod - def add_ipv6_neighbor(node, interface, ip_addr, link_layer_address): - """Add the IPv6 neighbour. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param ip_addr: IPv6 address of neighbour to be set. - :param link_layer_address: Link layer address. - :type node: dict - :type interface: str - :type ip_addr: str - :type link_layer_address: str - :return: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6", - "neighbor") - neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ] - return InterfaceKeywords._set_interface_properties( - node, interface, path, neighbor) - - @staticmethod - def remove_all_ipv6_neighbors(node, interface): - """Remove all IPv6 neighbours. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :return: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6", - "neighbor") - return InterfaceKeywords._set_interface_properties( - node, interface, path, None) - - @staticmethod - def configure_interface_ethernet(node, interface, param, value): - """Configure the ethernet parameters of interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param param: Parameter to configure (set, change, remove) - :param value: The value of parameter. If None, the parameter will be - removed. - :type node: dict - :type interface: str - :type param: str - :type value: str - :return: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - if param not in InterfaceKeywords.ETH_PARAMS: - raise HoneycombError("The parameter {0} is invalid.".format(param)) - path = ("interfaces", ("interface", "name", interface), "v3po:ethernet", - param) - return InterfaceKeywords._set_interface_properties( - node, interface, path, value) - - @staticmethod - def configure_interface_routing(node, interface, param, value): - """Configure the routing parameters of interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param param: Parameter to configure (set, change, remove) - :param value: The value of parameter. If None, the parameter will be - removed. - :type node: dict - :type interface: str - :type param: str - :type value: str - :return: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - if param not in InterfaceKeywords.ROUTING_PARAMS: - raise HoneycombError("The parameter {0} is invalid.".format(param)) - - path = ("interfaces", ("interface", "name", interface), "v3po:routing", - param) - return InterfaceKeywords._set_interface_properties( - node, interface, path, value) - - @staticmethod - def configure_interface_vxlan(node, interface, param, value): - """Configure the VxLAN parameters of interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param param: Parameter to configure (set, change, remove) - :param value: The value of parameter. If None, the parameter will be - removed. - :type node: dict - :type interface: str - :type param: str - :type value: str - :return: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - if param not in InterfaceKeywords.VXLAN_PARAMS: - raise HoneycombError("The parameter {0} is invalid.".format(param)) - - path = ("interfaces", ("interface", "name", interface), "v3po:vxlan", - param) - return InterfaceKeywords._set_interface_properties( - node, interface, path, value) - - @staticmethod - def configure_interface_l2(node, interface, param, value): - """Configure the L2 parameters of interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param param: Parameter to configure (set, change, remove) - :param value: The value of parameter. If None, the parameter will be - removed. - :type node: dict - :type interface: str - :type param: str - :type value: str - :return: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - if param not in InterfaceKeywords.L2_PARAMS: - raise HoneycombError("The parameter {0} is invalid.".format(param)) - path = ("interfaces", ("interface", "name", interface), "v3po:l2", - param) - return InterfaceKeywords._set_interface_properties( - node, interface, path, value) diff --git a/resources/libraries/python/HoneycombSetup.py b/resources/libraries/python/HoneycombSetup.py deleted file mode 100644 index 979b501522..0000000000 --- a/resources/libraries/python/HoneycombSetup.py +++ /dev/null @@ -1,186 +0,0 @@ -# Copyright (c) 2016 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. - -"""Implementation of keywords for Honeycomb setup.""" - -from robot.api import logger - -from resources.libraries.python.topology import NodeType -from resources.libraries.python.ssh import SSH -from resources.libraries.python.HTTPRequest import HTTPRequest, HTTPCodes, \ - HTTPRequestError -from resources.libraries.python.HoneycombUtil import HoneycombUtil as HcUtil -from resources.libraries.python.HoneycombUtil import HoneycombError -from resources.libraries.python.constants import Constants as Const - - -class HoneycombSetup(object): - """Implements keywords for Honeycomb setup. - - The keywords implemented in this class make possible to: - - start Honeycomb, - - stop Honeycomb, - - check the Honeycomb start-up state, - - check the Honeycomb shutdown state, - - add VPP to the topology. - """ - - def __init__(self): - pass - - @staticmethod - def start_honeycomb_on_duts(*nodes): - """Start Honeycomb on specified DUT nodes. - - This keyword starts the Honeycomb service on specified DUTs. - The keyword just starts the Honeycomb and does not check its startup - state. Use the keyword "Check Honeycomb Startup State" to check if the - Honeycomb is up and running. - Honeycomb must be installed in "/opt" directory, otherwise the start - will fail. - :param nodes: List of nodes to start Honeycomb on. - :type nodes: list - :raises HoneycombError: If Honeycomb fails to start. - """ - logger.console("Starting Honeycomb service ...") - - cmd = "{0}/start".format(Const.REMOTE_HC_DIR) - - for node in nodes: - if node['type'] == NodeType.DUT: - ssh = SSH() - ssh.connect(node) - (ret_code, _, _) = ssh.exec_command_sudo(cmd) - if int(ret_code) != 0: - raise HoneycombError('Node {0} failed to start Honeycomb.'. - format(node['host'])) - else: - logger.info("Starting the Honeycomb service on node {0} is " - "in progress ...".format(node['host'])) - - @staticmethod - def stop_honeycomb_on_duts(*nodes): - """Stop the Honeycomb service on specified DUT nodes. - - This keyword stops the Honeycomb service on specified nodes. It just - stops the Honeycomb and does not check its shutdown state. Use the - keyword "Check Honeycomb Shutdown State" to check if Honeycomb has - stopped. - :param nodes: List of nodes to stop Honeycomb on. - :type nodes: list - :raises HoneycombError: If Honeycomb failed to stop. - """ - logger.console("Shutting down Honeycomb service ...") - - cmd = "{0}/stop".format(Const.REMOTE_HC_DIR) - errors = [] - - for node in nodes: - if node['type'] == NodeType.DUT: - ssh = SSH() - ssh.connect(node) - (ret_code, _, _) = ssh.exec_command_sudo(cmd) - if int(ret_code) != 0: - errors.append(node['host']) - else: - logger.info("Stopping the Honeycomb service on node {0} is " - "in progress ...".format(node['host'])) - if errors: - raise HoneycombError('Node(s) {0} failed to stop Honeycomb.'. - format(errors)) - - @staticmethod - def check_honeycomb_startup_state(*nodes): - """Check state of Honeycomb service during startup on specified nodes. - - Reads html path from template file oper_vpp_version.url. - - Honeycomb nodes reply with connection refused or the following status - codes depending on startup progress: codes 200, 401, 403, 404, 500, 503 - - :param nodes: List of DUT nodes starting Honeycomb. - :type nodes: list - :return: True if all GETs returned code 200(OK). - :rtype bool - """ - path = HcUtil.read_path_from_url_file("oper_vpp_version") - expected_status_codes = (HTTPCodes.UNAUTHORIZED, - HTTPCodes.FORBIDDEN, - HTTPCodes.NOT_FOUND, - HTTPCodes.SERVICE_UNAVAILABLE, - HTTPCodes.INTERNAL_SERVER_ERROR) - - for node in nodes: - if node['type'] == NodeType.DUT: - status_code, _ = HTTPRequest.get(node, path, timeout=10, - enable_logging=False) - if status_code == HTTPCodes.OK: - logger.info("Honeycomb on node {0} is up and running". - format(node['host'])) - elif status_code in expected_status_codes: - if status_code == HTTPCodes.UNAUTHORIZED: - logger.info('Unauthorized. If this triggers keyword ' - 'timeout, verify Honeycomb username and ' - 'password.') - raise HoneycombError('Honeycomb on node {0} running but ' - 'not yet ready.'.format(node['host']), - enable_logging=False) - else: - raise HoneycombError('Unexpected return code: {0}.'. - format(status_code)) - return True - - @staticmethod - def check_honeycomb_shutdown_state(*nodes): - """Check state of Honeycomb service during shutdown on specified nodes. - - Honeycomb nodes reply with connection refused or the following status - codes depending on shutdown progress: codes 200, 404. - - :param nodes: List of DUT nodes stopping Honeycomb. - :type nodes: list - :return: True if all GETs fail to connect. - :rtype bool - """ - cmd = "ps -ef | grep -v grep | grep karaf" - for node in nodes: - if node['type'] == NodeType.DUT: - try: - status_code, _ = HTTPRequest.get(node, '/index.html', - timeout=5, - enable_logging=False) - if status_code == HTTPCodes.OK: - raise HoneycombError('Honeycomb on node {0} is still ' - 'running.'.format(node['host']), - enable_logging=False) - elif status_code == HTTPCodes.NOT_FOUND: - raise HoneycombError('Honeycomb on node {0} is shutting' - ' down.'.format(node['host']), - enable_logging=False) - else: - raise HoneycombError('Unexpected return code: {0}.'. - format(status_code)) - except HTTPRequestError: - logger.debug('Connection refused, checking the process ' - 'state ...') - ssh = SSH() - ssh.connect(node) - (ret_code, _, _) = ssh.exec_command_sudo(cmd) - if ret_code == 0: - raise HoneycombError('Honeycomb on node {0} is still ' - 'running.'.format(node['host']), - enable_logging=False) - else: - logger.info("Honeycomb on node {0} has stopped". - format(node['host'])) - return True diff --git a/resources/libraries/python/HoneycombUtil.py b/resources/libraries/python/HoneycombUtil.py deleted file mode 100644 index 644cf62c43..0000000000 --- a/resources/libraries/python/HoneycombUtil.py +++ /dev/null @@ -1,387 +0,0 @@ -# Copyright (c) 2016 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. - -"""Implementation of low level functionality used in communication with -Honeycomb. - -Exception HoneycombError is used in all methods and in all modules with -Honeycomb keywords. - -Class HoneycombUtil implements methods used by Honeycomb keywords. They must not -be used directly in tests. Use keywords implemented in the module -HoneycombAPIKeywords instead. -""" - -from json import loads, dumps -from enum import Enum, unique - -from robot.api import logger - -from resources.libraries.python.HTTPRequest import HTTPRequest -from resources.libraries.python.constants import Constants as Const - - -@unique -class DataRepresentation(Enum): - """Representation of data sent by PUT and POST requests.""" - NO_DATA = 0 - JSON = 1 - XML = 2 - TXT = 3 - - -# Headers used in requests. Key - content representation, value - header. -HEADERS = {DataRepresentation.NO_DATA: - {}, # It must be empty dictionary. - DataRepresentation.JSON: - {"Content-Type": "application/json", - "Accept": "text/plain"}, - DataRepresentation.XML: - {"Content-Type": "application/xml", - "Accept": "text/plain"}, - DataRepresentation.TXT: - {"Content-Type": "text/plain", - "Accept": "text/plain"} - } - - -class HoneycombError(Exception): - - """Exception(s) raised by methods working with Honeycomb. - - When raising this exception, put this information to the message in this - order: - - short description of the encountered problem (parameter msg), - - relevant messages if there are any collected, e.g., from caught - exception (optional parameter details), - - relevant data if there are any collected (optional parameter details). - The logging is performed on two levels: 1. error - short description of the - problem; 2. debug - detailed information. - """ - - def __init__(self, msg, details='', enable_logging=True): - """Sets the exception message and enables / disables logging. - - It is not wanted to log errors when using these keywords together - with keywords like "Wait until keyword succeeds". So you can disable - logging by setting enable_logging to False. - - :param msg: Message to be displayed and logged. - :param enable_logging: When True, logging is enabled, otherwise - logging is disabled. - :type msg: str - :type enable_logging: bool - """ - super(HoneycombError, self).__init__() - self._msg = "{0}: {1}".format(self.__class__.__name__, msg) - self._details = details - if enable_logging: - logger.error(self._msg) - logger.debug(self._details) - - def __repr__(self): - return repr(self._msg) - - def __str__(self): - return str(self._msg) - - -class HoneycombUtil(object): - """Implements low level functionality used in communication with Honeycomb. - - There are implemented methods to get, put and delete data to/from Honeycomb. - They are based on functionality implemented in the module HTTPRequests which - uses HTTP requests GET, PUT, POST and DELETE to communicate with Honeycomb. - - It is possible to PUT the data represented as XML or JSON structures or as - plain text. - Data received in the response of GET are always represented as a JSON - structure. - - There are also two supportive methods implemented: - - read_path_from_url_file which reads URL file and returns a path (see - docs/honeycomb_url_files.rst). - - parse_json_response which parses data from response in JSON representation - according to given path. - """ - - def __init__(self): - pass - - @staticmethod - def read_path_from_url_file(url_file): - """Read path from *.url file. - - For more information about *.url file see docs/honeycomb_url_files.rst - :param url_file: URL file. The argument contains only the name of file - without extension, not the full path. - :type url_file: str - :return: Requested path. - :rtype: str - """ - - url_file = "{0}/{1}.url".format(Const.RESOURCES_TPL_HC, url_file) - with open(url_file) as template: - path = template.readline() - return path - - @staticmethod - def find_item(data, path): - """Find a data item (single leaf or sub-tree) in data received from - Honeycomb REST API. - - Path format: - The path is a tuple with items navigating to requested data. The items - can be strings or tuples: - - string item represents a dictionary key in data, - - tuple item represents list item in data. - - Example: - data = \ - { - "interfaces": { - "interface": [ - { - "name": "GigabitEthernet0/8/0", - "enabled": "true", - "type": "iana-if-type:ethernetCsmacd", - }, - { - "name": "local0", - "enabled": "false", - "type": "iana-if-type:ethernetCsmacd", - } - ] - } - } - - path = ("interfaces", ("interface", "name", "local0"), "enabled") - This path points to "false". - - The tuple ("interface", "name", "local0") consists of: - index 0 - dictionary key pointing to a list, - index 1 - key which identifies an item in the list, it is also marked as - the key in corresponding yang file. - index 2 - key value. - - :param data: Data received from Honeycomb REST API. - :param path: Path to data we want to find. - :type data: dict - :type path: tuple - :return: Data represented by path. - :rtype: str, dict, or list - :raises HoneycombError: If the data has not been found. - """ - - for path_item in path: - try: - if isinstance(path_item, str): - data = data[path_item] - elif isinstance(path_item, tuple): - for data_item in data[path_item[0]]: - if data_item[path_item[1]] == path_item[2]: - data = data_item - except KeyError as err: - raise HoneycombError("Data not found: {0}".format(err)) - - return data - - @staticmethod - def remove_item(data, path): - """Remove a data item (single leaf or sub-tree) in data received from - Honeycomb REST API. - - :param data: Data received from Honeycomb REST API. - :param path: Path to data we want to remove. - :type data: dict - :type path: tuple - :return: Original data without removed part. - :rtype: dict - """ - - origin_data = previous_data = data - try: - for path_item in path: - previous_data = data - if isinstance(path_item, str): - data = data[path_item] - elif isinstance(path_item, tuple): - for data_item in data[path_item[0]]: - if data_item[path_item[1]] == path_item[2]: - data = data_item - except KeyError as err: - logger.debug("Data not found: {0}".format(err)) - return origin_data - - if isinstance(path[-1], str): - previous_data.pop(path[-1]) - elif isinstance(path[-1], tuple): - previous_data[path[-1][0]].remove(data) - if not previous_data[path[-1][0]]: - previous_data.pop(path[-1][0]) - - return origin_data - - @staticmethod - def set_item_value(data, path, new_value): - """Set or change the value (single leaf or sub-tree) in data received - from Honeycomb REST API. - - If the item is not present in the data structure, it is created. - - :param data: Data received from Honeycomb REST API. - :param path: Path to data we want to change or create. - :param new_value: The value to be set. - :type data: dict - :type path: tuple - :type new_value: str, dict or list - :return: Original data with the new value. - :rtype: dict - """ - - origin_data = data - for path_item in path[:-1]: - if isinstance(path_item, str): - try: - data = data[path_item] - except KeyError: - data[path_item] = {} - data = data[path_item] - elif isinstance(path_item, tuple): - try: - flag = False - index = 0 - for data_item in data[path_item[0]]: - if data_item[path_item[1]] == path_item[2]: - data = data[path_item[0]][index] - flag = True - break - index += 1 - if not flag: - data[path_item[0]].append({path_item[1]: path_item[2]}) - data = data[path_item[0]][-1] - except KeyError: - data[path_item] = [] - - if not path[-1] in data.keys(): - data[path[-1]] = {} - - if isinstance(new_value, list) and isinstance(data[path[-1]], list): - for value in new_value: - data[path[-1]].append(value) - else: - data[path[-1]] = new_value - - return origin_data - - @staticmethod - def get_honeycomb_data(node, url_file): - """Retrieve data from Honeycomb according to given URL. - - :param node: Honeycomb node. - :param url_file: URL file. The argument contains only the name of file - without extension, not the full path. - :type node: dict - :type url_file: str - :return: Status code and content of response. - :rtype tuple - """ - - path = HoneycombUtil.read_path_from_url_file(url_file) - status_code, resp = HTTPRequest.get(node, path) - return status_code, loads(resp) - - @staticmethod - def put_honeycomb_data(node, url_file, data, - data_representation=DataRepresentation.JSON): - """Send configuration data using PUT request and return the status code - and response content. - - :param node: Honeycomb node. - :param url_file: URL file. The argument contains only the name of file - without extension, not the full path. - :param data: Configuration data to be sent to Honeycomb. - :param data_representation: How the data is represented. - :type node: dict - :type url_file: str - :type data: dict, str - :type data_representation: DataRepresentation - :return: Status code and content of response. - :rtype: tuple - :raises HoneycombError: If the given data representation is not defined - in HEADERS. - """ - - try: - header = HEADERS[data_representation] - except AttributeError as err: - raise HoneycombError("Wrong data representation: {0}.". - format(data_representation), repr(err)) - if data_representation == DataRepresentation.JSON: - data = dumps(data) - - path = HoneycombUtil.read_path_from_url_file(url_file) - return HTTPRequest.put(node=node, path=path, headers=header, - payload=data) - - @staticmethod - def post_honeycomb_data(node, url_file, data=None, - data_representation=DataRepresentation.JSON, - timeout=10): - """Send a POST request and return the status code and response content. - - :param node: Honeycomb node. - :param url_file: URL file. The argument contains only the name of file - without extension, not the full path. - :param data: Configuration data to be sent to Honeycomb. - :param data_representation: How the data is represented. - :param timeout: How long to wait for the server to send data before - giving up. - :type node: dict - :type url_file: str - :type data: dict, str - :type data_representation: DataRepresentation - :type timeout: int - :return: Status code and content of response. - :rtype: tuple - :raises HoneycombError: If the given data representation is not defined - in HEADERS. - """ - - try: - header = HEADERS[data_representation] - except AttributeError as err: - raise HoneycombError("Wrong data representation: {0}.". - format(data_representation), repr(err)) - if data_representation == DataRepresentation.JSON: - data = dumps(data) - - path = HoneycombUtil.read_path_from_url_file(url_file) - return HTTPRequest.post(node=node, path=path, headers=header, - payload=data, timeout=timeout) - - @staticmethod - def delete_honeycomb_data(node, url_file): - """Delete data from Honeycomb according to given URL. - - :param node: Honeycomb node. - :param url_file: URL file. The argument contains only the name of file - without extension, not the full path. - :type node: dict - :type url_file: str - :return: Status code and content of response. - :rtype tuple - """ - - path = HoneycombUtil.read_path_from_url_file(url_file) - return HTTPRequest.delete(node, path) diff --git a/resources/libraries/python/honeycomb/HcAPIKwBridgeDomain.py b/resources/libraries/python/honeycomb/HcAPIKwBridgeDomain.py new file mode 100644 index 0000000000..0906d5c762 --- /dev/null +++ b/resources/libraries/python/honeycomb/HcAPIKwBridgeDomain.py @@ -0,0 +1,330 @@ +# Copyright (c) 2016 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. + +"""Keywords to manipulate bridge domain configuration using Honeycomb REST API. + +The keywords make possible to put and get configuration data and to get +operational data. +""" + +from resources.libraries.python.HTTPRequest import HTTPCodes +from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError +from resources.libraries.python.honeycomb.HoneycombUtil \ + import DataRepresentation +from resources.libraries.python.honeycomb.HoneycombUtil \ + import HoneycombUtil as HcUtil + + +class BridgeDomainKeywords(object): + """Keywords to manipulate bridge domain configuration. + + Implements keywords which get configuration and operational data about + bridge domains and put the bridge domains' parameters using Honeycomb REST + API. + """ + + PARAMS = ("flood", "forward", "learn", "unknown-unicast-flood", + "arp-termination") + + def __init__(self): + pass + + @staticmethod + def _configure_bd(node, bd_name, data, + data_representation=DataRepresentation.JSON): + """Send bridge domain configuration data and check the response. + + :param node: Honeycomb node. + :param bd_name: The name of bridge domain. + :param data: Configuration data to be sent in PUT request. + :param data_representation: How the data is represented. + :type node: dict + :type bd_name: str + :type data: dict + :type data_representation: DataRepresentation + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If the status code in response on PUT is not + 200 = OK. + """ + + status_code, resp = HcUtil.\ + put_honeycomb_data(node, "config_bridge_domain", data, + data_representation=data_representation) + if status_code != HTTPCodes.OK: + raise HoneycombError( + "The configuration of bridge domain '{0}' was not successful. " + "Status code: {1}.".format(bd_name, status_code)) + return resp + + @staticmethod + def _set_bd_properties(node, bd_name, path, new_value=None): + """Set bridge domain properties. + + This method reads bridge domain configuration data, creates, changes or + removes the requested data and puts it back to Honeycomb. + + :param node: Honeycomb node. + :param bd_name: The name of bridge domain. + :param path: Path to data we want to change, create or remove. + :param new_value: The new value to be set. If None, the item will be + removed. + :type node: dict + :type bd_name: str + :type path: tuple + :type new_value: str, dict or list + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If it is not possible to get or set the data. + """ + + status_code, resp = HcUtil.\ + get_honeycomb_data(node, "config_bridge_domain") + if status_code != HTTPCodes.OK: + raise HoneycombError( + "Not possible to get configuration information about the " + "bridge domains. Status code: {0}.".format(status_code)) + + if new_value: + new_data = HcUtil.set_item_value(resp, path, new_value) + else: + new_data = HcUtil.remove_item(resp, path) + return BridgeDomainKeywords._configure_bd(node, bd_name, new_data) + + @staticmethod + def _create_bd_structure(bd_name, **kwargs): + """Create the bridge domain data structure as it is expected by + Honeycomb REST API. + + :param bd_name: Bridge domain name. + :param kwargs: Parameters and their values. The accepted parameters are + defined in BridgeDomainKeywords.PARAMS. + :type bd_name: str + :type kwargs: dict + :return: Bridge domain data structure. + :rtype: dict + """ + + bd_structure = {"name": bd_name} + + for param, value in kwargs.items(): + if param not in BridgeDomainKeywords.PARAMS: + raise HoneycombError("The parameter {0} is invalid.". + format(param)) + bd_structure[param] = str(value) + + return bd_structure + + @staticmethod + def get_all_bds_cfg_data(node): + """Get configuration data about all bridge domains from Honeycomb. + + :param node: Honeycomb node. + :type node: dict + :return: Configuration data about all bridge domains from Honeycomb. + :rtype: list + :raises HoneycombError: If it is not possible to get configuration data. + """ + + status_code, resp = HcUtil.\ + get_honeycomb_data(node, "config_bridge_domain") + if status_code != HTTPCodes.OK: + raise HoneycombError( + "Not possible to get configuration information about the " + "bridge domains. Status code: {0}.".format(status_code)) + try: + return resp["bridge-domains"]["bridge-domain"] + + except (KeyError, TypeError): + return [] + + @staticmethod + def get_bd_cfg_data(node, bd_name): + """Get configuration data about the given bridge domain from Honeycomb. + + :param node: Honeycomb node. + :param bd_name: The name of bridge domain. + :type node: dict + :type bd_name: str + :return: Configuration data about the given bridge domain from + Honeycomb. + :rtype: dict + """ + + intfs = BridgeDomainKeywords.get_all_bds_cfg_data(node) + for intf in intfs: + if intf["name"] == bd_name: + return intf + return {} + + @staticmethod + def get_all_bds_oper_data(node): + """Get operational data about all bridge domains from Honeycomb. + + :param node: Honeycomb node. + :type node: dict + :return: Operational data about all bridge domains from Honeycomb. + :rtype: list + :raises HoneycombError: If it is not possible to get operational data. + """ + + status_code, resp = HcUtil.\ + get_honeycomb_data(node, "oper_bridge_domains") + if status_code != HTTPCodes.OK: + raise HoneycombError( + "Not possible to get operational information about the " + "bridge domains. Status code: {0}.".format(status_code)) + try: + return resp["bridge-domains"]["bridge-domain"] + + except (KeyError, TypeError): + return [] + + @staticmethod + def get_bd_oper_data(node, bd_name): + """Get operational data about the given bridge domain from Honeycomb. + + :param node: Honeycomb node. + :param bd_name: The name of bridge domain. + :type node: dict + :type bd_name: str + :return: Operational data about the given bridge domain from Honeycomb. + :rtype: dict + """ + + intfs = BridgeDomainKeywords.get_all_bds_oper_data(node) + for intf in intfs: + if intf["name"] == bd_name: + return intf + return {} + + @staticmethod + def add_first_bd(node, bd_name, **kwargs): + """Add the first bridge domain. + + If there are any other bridge domains configured, they will be removed. + + :param node: Honeycomb node. + :param bd_name: Bridge domain name. + :param kwargs: Parameters and their values. The accepted parameters are + defined in BridgeDomainKeywords.PARAMS + :type node: dict + :type bd_name: str + :type kwargs: dict + :return: Bridge domain data structure. + :rtype: dict + """ + + path = ("bridge-domains", ) + new_bd = BridgeDomainKeywords._create_bd_structure(bd_name, **kwargs) + bridge_domain = {"bridge-domain": [new_bd, ]} + return BridgeDomainKeywords._set_bd_properties(node, bd_name, path, + bridge_domain) + + @staticmethod + def add_bd(node, bd_name, **kwargs): + """Add a bridge domain. + + :param node: Honeycomb node. + :param bd_name: Bridge domain name. + :param kwargs: Parameters and their values. The accepted parameters are + defined in BridgeDomainKeywords.PARAMS + :type node: dict + :type bd_name: str + :type kwargs: dict + :return: Bridge domain data structure. + :rtype: dict + """ + + path = ("bridge-domains", "bridge-domain") + new_bd = BridgeDomainKeywords._create_bd_structure(bd_name, **kwargs) + bridge_domain = [new_bd, ] + return BridgeDomainKeywords._set_bd_properties(node, bd_name, path, + bridge_domain) + + @staticmethod + def remove_all_bds(node): + """Remove all bridge domains. + + :param node: Honeycomb node. + :type node: dict + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If it is not possible to remove all bridge + domains. + """ + + data = {"bridge-domains": {"bridge-domain": []}} + status_code, resp = HcUtil.\ + put_honeycomb_data(node, "config_bridge_domain", data) + if status_code != HTTPCodes.OK: + raise HoneycombError("Not possible to remove all bridge domains. " + "Status code: {0}.".format(status_code)) + return resp + + @staticmethod + def remove_bridge_domain(node, bd_name): + """Remove a bridge domain. + + :param node: Honeycomb node. + :param bd_name: The name of bridge domain to be removed. + :type node: dict + :type bd_name: str + :return: Content of response. + :rtype: bytearray + :raises HoneycombError:If it is not possible to remove the bridge + domain. + """ + + path = ("bridge-domains", ("bridge-domain", "name", bd_name)) + + status_code, resp = HcUtil.\ + get_honeycomb_data(node, "config_bridge_domain") + if status_code != HTTPCodes.OK: + raise HoneycombError( + "Not possible to get configuration information about the " + "bridge domains. Status code: {0}.".format(status_code)) + + new_data = HcUtil.remove_item(resp, path) + status_code, resp = HcUtil.\ + put_honeycomb_data(node, "config_bridge_domain", new_data) + if status_code != HTTPCodes.OK: + raise HoneycombError("Not possible to remove bridge domain {0}. " + "Status code: {1}.". + format(bd_name, status_code)) + return resp + + @staticmethod + def configure_bridge_domain(node, bd_name, param, value): + """Configure a bridge domain. + + :param node: Honeycomb node. + :param bd_name: Bridge domain name. + :param param: Parameter to set, change or remove. The accepted + parameters are defined in BridgeDomainKeywords.PARAMS + :param value: The new value to be set, change or remove. If None, the + item will be removed. + :type node: dict + :type bd_name: str + :type param: str + :type value: str + :return: Content of response. + :rtype: bytearray + """ + + if param not in BridgeDomainKeywords.PARAMS: + raise HoneycombError("The parameter {0} is invalid.".format(param)) + + path = ("bridge-domains", ("bridge-domain", "name", bd_name), param) + return BridgeDomainKeywords.\ + _set_bd_properties(node, bd_name, path, value) diff --git a/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py b/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py new file mode 100644 index 0000000000..8f6819ef5e --- /dev/null +++ b/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py @@ -0,0 +1,713 @@ +# Copyright (c) 2016 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. + +"""Keywords to manipulate interface configuration using Honeycomb REST API. + +The keywords make possible to put and get configuration data and to get +operational data. +""" + +from resources.libraries.python.HTTPRequest import HTTPCodes +from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError +from resources.libraries.python.honeycomb.HoneycombUtil \ + import DataRepresentation +from resources.libraries.python.honeycomb.HoneycombUtil \ + import HoneycombUtil as HcUtil + + +class InterfaceKeywords(object): + """Keywords for Interface manipulation. + + Implements keywords which get configuration and operational data about + vpp interfaces and set the interface's parameters using Honeycomb REST API. + """ + + INTF_PARAMS = ("name", "description", "type", "enabled", + "link-up-down-trap-enable") + IPV4_PARAMS = ("enabled", "forwarding", "mtu") + IPV6_PARAMS = ("enabled", "forwarding", "mtu", "dup-addr-detect-transmits") + IPV6_AUTOCONF_PARAMS = ("create-global-addresses", + "create-temporary-addresses", + "temporary-valid-lifetime", + "temporary-preferred-lifetime") + ETH_PARAMS = ("mtu", ) + ROUTING_PARAMS = ("vrf-id", ) + VXLAN_PARAMS = ("src", "dst", "vni", "encap-vrf-id") + L2_PARAMS = ("bridge-domain", "split-horizon-group", + "bridged-virtual-interface") + + def __init__(self): + pass + + @staticmethod + def _configure_interface(node, interface, data, + data_representation=DataRepresentation.JSON): + """Send interface configuration data and check the response. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param data: Configuration data to be sent in PUT request. + :param data_representation: How the data is represented. + :type node: dict + :type interface: str + :type data: dict + :type data_representation: DataRepresentation + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If the status code in response on PUT is not + 200 = OK. + """ + + status_code, resp = HcUtil.\ + put_honeycomb_data(node, "config_vpp_interfaces", data, + data_representation=data_representation) + if status_code != HTTPCodes.OK: + raise HoneycombError( + "The configuration of interface '{0}' was not successful. " + "Status code: {1}.".format(interface, status_code)) + return resp + + @staticmethod + def get_all_interfaces_cfg_data(node): + """Get configuration data about all interfaces from Honeycomb. + + :param node: Honeycomb node. + :type node: dict + :return: Configuration data about all interfaces from Honeycomb. + :rtype: list + :raises HoneycombError: If it is not possible to get configuration data. + """ + + status_code, resp = HcUtil.\ + get_honeycomb_data(node, "config_vpp_interfaces") + if status_code != HTTPCodes.OK: + raise HoneycombError( + "Not possible to get configuration information about the " + "interfaces. Status code: {0}.".format(status_code)) + try: + return resp["interfaces"]["interface"] + + except (KeyError, TypeError): + return [] + + @staticmethod + def get_interface_cfg_data(node, interface): + """Get configuration data about the given interface from Honeycomb. + + :param node: Honeycomb node. + :param interface: The name of interface. + :type node: dict + :type interface: str + :return: Configuration data about the given interface from Honeycomb. + :rtype: dict + """ + + intfs = InterfaceKeywords.get_all_interfaces_cfg_data(node) + for intf in intfs: + if intf["name"] == interface: + return intf + return {} + + @staticmethod + def get_all_interfaces_oper_data(node): + """Get operational data about all interfaces from Honeycomb. + + :param node: Honeycomb node. + :type node: dict + :return: Operational data about all interfaces from Honeycomb. + :rtype: list + :raises HoneycombError: If it is not possible to get operational data. + """ + + status_code, resp = HcUtil.\ + get_honeycomb_data(node, "oper_vpp_interfaces") + if status_code != HTTPCodes.OK: + raise HoneycombError( + "Not possible to get operational information about the " + "interfaces. Status code: {0}.".format(status_code)) + try: + return resp["interfaces-state"]["interface"] + + except (KeyError, TypeError): + return [] + + @staticmethod + def get_interface_oper_data(node, interface): + """Get operational data about the given interface from Honeycomb. + + :param node: Honeycomb node. + :param interface: The name of interface. + :type node: dict + :type interface: str + :return: Operational data about the given interface from Honeycomb. + :rtype: dict + """ + + intfs = InterfaceKeywords.get_all_interfaces_oper_data(node) + for intf in intfs: + if intf["name"] == interface: + return intf + return {} + + @staticmethod + def _set_interface_properties(node, interface, path, new_value=None): + """Set interface properties. + + This method reads interface configuration data, creates, changes or + removes the requested data and puts it back to Honeycomb. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param path: Path to data we want to change / create / remove. + :param new_value: The new value to be set. If None, the item will be + removed. + :type node: dict + :type interface: str + :type path: tuple + :type new_value: str, dict or list + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If it is not possible to get or set the data. + """ + + status_code, resp = HcUtil.\ + get_honeycomb_data(node, "config_vpp_interfaces") + if status_code != HTTPCodes.OK: + raise HoneycombError( + "Not possible to get configuration information about the " + "interfaces. Status code: {0}.".format(status_code)) + + if new_value: + new_data = HcUtil.set_item_value(resp, path, new_value) + else: + new_data = HcUtil.remove_item(resp, path) + return InterfaceKeywords._configure_interface(node, interface, new_data) + + @staticmethod + def set_interface_state(node, interface, state="up"): + """Set VPP interface state. + + The keyword changes the administration state of interface to up or down + depending on the parameter "state". + + :param node: Honeycomb node. + :param interface: The name of interface. + :param state: The requested state, only "up" and "down" are valid + values. + :type node: dict + :type interface: str + :type state: str + :return: Content of response. + :rtype: bytearray + :raises KeyError: If the argument "state" is nor "up" or "down". + :raises HoneycombError: If the interface is not present on the node. + """ + + intf_state = {"up": "true", + "down": "false"} + + path = ("interfaces", ("interface", "name", str(interface)), "enabled") + return InterfaceKeywords._set_interface_properties( + node, interface, path, intf_state[state.lower()]) + + @staticmethod + def set_interface_up(node, interface): + """Set the administration state of VPP interface to up. + + :param node: Honeycomb node. + :param interface: The name of interface. + :type node: dict + :type interface: str + :return: Content of response + :rtype: bytearray + """ + + return InterfaceKeywords.set_interface_state(node, interface, "up") + + @staticmethod + def set_interface_down(node, interface): + """Set the administration state of VPP interface to down. + + :param node: Honeycomb node. + :param interface: The name of interface. + :type node: dict + :type interface: str + :return: Content of response. + :rtype: bytearray + """ + + return InterfaceKeywords.set_interface_state(node, interface, "down") + + @staticmethod + def add_bridge_domain_to_interface(node, interface, bd_name, + split_horizon_group=None, bvi=None): + """Add a new bridge domain to an interface and set its parameters. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param bd_name: Bridge domain name. + :param split_horizon_group: Split-horizon group name. + :param bvi: The bridged virtual interface. + :type node: dict + :type interface: str + :type bd_name: str + :type split_horizon_group: str + :type bvi: str + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If the interface is not present on the node. + """ + + v3po_l2 = {"bridge-domain": str(bd_name)} + if split_horizon_group: + v3po_l2["split-horizon-group"] = str(split_horizon_group) + if bvi: + v3po_l2["bridged-virtual-interface"] = str(bvi) + + path = ("interfaces", ("interface", "name", str(interface)), "v3po:l2") + + return InterfaceKeywords._set_interface_properties( + node, interface, path, v3po_l2) + + @staticmethod + def configure_interface_base(node, interface, param, value): + """Configure the base parameters of interface. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param param: Parameter to configure (set, change, remove) + :param value: The value of parameter. If None, the parameter will be + removed. + :type node: dict + :type interface: str + :type param: str + :type value: str + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If the parameter is not valid. + """ + + if param not in InterfaceKeywords.INTF_PARAMS: + raise HoneycombError("The parameter {0} is invalid.".format(param)) + + path = ("interfaces", ("interface", "name", interface), param) + return InterfaceKeywords._set_interface_properties( + node, interface, path, value) + + @staticmethod + def configure_interface_ipv4(node, interface, param, value): + """Configure IPv4 parameters of interface + + :param node: Honeycomb node. + :param interface: The name of interface. + :param param: Parameter to configure (set, change, remove) + :param value: The value of parameter. If None, the parameter will be + removed. + :type node: dict + :type interface: str + :type param: str + :type value: str + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If the parameter is not valid. + """ + + if param not in InterfaceKeywords.IPV4_PARAMS: + raise HoneycombError("The parameter {0} is invalid.".format(param)) + + path = ("interfaces", ("interface", "name", interface), + "ietf-ip:ipv4", param) + return InterfaceKeywords._set_interface_properties( + node, interface, path, value) + + @staticmethod + def add_first_ipv4_address(node, interface, ip_addr, netmask): + """Add the first IPv4 address. + + If there are any other addresses configured, they will be removed. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param ip_addr: IPv4 address to be set. + :param netmask: Netmask. + :type node: dict + :type interface: str + :type ip_addr: str + :type netmask: str + :return: Content of response. + :rtype: bytearray + """ + + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4") + address = {"address": [{"ip": ip_addr, "netmask": netmask}, ]} + return InterfaceKeywords._set_interface_properties( + node, interface, path, address) + + @staticmethod + def add_ipv4_address(node, interface, ip_addr, netmask): + """Add IPv4 address. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param ip_addr: IPv4 address to be set. + :param netmask: Netmask. + :type node: dict + :type interface: str + :type ip_addr: str + :type netmask: str + :return: Content of response. + :rtype: bytearray + """ + + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4", + "address") + address = [{"ip": ip_addr, "prefix-length": netmask}, ] + return InterfaceKeywords._set_interface_properties( + node, interface, path, address) + + @staticmethod + def remove_all_ipv4_addresses(node, interface): + """Remove all IPv4 addresses from interface. + + :param node: Honeycomb node. + :param interface: The name of interface. + :type node: dict + :type interface: str + :return: Content of response. + :rtype: bytearray + """ + + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4", + "address") + return InterfaceKeywords._set_interface_properties( + node, interface, path, None) + + @staticmethod + def add_first_ipv4_neighbor(node, interface, ip_addr, link_layer_address): + """Add the first IPv4 neighbour. + + If there are any other neighbours configured, they will be removed. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param ip_addr: IPv4 address of neighbour to be set. + :param link_layer_address: Link layer address. + :type node: dict + :type interface: str + :type ip_addr: str + :type link_layer_address: str + :return: Content of response. + :rtype: bytearray + """ + + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4") + neighbor = {"neighbor": [{"ip": ip_addr, + "link-layer-address": link_layer_address}, ]} + return InterfaceKeywords._set_interface_properties( + node, interface, path, neighbor) + + @staticmethod + def add_ipv4_neighbor(node, interface, ip_addr, link_layer_address): + """Add the IPv4 neighbour. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param ip_addr: IPv4 address of neighbour to be set. + :param link_layer_address: Link layer address. + :type node: dict + :type interface: str + :type ip_addr: str + :type link_layer_address: str + :return: Content of response. + :rtype: bytearray + """ + + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4", + "neighbor") + neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ] + return InterfaceKeywords._set_interface_properties( + node, interface, path, neighbor) + + @staticmethod + def remove_all_ipv4_neighbors(node, interface): + """Remove all IPv4 neighbours. + + :param node: Honeycomb node. + :param interface: The name of interface. + :type node: dict + :type interface: str + :return: Content of response. + :rtype: bytearray + """ + + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4", + "neighbor") + return InterfaceKeywords._set_interface_properties( + node, interface, path, None) + + @staticmethod + def configure_interface_ipv6(node, interface, param, value): + """Configure IPv6 parameters of interface + + :param node: Honeycomb node. + :param interface: The name of interface. + :param param: Parameter to configure (set, change, remove) + :param value: The value of parameter. If None, the parameter will be + removed. + :type node: dict + :type interface: str + :type param: str + :type value: str + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If the parameter is not valid. + """ + + if param in InterfaceKeywords.IPV6_PARAMS: + path = ("interfaces", ("interface", "name", interface), + "ietf-ip:ipv6", param) + elif param in InterfaceKeywords.IPV6_AUTOCONF_PARAMS: + path = ("interfaces", ("interface", "name", interface), + "ietf-ip:ipv6", "autoconf", param) + else: + raise HoneycombError("The parameter {0} is invalid.".format(param)) + + return InterfaceKeywords._set_interface_properties( + node, interface, path, value) + + @staticmethod + def add_first_ipv6_address(node, interface, ip_addr, prefix_len): + """Add the first IPv6 address. + + If there are any other addresses configured, they will be removed. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param ip_addr: IPv6 address to be set. + :param prefix_len: Prefix length. + :type node: dict + :type interface: str + :type ip_addr: str + :type prefix_len: str + :return: Content of response. + :rtype: bytearray + """ + + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6") + address = {"address": [{"ip": ip_addr, "prefix-length": prefix_len}, ]} + return InterfaceKeywords._set_interface_properties( + node, interface, path, address) + + @staticmethod + def add_ipv6_address(node, interface, ip_addr, prefix_len): + """Add IPv6 address. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param ip_addr: IPv6 address to be set. + :param prefix_len: Prefix length. + :type node: dict + :type interface: str + :type ip_addr: str + :type prefix_len: str + :return: Content of response. + :rtype: bytearray + """ + + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6", + "address") + address = [{"ip": ip_addr, "prefix-length": prefix_len}, ] + return InterfaceKeywords._set_interface_properties( + node, interface, path, address) + + @staticmethod + def remove_all_ipv6_addresses(node, interface): + """Remove all IPv6 addresses from interface. + + :param node: Honeycomb node. + :param interface: The name of interface. + :type node: dict + :type interface: str + :return: Content of response. + :rtype: bytearray + """ + + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6", + "address") + return InterfaceKeywords._set_interface_properties( + node, interface, path, None) + + @staticmethod + def add_first_ipv6_neighbor(node, interface, ip_addr, link_layer_address): + """Add the first IPv6 neighbour. + + If there are any other neighbours configured, they will be removed. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param ip_addr: IPv6 address of neighbour to be set. + :param link_layer_address: Link layer address. + :type node: dict + :type interface: str + :type ip_addr: str + :type link_layer_address: str + :return: Content of response. + :rtype: bytearray + """ + + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6") + neighbor = {"neighbor": [{"ip": ip_addr, + "link-layer-address": link_layer_address}, ]} + return InterfaceKeywords._set_interface_properties( + node, interface, path, neighbor) + + @staticmethod + def add_ipv6_neighbor(node, interface, ip_addr, link_layer_address): + """Add the IPv6 neighbour. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param ip_addr: IPv6 address of neighbour to be set. + :param link_layer_address: Link layer address. + :type node: dict + :type interface: str + :type ip_addr: str + :type link_layer_address: str + :return: Content of response. + :rtype: bytearray + """ + + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6", + "neighbor") + neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ] + return InterfaceKeywords._set_interface_properties( + node, interface, path, neighbor) + + @staticmethod + def remove_all_ipv6_neighbors(node, interface): + """Remove all IPv6 neighbours. + + :param node: Honeycomb node. + :param interface: The name of interface. + :type node: dict + :type interface: str + :return: Content of response. + :rtype: bytearray + """ + + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6", + "neighbor") + return InterfaceKeywords._set_interface_properties( + node, interface, path, None) + + @staticmethod + def configure_interface_ethernet(node, interface, param, value): + """Configure the ethernet parameters of interface. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param param: Parameter to configure (set, change, remove) + :param value: The value of parameter. If None, the parameter will be + removed. + :type node: dict + :type interface: str + :type param: str + :type value: str + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If the parameter is not valid. + """ + + if param not in InterfaceKeywords.ETH_PARAMS: + raise HoneycombError("The parameter {0} is invalid.".format(param)) + path = ("interfaces", ("interface", "name", interface), "v3po:ethernet", + param) + return InterfaceKeywords._set_interface_properties( + node, interface, path, value) + + @staticmethod + def configure_interface_routing(node, interface, param, value): + """Configure the routing parameters of interface. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param param: Parameter to configure (set, change, remove) + :param value: The value of parameter. If None, the parameter will be + removed. + :type node: dict + :type interface: str + :type param: str + :type value: str + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If the parameter is not valid. + """ + + if param not in InterfaceKeywords.ROUTING_PARAMS: + raise HoneycombError("The parameter {0} is invalid.".format(param)) + + path = ("interfaces", ("interface", "name", interface), "v3po:routing", + param) + return InterfaceKeywords._set_interface_properties( + node, interface, path, value) + + @staticmethod + def configure_interface_vxlan(node, interface, param, value): + """Configure the VxLAN parameters of interface. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param param: Parameter to configure (set, change, remove) + :param value: The value of parameter. If None, the parameter will be + removed. + :type node: dict + :type interface: str + :type param: str + :type value: str + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If the parameter is not valid. + """ + + if param not in InterfaceKeywords.VXLAN_PARAMS: + raise HoneycombError("The parameter {0} is invalid.".format(param)) + + path = ("interfaces", ("interface", "name", interface), "v3po:vxlan", + param) + return InterfaceKeywords._set_interface_properties( + node, interface, path, value) + + @staticmethod + def configure_interface_l2(node, interface, param, value): + """Configure the L2 parameters of interface. + + :param node: Honeycomb node. + :param interface: The name of interface. + :param param: Parameter to configure (set, change, remove) + :param value: The value of parameter. If None, the parameter will be + removed. + :type node: dict + :type interface: str + :type param: str + :type value: str + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If the parameter is not valid. + """ + + if param not in InterfaceKeywords.L2_PARAMS: + raise HoneycombError("The parameter {0} is invalid.".format(param)) + path = ("interfaces", ("interface", "name", interface), "v3po:l2", + param) + return InterfaceKeywords._set_interface_properties( + node, interface, path, value) diff --git a/resources/libraries/python/honeycomb/HoneycombSetup.py b/resources/libraries/python/honeycomb/HoneycombSetup.py new file mode 100644 index 0000000000..e9c1295260 --- /dev/null +++ b/resources/libraries/python/honeycomb/HoneycombSetup.py @@ -0,0 +1,187 @@ +# Copyright (c) 2016 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. + +"""Implementation of keywords for Honeycomb setup.""" + +from robot.api import logger + +from resources.libraries.python.HTTPRequest import HTTPRequest, HTTPCodes, \ + HTTPRequestError +from resources.libraries.python.constants import Constants as Const +from resources.libraries.python.honeycomb.HoneycombUtil import HoneycombError +from resources.libraries.python.honeycomb.HoneycombUtil \ + import HoneycombUtil as HcUtil +from resources.libraries.python.ssh import SSH +from resources.libraries.python.topology import NodeType + + +class HoneycombSetup(object): + """Implements keywords for Honeycomb setup. + + The keywords implemented in this class make possible to: + - start Honeycomb, + - stop Honeycomb, + - check the Honeycomb start-up state, + - check the Honeycomb shutdown state, + - add VPP to the topology. + """ + + def __init__(self): + pass + + @staticmethod + def start_honeycomb_on_duts(*nodes): + """Start Honeycomb on specified DUT nodes. + + This keyword starts the Honeycomb service on specified DUTs. + The keyword just starts the Honeycomb and does not check its startup + state. Use the keyword "Check Honeycomb Startup State" to check if the + Honeycomb is up and running. + Honeycomb must be installed in "/opt" directory, otherwise the start + will fail. + :param nodes: List of nodes to start Honeycomb on. + :type nodes: list + :raises HoneycombError: If Honeycomb fails to start. + """ + logger.console("Starting Honeycomb service ...") + + cmd = "{0}/start".format(Const.REMOTE_HC_DIR) + + for node in nodes: + if node['type'] == NodeType.DUT: + ssh = SSH() + ssh.connect(node) + (ret_code, _, _) = ssh.exec_command_sudo(cmd) + if int(ret_code) != 0: + raise HoneycombError('Node {0} failed to start Honeycomb.'. + format(node['host'])) + else: + logger.info("Starting the Honeycomb service on node {0} is " + "in progress ...".format(node['host'])) + + @staticmethod + def stop_honeycomb_on_duts(*nodes): + """Stop the Honeycomb service on specified DUT nodes. + + This keyword stops the Honeycomb service on specified nodes. It just + stops the Honeycomb and does not check its shutdown state. Use the + keyword "Check Honeycomb Shutdown State" to check if Honeycomb has + stopped. + :param nodes: List of nodes to stop Honeycomb on. + :type nodes: list + :raises HoneycombError: If Honeycomb failed to stop. + """ + logger.console("Shutting down Honeycomb service ...") + + cmd = "{0}/stop".format(Const.REMOTE_HC_DIR) + errors = [] + + for node in nodes: + if node['type'] == NodeType.DUT: + ssh = SSH() + ssh.connect(node) + (ret_code, _, _) = ssh.exec_command_sudo(cmd) + if int(ret_code) != 0: + errors.append(node['host']) + else: + logger.info("Stopping the Honeycomb service on node {0} is " + "in progress ...".format(node['host'])) + if errors: + raise HoneycombError('Node(s) {0} failed to stop Honeycomb.'. + format(errors)) + + @staticmethod + def check_honeycomb_startup_state(*nodes): + """Check state of Honeycomb service during startup on specified nodes. + + Reads html path from template file oper_vpp_version.url. + + Honeycomb nodes reply with connection refused or the following status + codes depending on startup progress: codes 200, 401, 403, 404, 500, 503 + + :param nodes: List of DUT nodes starting Honeycomb. + :type nodes: list + :return: True if all GETs returned code 200(OK). + :rtype bool + """ + path = HcUtil.read_path_from_url_file("oper_vpp_version") + expected_status_codes = (HTTPCodes.UNAUTHORIZED, + HTTPCodes.FORBIDDEN, + HTTPCodes.NOT_FOUND, + HTTPCodes.SERVICE_UNAVAILABLE, + HTTPCodes.INTERNAL_SERVER_ERROR) + + for node in nodes: + if node['type'] == NodeType.DUT: + status_code, _ = HTTPRequest.get(node, path, timeout=10, + enable_logging=False) + if status_code == HTTPCodes.OK: + logger.info("Honeycomb on node {0} is up and running". + format(node['host'])) + elif status_code in expected_status_codes: + if status_code == HTTPCodes.UNAUTHORIZED: + logger.info('Unauthorized. If this triggers keyword ' + 'timeout, verify Honeycomb username and ' + 'password.') + raise HoneycombError('Honeycomb on node {0} running but ' + 'not yet ready.'.format(node['host']), + enable_logging=False) + else: + raise HoneycombError('Unexpected return code: {0}.'. + format(status_code)) + return True + + @staticmethod + def check_honeycomb_shutdown_state(*nodes): + """Check state of Honeycomb service during shutdown on specified nodes. + + Honeycomb nodes reply with connection refused or the following status + codes depending on shutdown progress: codes 200, 404. + + :param nodes: List of DUT nodes stopping Honeycomb. + :type nodes: list + :return: True if all GETs fail to connect. + :rtype bool + """ + cmd = "ps -ef | grep -v grep | grep karaf" + for node in nodes: + if node['type'] == NodeType.DUT: + try: + status_code, _ = HTTPRequest.get(node, '/index.html', + timeout=5, + enable_logging=False) + if status_code == HTTPCodes.OK: + raise HoneycombError('Honeycomb on node {0} is still ' + 'running.'.format(node['host']), + enable_logging=False) + elif status_code == HTTPCodes.NOT_FOUND: + raise HoneycombError('Honeycomb on node {0} is shutting' + ' down.'.format(node['host']), + enable_logging=False) + else: + raise HoneycombError('Unexpected return code: {0}.'. + format(status_code)) + except HTTPRequestError: + logger.debug('Connection refused, checking the process ' + 'state ...') + ssh = SSH() + ssh.connect(node) + (ret_code, _, _) = ssh.exec_command_sudo(cmd) + if ret_code == 0: + raise HoneycombError('Honeycomb on node {0} is still ' + 'running.'.format(node['host']), + enable_logging=False) + else: + logger.info("Honeycomb on node {0} has stopped". + format(node['host'])) + return True diff --git a/resources/libraries/python/honeycomb/HoneycombUtil.py b/resources/libraries/python/honeycomb/HoneycombUtil.py new file mode 100644 index 0000000000..644cf62c43 --- /dev/null +++ b/resources/libraries/python/honeycomb/HoneycombUtil.py @@ -0,0 +1,387 @@ +# Copyright (c) 2016 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. + +"""Implementation of low level functionality used in communication with +Honeycomb. + +Exception HoneycombError is used in all methods and in all modules with +Honeycomb keywords. + +Class HoneycombUtil implements methods used by Honeycomb keywords. They must not +be used directly in tests. Use keywords implemented in the module +HoneycombAPIKeywords instead. +""" + +from json import loads, dumps +from enum import Enum, unique + +from robot.api import logger + +from resources.libraries.python.HTTPRequest import HTTPRequest +from resources.libraries.python.constants import Constants as Const + + +@unique +class DataRepresentation(Enum): + """Representation of data sent by PUT and POST requests.""" + NO_DATA = 0 + JSON = 1 + XML = 2 + TXT = 3 + + +# Headers used in requests. Key - content representation, value - header. +HEADERS = {DataRepresentation.NO_DATA: + {}, # It must be empty dictionary. + DataRepresentation.JSON: + {"Content-Type": "application/json", + "Accept": "text/plain"}, + DataRepresentation.XML: + {"Content-Type": "application/xml", + "Accept": "text/plain"}, + DataRepresentation.TXT: + {"Content-Type": "text/plain", + "Accept": "text/plain"} + } + + +class HoneycombError(Exception): + + """Exception(s) raised by methods working with Honeycomb. + + When raising this exception, put this information to the message in this + order: + - short description of the encountered problem (parameter msg), + - relevant messages if there are any collected, e.g., from caught + exception (optional parameter details), + - relevant data if there are any collected (optional parameter details). + The logging is performed on two levels: 1. error - short description of the + problem; 2. debug - detailed information. + """ + + def __init__(self, msg, details='', enable_logging=True): + """Sets the exception message and enables / disables logging. + + It is not wanted to log errors when using these keywords together + with keywords like "Wait until keyword succeeds". So you can disable + logging by setting enable_logging to False. + + :param msg: Message to be displayed and logged. + :param enable_logging: When True, logging is enabled, otherwise + logging is disabled. + :type msg: str + :type enable_logging: bool + """ + super(HoneycombError, self).__init__() + self._msg = "{0}: {1}".format(self.__class__.__name__, msg) + self._details = details + if enable_logging: + logger.error(self._msg) + logger.debug(self._details) + + def __repr__(self): + return repr(self._msg) + + def __str__(self): + return str(self._msg) + + +class HoneycombUtil(object): + """Implements low level functionality used in communication with Honeycomb. + + There are implemented methods to get, put and delete data to/from Honeycomb. + They are based on functionality implemented in the module HTTPRequests which + uses HTTP requests GET, PUT, POST and DELETE to communicate with Honeycomb. + + It is possible to PUT the data represented as XML or JSON structures or as + plain text. + Data received in the response of GET are always represented as a JSON + structure. + + There are also two supportive methods implemented: + - read_path_from_url_file which reads URL file and returns a path (see + docs/honeycomb_url_files.rst). + - parse_json_response which parses data from response in JSON representation + according to given path. + """ + + def __init__(self): + pass + + @staticmethod + def read_path_from_url_file(url_file): + """Read path from *.url file. + + For more information about *.url file see docs/honeycomb_url_files.rst + :param url_file: URL file. The argument contains only the name of file + without extension, not the full path. + :type url_file: str + :return: Requested path. + :rtype: str + """ + + url_file = "{0}/{1}.url".format(Const.RESOURCES_TPL_HC, url_file) + with open(url_file) as template: + path = template.readline() + return path + + @staticmethod + def find_item(data, path): + """Find a data item (single leaf or sub-tree) in data received from + Honeycomb REST API. + + Path format: + The path is a tuple with items navigating to requested data. The items + can be strings or tuples: + - string item represents a dictionary key in data, + - tuple item represents list item in data. + + Example: + data = \ + { + "interfaces": { + "interface": [ + { + "name": "GigabitEthernet0/8/0", + "enabled": "true", + "type": "iana-if-type:ethernetCsmacd", + }, + { + "name": "local0", + "enabled": "false", + "type": "iana-if-type:ethernetCsmacd", + } + ] + } + } + + path = ("interfaces", ("interface", "name", "local0"), "enabled") + This path points to "false". + + The tuple ("interface", "name", "local0") consists of: + index 0 - dictionary key pointing to a list, + index 1 - key which identifies an item in the list, it is also marked as + the key in corresponding yang file. + index 2 - key value. + + :param data: Data received from Honeycomb REST API. + :param path: Path to data we want to find. + :type data: dict + :type path: tuple + :return: Data represented by path. + :rtype: str, dict, or list + :raises HoneycombError: If the data has not been found. + """ + + for path_item in path: + try: + if isinstance(path_item, str): + data = data[path_item] + elif isinstance(path_item, tuple): + for data_item in data[path_item[0]]: + if data_item[path_item[1]] == path_item[2]: + data = data_item + except KeyError as err: + raise HoneycombError("Data not found: {0}".format(err)) + + return data + + @staticmethod + def remove_item(data, path): + """Remove a data item (single leaf or sub-tree) in data received from + Honeycomb REST API. + + :param data: Data received from Honeycomb REST API. + :param path: Path to data we want to remove. + :type data: dict + :type path: tuple + :return: Original data without removed part. + :rtype: dict + """ + + origin_data = previous_data = data + try: + for path_item in path: + previous_data = data + if isinstance(path_item, str): + data = data[path_item] + elif isinstance(path_item, tuple): + for data_item in data[path_item[0]]: + if data_item[path_item[1]] == path_item[2]: + data = data_item + except KeyError as err: + logger.debug("Data not found: {0}".format(err)) + return origin_data + + if isinstance(path[-1], str): + previous_data.pop(path[-1]) + elif isinstance(path[-1], tuple): + previous_data[path[-1][0]].remove(data) + if not previous_data[path[-1][0]]: + previous_data.pop(path[-1][0]) + + return origin_data + + @staticmethod + def set_item_value(data, path, new_value): + """Set or change the value (single leaf or sub-tree) in data received + from Honeycomb REST API. + + If the item is not present in the data structure, it is created. + + :param data: Data received from Honeycomb REST API. + :param path: Path to data we want to change or create. + :param new_value: The value to be set. + :type data: dict + :type path: tuple + :type new_value: str, dict or list + :return: Original data with the new value. + :rtype: dict + """ + + origin_data = data + for path_item in path[:-1]: + if isinstance(path_item, str): + try: + data = data[path_item] + except KeyError: + data[path_item] = {} + data = data[path_item] + elif isinstance(path_item, tuple): + try: + flag = False + index = 0 + for data_item in data[path_item[0]]: + if data_item[path_item[1]] == path_item[2]: + data = data[path_item[0]][index] + flag = True + break + index += 1 + if not flag: + data[path_item[0]].append({path_item[1]: path_item[2]}) + data = data[path_item[0]][-1] + except KeyError: + data[path_item] = [] + + if not path[-1] in data.keys(): + data[path[-1]] = {} + + if isinstance(new_value, list) and isinstance(data[path[-1]], list): + for value in new_value: + data[path[-1]].append(value) + else: + data[path[-1]] = new_value + + return origin_data + + @staticmethod + def get_honeycomb_data(node, url_file): + """Retrieve data from Honeycomb according to given URL. + + :param node: Honeycomb node. + :param url_file: URL file. The argument contains only the name of file + without extension, not the full path. + :type node: dict + :type url_file: str + :return: Status code and content of response. + :rtype tuple + """ + + path = HoneycombUtil.read_path_from_url_file(url_file) + status_code, resp = HTTPRequest.get(node, path) + return status_code, loads(resp) + + @staticmethod + def put_honeycomb_data(node, url_file, data, + data_representation=DataRepresentation.JSON): + """Send configuration data using PUT request and return the status code + and response content. + + :param node: Honeycomb node. + :param url_file: URL file. The argument contains only the name of file + without extension, not the full path. + :param data: Configuration data to be sent to Honeycomb. + :param data_representation: How the data is represented. + :type node: dict + :type url_file: str + :type data: dict, str + :type data_representation: DataRepresentation + :return: Status code and content of response. + :rtype: tuple + :raises HoneycombError: If the given data representation is not defined + in HEADERS. + """ + + try: + header = HEADERS[data_representation] + except AttributeError as err: + raise HoneycombError("Wrong data representation: {0}.". + format(data_representation), repr(err)) + if data_representation == DataRepresentation.JSON: + data = dumps(data) + + path = HoneycombUtil.read_path_from_url_file(url_file) + return HTTPRequest.put(node=node, path=path, headers=header, + payload=data) + + @staticmethod + def post_honeycomb_data(node, url_file, data=None, + data_representation=DataRepresentation.JSON, + timeout=10): + """Send a POST request and return the status code and response content. + + :param node: Honeycomb node. + :param url_file: URL file. The argument contains only the name of file + without extension, not the full path. + :param data: Configuration data to be sent to Honeycomb. + :param data_representation: How the data is represented. + :param timeout: How long to wait for the server to send data before + giving up. + :type node: dict + :type url_file: str + :type data: dict, str + :type data_representation: DataRepresentation + :type timeout: int + :return: Status code and content of response. + :rtype: tuple + :raises HoneycombError: If the given data representation is not defined + in HEADERS. + """ + + try: + header = HEADERS[data_representation] + except AttributeError as err: + raise HoneycombError("Wrong data representation: {0}.". + format(data_representation), repr(err)) + if data_representation == DataRepresentation.JSON: + data = dumps(data) + + path = HoneycombUtil.read_path_from_url_file(url_file) + return HTTPRequest.post(node=node, path=path, headers=header, + payload=data, timeout=timeout) + + @staticmethod + def delete_honeycomb_data(node, url_file): + """Delete data from Honeycomb according to given URL. + + :param node: Honeycomb node. + :param url_file: URL file. The argument contains only the name of file + without extension, not the full path. + :type node: dict + :type url_file: str + :return: Status code and content of response. + :rtype tuple + """ + + path = HoneycombUtil.read_path_from_url_file(url_file) + return HTTPRequest.delete(node, path) diff --git a/resources/libraries/python/honeycomb/__init__.py b/resources/libraries/python/honeycomb/__init__.py new file mode 100644 index 0000000000..c35326d604 --- /dev/null +++ b/resources/libraries/python/honeycomb/__init__.py @@ -0,0 +1,16 @@ +# Copyright (c) 2016 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. + +""" +__init__ file for directory resources/libraries/python/honeycomb +""" diff --git a/resources/libraries/robot/honeycomb/bridge_domain.robot b/resources/libraries/robot/honeycomb/bridge_domain.robot index da3ae0af47..a3f695cf70 100644 --- a/resources/libraries/robot/honeycomb/bridge_domain.robot +++ b/resources/libraries/robot/honeycomb/bridge_domain.robot @@ -13,9 +13,9 @@ *** Settings *** | Library | resources.libraries.python.L2Util -| Library | resources.libraries.python.HcAPIKwBridgeDomain.BridgeDomainKeywords -| Library | resources.libraries.python.HcAPIKwInterfaces.InterfaceKeywords -| ... | WITH NAME | InterfaceAPI +| Library | resources.libraries.python.honeycomb.HcAPIKwBridgeDomain.BridgeDomainKeywords +| Library | resources.libraries.python.honeycomb.HcAPIKwInterfaces.InterfaceKeywords +| ... | WITH NAME | InterfaceAPI *** Keywords *** | Honeycomb creates first L2 bridge domain diff --git a/resources/libraries/robot/honeycomb/honeycomb.robot b/resources/libraries/robot/honeycomb/honeycomb.robot index 54aff2febf..c71d6a7257 100644 --- a/resources/libraries/robot/honeycomb/honeycomb.robot +++ b/resources/libraries/robot/honeycomb/honeycomb.robot @@ -12,9 +12,8 @@ # limitations under the License. *** Settings *** -| Library | resources/libraries/python/HoneycombSetup.py -| Library | resources/libraries/python/HoneycombUtil.py -| Library | resources/libraries/python/HTTPRequest.py +| Library | resources/libraries/python/honeycomb/HoneycombSetup.py +| Library | resources/libraries/python/honeycomb/HoneycombUtil.py *** Keywords *** | Setup Honeycomb service on DUTs diff --git a/resources/libraries/robot/honeycomb/interfaces.robot b/resources/libraries/robot/honeycomb/interfaces.robot index f98cca0901..d27aff4175 100644 --- a/resources/libraries/robot/honeycomb/interfaces.robot +++ b/resources/libraries/robot/honeycomb/interfaces.robot @@ -12,11 +12,11 @@ # limitations under the License. *** Settings *** -| Library | resources/libraries/python/HoneycombUtil.py +| Library | resources/libraries/python/honeycomb/HoneycombUtil.py | Library | resources.libraries.python.InterfaceUtil -| ... | WITH NAME | interfaceCLI -| Library | resources.libraries.python.HcAPIKwInterfaces.InterfaceKeywords -| ... | WITH NAME | InterfaceAPI +| ... | WITH NAME | interfaceCLI +| Library | resources.libraries.python.honeycomb.HcAPIKwInterfaces.InterfaceKeywords +| ... | WITH NAME | InterfaceAPI *** Keywords *** | Interface state is -- cgit 1.2.3-korg