86c25adc38674b6e31c8da401a46bfa2479f6b01
[csit.git] / resources / libraries / python / HoneycombUtil.py
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:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
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.
13
14 """Implementation of low level functionality used in communication with
15 Honeycomb.
16
17 Exception HoneycombError is used in all methods and in all modules with
18 Honeycomb keywords.
19
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.
23 """
24
25 from json import loads
26
27 from robot.api import logger
28
29 from resources.libraries.python.HTTPRequest import HTTPRequest
30 from resources.libraries.python.constants import Constants as Const
31
32
33 class HoneycombError(Exception):
34
35     """Exception(s) raised by methods working with Honeycomb.
36
37     When raising this exception, put this information to the message in this
38     order:
39      - short description of the encountered problem (parameter msg),
40      - relevant messages if there are any collected, e.g., from caught
41        exception (optional parameter details),
42      - relevant data if there are any collected (optional parameter details).
43      The logging is performed on two levels: 1. error - short description of the
44      problem; 2. debug - detailed information.
45     """
46
47     def __init__(self, msg, details='', enable_logging=True):
48         """Sets the exception message and enables / disables logging.
49
50         It is not wanted to log errors when using these keywords together
51         with keywords like "Wait until keyword succeeds". So you can disable
52         logging by setting enable_logging to False.
53
54         :param msg: Message to be displayed and logged
55         :param enable_logging: When True, logging is enabled, otherwise
56         logging is disabled.
57         :type msg: str
58         :type enable_logging: bool
59         """
60         super(HoneycombError, self).__init__()
61         self._msg = "{0}: {1}".format(self.__class__.__name__, msg)
62         self._details = details
63         if enable_logging:
64             logger.error(self._msg)
65             logger.debug(self._details)
66
67     def __repr__(self):
68         return repr(self._msg)
69
70     def __str__(self):
71         return str(self._msg)
72
73
74 class HoneycombUtil(object):
75     """Implements low level functionality used in communication with Honeycomb.
76
77     There are implemented methods to get, put and delete data to/from Honeycomb.
78     They are based on functionality implemented in the module HTTPRequests which
79     uses HTTP requests GET, PUT, POST and DELETE to communicate with Honeycomb.
80
81     It is possible to PUT the data represented as XML or JSON structures or as
82     plain text.
83     Data received in the response of GET are always represented as a JSON
84     structure.
85
86     There are also two supportive methods implemented:
87     - read_path_from_url_file which reads URL file and returns a path (see
88       docs/honeycomb_url_files.rst).
89     - parse_json_response which parses data from response in JSON representation
90       according to given path.
91     """
92
93     def __init__(self):
94         pass
95
96     @staticmethod
97     def read_path_from_url_file(url_file):
98         """Read path from *.url file.
99
100         For more information about *.url file see docs/honeycomb_url_files.rst
101         :param url_file: URL file. The argument contains only the name of file
102         without extension, not the full path.
103         :type url_file: str
104         :return: Requested path.
105         :rtype: str
106         """
107
108         url_file = "{0}/{1}.url".format(Const.RESOURCES_TPL_HC, url_file)
109         with open(url_file) as template:
110             path = template.readline()
111         return path
112
113     @staticmethod
114     def parse_json_response(response, path=None):
115         """Parse data from response string in JSON format according to given
116         path.
117
118         :param response: JSON formatted string.
119         :param path: Path to navigate down the data structure.
120         :type response: string
121         :type path: tuple
122         :return: JSON dictionary/list tree.
123         :rtype: list
124         """
125         data = loads(response)
126
127         if path:
128             data = HoneycombUtil._parse_json_tree(data, path)
129             if not isinstance(data, list):
130                 data = [data, ]
131
132         return data
133
134     @staticmethod
135     def _parse_json_tree(data, path):
136         """Retrieve data addressed by path from python representation of JSON
137         object.
138
139         :param data: Parsed JSON dictionary tree.
140         :param path: Path to navigate down the dictionary tree.
141         :type data: dict
142         :type path: tuple
143         :return: Data from specified path.
144         :rtype: list, dict or str
145         """
146
147         count = 0
148         for key in path:
149             if isinstance(data, dict):
150                 data = data[key]
151                 count += 1
152             elif isinstance(data, list):
153                 result = []
154                 for item in data:
155                     result.append(HoneycombUtil._parse_json_tree(item,
156                                                                  path[count:]))
157                     return result
158         return data
159
160     @staticmethod
161     def get_honeycomb_data(node, url_file):
162         """Retrieve data from Honeycomb according to given URL.
163
164         :param node: Honeycomb node.
165         :param url_file: URL file. The argument contains only the name of file
166         without extension, not the full path.
167         :type node: dict
168         :type url_file: str
169         :return: Requested information.
170         :rtype list
171         """
172
173         path = HoneycombUtil.read_path_from_url_file(url_file)
174         status_code, resp = HTTPRequest.get(node, path)
175         return status_code, resp
176
177     @staticmethod
178     def put_honeycomb_data(node, url_file, data, data_representation='json'):
179         """Send configuration data using PUT request and return the status code
180         and response.
181
182         :param node: Honeycomb node.
183         :param url_file: URL file. The argument contains only the name of file
184         without extension, not the full path.
185         :param data: Configuration data to be sent to Honeycomb.
186         :param data_representation: How the data is represented. Supported types
187         of representation are: json, xml and txt.
188         :type node: dict
189         :type url_file: str
190         :type data: str
191         :type data_representation: str
192         :return: Status code and content of response.
193         :rtype: tuple
194         """
195
196         headers = {'json':
197                        {"Content-Type": "application/json",
198                         'Accept': 'text/plain'},
199                    'xml':
200                        {"Content-Type": "application/xml",
201                         'Accept': 'text/plain'},
202                    'txt':
203                        {"Content-Type": "text/plain",
204                         'Accept': 'text/plain'}
205                   }
206         try:
207             header = headers[data_representation]
208         except KeyError as err:
209             raise HoneycombError("Wrong data type: {0}.".
210                                  format(data_representation), repr(err))
211
212         path = HoneycombUtil.read_path_from_url_file(url_file)
213         status_code, resp = HTTPRequest.put(node=node, path=path,
214                                             headers=header, payload=data)
215         return status_code, resp
216
217     @staticmethod
218     def delete_honeycomb_data(node, url_file):
219         """Delete data from Honeycomb according to given URL.
220
221         :param node: Honeycomb node.
222         :param url_file: URL file. The argument contains only the name of file
223         without extension, not the full path.
224         :type node: dict
225         :type url_file: str
226         :return: Status code and response.
227         :rtype tuple
228         """
229
230         path = HoneycombUtil.read_path_from_url_file(url_file)
231         return HTTPRequest.delete(node, path)