aboutsummaryrefslogtreecommitdiffstats
path: root/resources/libraries/python/honeycomb/HoneycombUtil.py
diff options
context:
space:
mode:
Diffstat (limited to 'resources/libraries/python/honeycomb/HoneycombUtil.py')
-rw-r--r--resources/libraries/python/honeycomb/HoneycombUtil.py512
1 files changed, 0 insertions, 512 deletions
diff --git a/resources/libraries/python/honeycomb/HoneycombUtil.py b/resources/libraries/python/honeycomb/HoneycombUtil.py
deleted file mode 100644
index 59483f4672..0000000000
--- a/resources/libraries/python/honeycomb/HoneycombUtil.py
+++ /dev/null
@@ -1,512 +0,0 @@
-# Copyright (c) 2018 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.ssh import SSH
-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.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
- :returns: 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
- :returns: 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
- :returns: 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
- :returns: 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, path=""):
- """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.
- :param path: Path which is added to the base path to identify the data.
- :type node: dict
- :type url_file: str
- :type path: str
- :returns: Status code and content of response.
- :rtype: tuple
- """
-
- base_path = HoneycombUtil.read_path_from_url_file(url_file)
- path = base_path + path
- status_code, resp = HTTPRequest.get(node, path)
-
- try:
- data = loads(resp)
- except ValueError:
- logger.debug("Failed to deserialize JSON data.")
- data = None
-
- return status_code, data
-
- @staticmethod
- def put_honeycomb_data(node, url_file, data, path="",
- 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 path: Path which is added to the base path to identify the data.
- :param data_representation: How the data is represented.
- :type node: dict
- :type url_file: str
- :type data: dict, str
- :type path: str
- :type data_representation: DataRepresentation
- :returns: 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)
-
- logger.trace(data)
-
- base_path = HoneycombUtil.read_path_from_url_file(url_file)
- path = base_path + path
- logger.trace(path)
- 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
- :returns: 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, path=""):
- """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.
- :param path: Path which is added to the base path to identify the data.
- :type node: dict
- :type url_file: str
- :type path: str
- :returns: Status code and content of response.
- :rtype: tuple
- """
-
- base_path = HoneycombUtil.read_path_from_url_file(url_file)
- path = base_path + path
- return HTTPRequest.delete(node, path)
-
- @staticmethod
- def append_honeycomb_log(node, suite_name):
- """Append Honeycomb log for the current test suite to the full log.
-
- :param node: Honeycomb node.
- :param suite_name: Name of the current test suite. ${SUITE_NAME}
- variable in robotframework.
- :type node: dict
- :type suite_name: str
- """
-
- ssh = SSH()
- ssh.connect(node)
-
- ssh.exec_command(
- "echo '{separator}' >> /tmp/honeycomb.log".format(separator="="*80))
- ssh.exec_command(
- "echo 'Log for suite: {suite}' >> /tmp/honeycomb.log".format(
- suite=suite_name))
- ssh.exec_command(
- "cat {hc_log} >> /tmp/honeycomb.log".format(
- hc_log=Const.REMOTE_HC_LOG))
-
- @staticmethod
- def append_odl_log(node, odl_name, suite_name):
- """Append ODL karaf log for the current test suite to the full log.
-
- :param node: Honeycomb node.
- :param odl_name: Name of ODL client version to use.
- :param suite_name: Name of the current test suite. ${SUITE_NAME}
- variable in robotframework.
- :type node: dict
- :type odl_name: str
- :type suite_name: str
- """
-
- ssh = SSH()
- ssh.connect(node)
-
- ssh.exec_command(
- "echo '{separator}' >> /tmp/karaf.log".format(separator="="*80))
- ssh.exec_command(
- "echo 'Log for suite: {suite}' >> /tmp/karaf.log".format(
- suite=suite_name))
- ssh.exec_command(
- "cat /tmp/karaf_{odl_name}/data/log/karaf.log >> /tmp/karaf.log"
- .format(odl_name=odl_name))
-
- @staticmethod
- def clear_honeycomb_log(node):
- """Delete the Honeycomb log file for the current test suite.
-
- :param node: Honeycomb node.
- :type node: dict
- """
-
- ssh = SSH()
- ssh.connect(node)
-
- ssh.exec_command("sudo rm {hc_log}".format(hc_log=Const.REMOTE_HC_LOG))
-
- @staticmethod
- def archive_honeycomb_log(node, perf=False):
- """Copy honeycomb log file from DUT node to VIRL for archiving.
-
- :param node: Honeycomb node.
- :param perf: Alternate handling, for use with performance test topology.
- :type node: dict
- :type perf: bool
- """
-
- ssh = SSH()
- ssh.connect(node)
-
- if not perf:
- cmd = "cp /tmp/honeycomb.log /scratch/"
- ssh.exec_command_sudo(cmd, timeout=60)
- else:
- ssh.scp(
- ".",
- "/tmp/honeycomb.log",
- get=True,
- timeout=60)
- ssh.exec_command("rm /tmp/honeycomb.log")
-
- @staticmethod
- def archive_odl_log(node):
- """Copy ODL karaf log file from DUT node to VIRL for archiving.
-
- :param node: Honeycomb node.
- :type node: dict
- """
-
- ssh = SSH()
- ssh.connect(node)
-
- cmd = "cp /tmp/karaf.log /scratch/"
- ssh.exec_command_sudo(cmd, timeout=60)