1 # Copyright (c) 2016 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
14 """Implementation of low level functionality used in communication with
17 Exception HoneycombError is used in all methods and in all modules with
20 Class HoneycombUtil implements methods used by Honeycomb keywords. They must not
21 be used directly in tests. Use keywords implemented in the module
22 HoneycombAPIKeywords instead.
25 from json import loads
26 from enum import Enum, unique
28 from robot.api import logger
30 from resources.libraries.python.HTTPRequest import HTTPRequest
31 from resources.libraries.python.constants import Constants as Const
35 class DataRepresentation(Enum):
36 """Representation of data sent by PUT and POST requests."""
43 # Headers used in requests. Key - content representation, value - header.
44 HEADERS = {DataRepresentation.NO_DATA:
46 DataRepresentation.JSON:
47 {"Content-Type": "application/json",
48 "Accept": "text/plain"},
49 DataRepresentation.XML:
50 {"Content-Type": "application/xml",
51 "Accept": "text/plain"},
52 DataRepresentation.TXT:
53 {"Content-Type": "text/plain",
54 "Accept": "text/plain"}
58 class HoneycombError(Exception):
60 """Exception(s) raised by methods working with Honeycomb.
62 When raising this exception, put this information to the message in this
64 - short description of the encountered problem (parameter msg),
65 - relevant messages if there are any collected, e.g., from caught
66 exception (optional parameter details),
67 - relevant data if there are any collected (optional parameter details).
68 The logging is performed on two levels: 1. error - short description of the
69 problem; 2. debug - detailed information.
72 def __init__(self, msg, details='', enable_logging=True):
73 """Sets the exception message and enables / disables logging.
75 It is not wanted to log errors when using these keywords together
76 with keywords like "Wait until keyword succeeds". So you can disable
77 logging by setting enable_logging to False.
79 :param msg: Message to be displayed and logged.
80 :param enable_logging: When True, logging is enabled, otherwise
83 :type enable_logging: bool
85 super(HoneycombError, self).__init__()
86 self._msg = "{0}: {1}".format(self.__class__.__name__, msg)
87 self._details = details
89 logger.error(self._msg)
90 logger.debug(self._details)
93 return repr(self._msg)
99 class HoneycombUtil(object):
100 """Implements low level functionality used in communication with Honeycomb.
102 There are implemented methods to get, put and delete data to/from Honeycomb.
103 They are based on functionality implemented in the module HTTPRequests which
104 uses HTTP requests GET, PUT, POST and DELETE to communicate with Honeycomb.
106 It is possible to PUT the data represented as XML or JSON structures or as
108 Data received in the response of GET are always represented as a JSON
111 There are also two supportive methods implemented:
112 - read_path_from_url_file which reads URL file and returns a path (see
113 docs/honeycomb_url_files.rst).
114 - parse_json_response which parses data from response in JSON representation
115 according to given path.
122 def read_path_from_url_file(url_file):
123 """Read path from *.url file.
125 For more information about *.url file see docs/honeycomb_url_files.rst
126 :param url_file: URL file. The argument contains only the name of file
127 without extension, not the full path.
129 :return: Requested path.
133 url_file = "{0}/{1}.url".format(Const.RESOURCES_TPL_HC, url_file)
134 with open(url_file) as template:
135 path = template.readline()
139 def parse_json_response(response, path=None):
140 """Parse data from response string in JSON format according to given
143 :param response: JSON formatted string.
144 :param path: Path to navigate down the data structure.
147 :return: JSON dictionary/list tree.
150 data = loads(response)
153 data = HoneycombUtil._parse_json_tree(data, path)
154 if not isinstance(data, list):
160 def _parse_json_tree(data, path):
161 """Retrieve data addressed by path from python representation of JSON
164 :param data: Parsed JSON dictionary tree.
165 :param path: Path to navigate down the dictionary tree.
168 :return: Data from specified path.
169 :rtype: list, dict or str
174 if isinstance(data, dict):
177 elif isinstance(data, list):
180 result.append(HoneycombUtil._parse_json_tree(item,
186 def get_honeycomb_data(node, url_file):
187 """Retrieve data from Honeycomb according to given URL.
189 :param node: Honeycomb node.
190 :param url_file: URL file. The argument contains only the name of file
191 without extension, not the full path.
194 :return: Status code and content of response.
198 path = HoneycombUtil.read_path_from_url_file(url_file)
199 return HTTPRequest.get(node, path)
202 def put_honeycomb_data(node, url_file, data,
203 data_representation=DataRepresentation.JSON):
204 """Send configuration data using PUT request and return the status code
205 and response content.
207 :param node: Honeycomb node.
208 :param url_file: URL file. The argument contains only the name of file
209 without extension, not the full path.
210 :param data: Configuration data to be sent to Honeycomb.
211 :param data_representation: How the data is represented.
215 :type data_representation: DataRepresentation
216 :return: Status code and content of response.
218 :raises HoneycombError: If the given data representation is not defined
223 header = HEADERS[data_representation]
224 except AttributeError as err:
225 raise HoneycombError("Wrong data representation: {0}.".
226 format(data_representation), repr(err))
228 path = HoneycombUtil.read_path_from_url_file(url_file)
229 return HTTPRequest.put(node=node, path=path, headers=header,
233 def post_honeycomb_data(node, url_file, data=None,
234 data_representation=DataRepresentation.JSON,
236 """Send a POST request and return the status code and response content.
238 :param node: Honeycomb node.
239 :param url_file: URL file. The argument contains only the name of file
240 without extension, not the full path.
241 :param data: Configuration data to be sent to Honeycomb.
242 :param data_representation: How the data is represented.
243 :param timeout: How long to wait for the server to send data before
248 :type data_representation: DataRepresentation
250 :return: Status code and content of response.
252 :raises HoneycombError: If the given data representation is not defined
257 header = HEADERS[data_representation]
258 except AttributeError as err:
259 raise HoneycombError("Wrong data representation: {0}.".
260 format(data_representation), repr(err))
262 path = HoneycombUtil.read_path_from_url_file(url_file)
263 return HTTPRequest.post(node=node, path=path, headers=header,
264 payload=data, timeout=timeout)
267 def delete_honeycomb_data(node, url_file):
268 """Delete data from Honeycomb according to given URL.
270 :param node: Honeycomb node.
271 :param url_file: URL file. The argument contains only the name of file
272 without extension, not the full path.
275 :return: Status code and content of response.
279 path = HoneycombUtil.read_path_from_url_file(url_file)
280 return HTTPRequest.delete(node, path)