aboutsummaryrefslogtreecommitdiffstats
path: root/resources/libraries/python/honeycomb
diff options
context:
space:
mode:
authorTibor Frank <tifrank@cisco.com>2016-05-10 14:50:41 +0200
committerMatej Klotton <mklotton@cisco.com>2016-05-11 10:36:20 +0000
commitc37f394a29165f839c3032e7f9485e35fb3307f2 (patch)
tree41d9bb9d7ef32cb6b1350186272ed0a4c9e4eb05 /resources/libraries/python/honeycomb
parent452fabf532691f88b36b79bf2469afde18183de2 (diff)
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 <tifrank@cisco.com>
Diffstat (limited to 'resources/libraries/python/honeycomb')
-rw-r--r--resources/libraries/python/honeycomb/HcAPIKwBridgeDomain.py330
-rw-r--r--resources/libraries/python/honeycomb/HcAPIKwInterfaces.py713
-rw-r--r--resources/libraries/python/honeycomb/HoneycombSetup.py187
-rw-r--r--resources/libraries/python/honeycomb/HoneycombUtil.py387
-rw-r--r--resources/libraries/python/honeycomb/__init__.py16
5 files changed, 1633 insertions, 0 deletions
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
+"""