-# Copyright (c) 2016 Cisco and/or its affiliates.
+# 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:
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
+from resources.libraries.python.Constants import Constants as Const
@unique
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.
+
+ 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):
:param msg: Message to be displayed and logged.
:param enable_logging: When True, logging is enabled, otherwise
- logging is disabled.
+ logging is disabled.
:type msg: str
:type enable_logging: bool
"""
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):
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.
+
+ - 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):
@staticmethod
def read_path_from_url_file(url_file):
- """Read path from *.url file.
+ """Read path from .url file.
+
+ For more information about .url file see docs/honeycomb_url_files.rst
- 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.
+ without extension, not the full path.
:type url_file: str
- :return: Requested path.
+ :returns: Requested path.
:rtype: str
"""
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",
- }
- ]
- }
- }
+
+ - 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.
+ 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.
+ :returns: Data represented by path.
:rtype: str, dict, or list
:raises HoneycombError: If the data has not been found.
"""
:param path: Path to data we want to remove.
:type data: dict
:type path: tuple
- :return: Original data without removed part.
+ :returns: Original data without removed part.
:rtype: dict
"""
:type data: dict
:type path: tuple
:type new_value: str, dict or list
- :return: Original data with the new value.
+ :returns: Original data with the new value.
:rtype: dict
"""
:param node: Honeycomb node.
:param url_file: URL file. The argument contains only the name of file
- without extension, not the full path.
+ 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
- :return: Status code and content of response.
- :rtype tuple
+ :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)
- return status_code, loads(resp)
+
+ 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="",
:param node: Honeycomb node.
:param url_file: URL file. The argument contains only the name of file
- without extension, not the full path.
+ 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 data: dict, str
:type path: str
:type data_representation: DataRepresentation
- :return: Status code and content of response.
+ :returns: Status code and content of response.
:rtype: tuple
:raises HoneycombError: If the given data representation is not defined
- in HEADERS.
+ in HEADERS.
"""
try:
base_path = HoneycombUtil.read_path_from_url_file(url_file)
path = base_path + path
- return HTTPRequest.put(node=node, path=path, headers=header,
- payload=data)
+ logger.trace(path)
+ return HTTPRequest.put(
+ node=node, path=path, headers=header, payload=data)
@staticmethod
def post_honeycomb_data(node, url_file, data=None,
:param node: Honeycomb node.
:param url_file: URL file. The argument contains only the name of file
- without extension, not the full path.
+ 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.
+ 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.
+ :returns: Status code and content of response.
:rtype: tuple
:raises HoneycombError: If the given data representation is not defined
- in HEADERS.
+ in HEADERS.
"""
try:
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)
+ return HTTPRequest.post(
+ node=node, path=path, headers=header, payload=data, timeout=timeout)
@staticmethod
def delete_honeycomb_data(node, url_file, path=""):
:param node: Honeycomb node.
:param url_file: URL file. The argument contains only the name of file
- without extension, not the full path.
+ 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
- :return: Status code and content of response.
- :rtype tuple
+ :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)