X-Git-Url: https://gerrit.fd.io/r/gitweb?p=csit.git;a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2Fhoneycomb%2FHoneycombUtil.py;h=59483f4672daefc861594bd356185d3a92db7922;hp=39c076d9c3d843722b4c2a79d64816986733a551;hb=da799981f5373b09398319df12e77e2efc75caa6;hpb=0513ce5642dcf58b21f9b77d6b50e4e9a7a94f04 diff --git a/resources/libraries/python/honeycomb/HoneycombUtil.py b/resources/libraries/python/honeycomb/HoneycombUtil.py index 39c076d9c3..59483f4672 100644 --- a/resources/libraries/python/honeycomb/HoneycombUtil.py +++ b/resources/libraries/python/honeycomb/HoneycombUtil.py @@ -1,4 +1,4 @@ -# 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: @@ -29,7 +29,7 @@ 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 @@ -62,12 +62,14 @@ class HoneycombError(Exception): 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): @@ -79,7 +81,7 @@ class HoneycombError(Exception): :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 """ @@ -109,10 +111,11 @@ class HoneycombUtil(object): 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): @@ -120,11 +123,12 @@ class HoneycombUtil(object): @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 :returns: Requested path. :rtype: str @@ -143,36 +147,39 @@ class HoneycombUtil(object): 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. @@ -290,19 +297,26 @@ class HoneycombUtil(object): :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 :returns: Status code and content of response. - :rtype tuple + :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="", @@ -312,7 +326,7 @@ class HoneycombUtil(object): :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. @@ -324,7 +338,7 @@ class HoneycombUtil(object): :returns: Status code and content of response. :rtype: tuple :raises HoneycombError: If the given data representation is not defined - in HEADERS. + in HEADERS. """ try: @@ -351,11 +365,11 @@ class HoneycombUtil(object): :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 @@ -364,7 +378,7 @@ class HoneycombUtil(object): :returns: Status code and content of response. :rtype: tuple :raises HoneycombError: If the given data representation is not defined - in HEADERS. + in HEADERS. """ try: @@ -385,13 +399,13 @@ class HoneycombUtil(object): :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 :returns: Status code and content of response. - :rtype tuple + :rtype: tuple """ base_path = HoneycombUtil.read_path_from_url_file(url_file) @@ -404,7 +418,7 @@ class HoneycombUtil(object): :param node: Honeycomb node. :param suite_name: Name of the current test suite. ${SUITE_NAME} - variable in robotframework. + variable in robotframework. :type node: dict :type suite_name: str """ @@ -421,12 +435,38 @@ class HoneycombUtil(object): "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""" + :type node: dict + """ ssh = SSH() ssh.connect(node) @@ -448,10 +488,25 @@ class HoneycombUtil(object): if not perf: cmd = "cp /tmp/honeycomb.log /scratch/" - ssh.exec_command_sudo(cmd) + ssh.exec_command_sudo(cmd, timeout=60) else: ssh.scp( ".", "/tmp/honeycomb.log", - get=True) + 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)