b2848411a14a301bfdd718f2570dac6ec6019952
[csit.git] / resources / libraries / python / honeycomb / HcAPIKwACL.py
1 # Copyright (c) 2019 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 """This module implements keywords to manipulate ACL data structures using
15 Honeycomb REST API."""
16
17
18 from robot.api import logger
19
20 from resources.libraries.python.topology import Topology
21 from resources.libraries.python.HTTPRequest import HTTPCodes
22 from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError
23 from resources.libraries.python.honeycomb.HoneycombUtil \
24     import HoneycombUtil as HcUtil
25 from resources.libraries.python.honeycomb.HoneycombUtil \
26     import DataRepresentation
27
28
29 class ACLKeywords(object):
30     """Implementation of keywords which make it possible to:
31     - add classify table(s),
32     - remove classify table(s),
33     - get operational data about classify table(s),
34     - add classify session(s),
35     - remove classify session(s),
36     - get operational data about classify sessions(s).
37     """
38
39     def __init__(self):
40         pass
41
42     @staticmethod
43     def _set_classify_table_properties(node, path, data=None):
44         """Set classify table properties and check the return code.
45
46         :param node: Honeycomb node.
47         :param path: Path which is added to the base path to identify the data.
48         :param data: The new data to be set. If None, the item will be removed.
49         :type node: dict
50         :type path: str
51         :type data: dict
52         :returns: Content of response.
53         :rtype: bytearray
54         :raises HoneycombError: If the status code in response to PUT is not
55             200 = OK.
56         """
57
58         if data:
59             status_code, resp = HcUtil.\
60                 put_honeycomb_data(node, "config_classify_table", data, path,
61                                    data_representation=DataRepresentation.JSON)
62         else:
63             status_code, resp = HcUtil.\
64                 delete_honeycomb_data(node, "config_classify_table", path)
65
66         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
67             if data is None and '"error-tag":"data-missing"' in resp:
68                 logger.debug("data does not exist in path.")
69             else:
70                 raise HoneycombError(
71                     "The configuration of classify table was not successful. "
72                     "Status code: {0}.".format(status_code))
73         return resp
74
75     @staticmethod
76     def add_classify_table(node, table):
77         """Add a classify table to the list of classify tables. The keyword does
78         not validate given data.
79
80         :param node: Honeycomb node.
81         :param table: Classify table to be added.
82         :type node: dict
83         :type table: dict
84         :returns: Content of response.
85         :rtype: bytearray
86         """
87
88         path = "/classify-table/" + table["name"]
89         data = {"classify-table": [table, ]}
90         return ACLKeywords._set_classify_table_properties(node, path, data)
91
92     @staticmethod
93     def remove_all_classify_tables(node):
94         """Remove all classify tables defined on the node.
95
96         :param node: Honeycomb node.
97         :type node: dict
98         :returns: Content of response.
99         :rtype: bytearray
100         """
101
102         return ACLKeywords._set_classify_table_properties(node, path="")
103
104     @staticmethod
105     def remove_classify_table(node, table_name):
106         """Remove the given classify table.
107
108         :param node: Honeycomb node.
109         :param table_name: Name of the classify table to be removed.
110         :type node: dict
111         :type table_name: str
112         :returns: Content of response.
113         :rtype: bytearray
114         """
115
116         path = "/classify-table/" + table_name
117         return ACLKeywords._set_classify_table_properties(node, path)
118
119     @staticmethod
120     def get_all_classify_tables_oper_data(node):
121         """Get operational data about all classify tables present on the node.
122
123         :param node: Honeycomb node.
124         :type node: dict
125         :returns: List of classify tables.
126         :rtype: list
127         """
128
129         status_code, resp = HcUtil.\
130             get_honeycomb_data(node, "oper_classify_table")
131
132         if status_code != HTTPCodes.OK:
133             raise HoneycombError(
134                 "Not possible to get operational information about the "
135                 "classify tables. Status code: {0}.".format(status_code))
136
137         return resp["vpp-classifier-state"]["classify-table"]
138
139     @staticmethod
140     def get_classify_table_oper_data(node, table_name):
141         """Get operational data about the given classify table.
142
143         :param node: Honeycomb node.
144         :param table_name: Name of the classify table.
145         :type node: dict
146         :type table_name: str
147         :returns: Operational data about the given classify table.
148         :rtype: dict
149         """
150
151         tables = ACLKeywords.get_all_classify_tables_oper_data(node)
152         for table in tables:
153             if table["name"] == table_name:
154                 return table
155         raise HoneycombError("Table {0} not found in ACL table list.".format(
156             table_name))
157
158     @staticmethod
159     def get_all_classify_tables_cfg_data(node):
160         """Get configuration data about all classify tables present on the node.
161
162         :param node: Honeycomb node.
163         :type node: dict
164         :returns: List of classify tables.
165         :rtype: list
166         """
167
168         status_code, resp = HcUtil.\
169             get_honeycomb_data(node, "config_classify_table")
170
171         if status_code != HTTPCodes.OK:
172             raise HoneycombError(
173                 "Not possible to get operational information about the "
174                 "classify tables. Status code: {0}.".format(status_code))
175         try:
176             return resp["vpp-classifier"]["classify-table"]
177         except (KeyError, TypeError):
178             return []
179
180     @staticmethod
181     def add_classify_session(node, table_name, session):
182         """Add a classify session to the classify table.
183
184         :param node: Honeycomb node.
185         :param table_name: Name of the classify table.
186         :param session: Classify session to be added to the classify table.
187         :type node: dict
188         :type table_name: str
189         :type session: dict
190         :returns: Content of response.
191         :rtype: bytearray
192         """
193
194         path = "/classify-table/" + table_name + \
195                "/classify-session/" + session["match"]
196         data = {"classify-session": [session, ]}
197         return ACLKeywords._set_classify_table_properties(node, path, data)
198
199     @staticmethod
200     def remove_classify_session(node, table_name, session_match):
201         """Remove the given classify session from the classify table.
202
203         :param node: Honeycomb node.
204         :param table_name: Name of the classify table.
205         :param session_match: Classify session match.
206         :type node: dict
207         :type table_name: str
208         :type session_match: str
209         :returns: Content of response.
210         :rtype: bytearray
211         """
212
213         path = "/classify-table/" + table_name + \
214                "/classify-session/" + session_match
215         return ACLKeywords._set_classify_table_properties(node, path)
216
217     @staticmethod
218     def get_all_classify_sessions_oper_data(node, table_name):
219         """Get operational data about all classify sessions in the classify
220         table.
221
222         :param node: Honeycomb node.
223         :param table_name: Name of the classify table.
224         :type node: dict
225         :type table_name: str
226         :returns: List of classify sessions present in the classify table.
227         :rtype: list
228         """
229
230         table_data = ACLKeywords.get_classify_table_oper_data(node, table_name)
231
232         return table_data["classify-session"]
233
234     @staticmethod
235     def get_classify_session_oper_data(node, table_name, session_match):
236         """Get operational data about the given classify session in the classify
237         table.
238
239         :param node: Honeycomb node.
240         :param table_name: Name of the classify table.
241         :param session_match: Classify session match.
242         :type node: dict
243         :type table_name: str
244         :type session_match: str
245         :returns: Classify session operational data.
246         :rtype: dict
247         :raises HoneycombError: If no session the specified match Id is found.
248         """
249
250         sessions = ACLKeywords.get_all_classify_sessions_oper_data(
251             node, table_name)
252         for session in sessions:
253             if session["match"] == session_match:
254                 return session
255         raise HoneycombError(
256             "Session with match value \"{0}\" not found"
257             " under ACL table {1}.".format(session_match, table_name))
258
259     @staticmethod
260     def create_acl_plugin_classify_chain(node, list_name, data):
261         """Create classify chain using the ietf-acl node.
262
263         :param node: Honeycomb node.
264         :param list_name: Name for the classify list.
265         :param data: Dictionary of settings to send to Honeycomb.
266         :type node: dict
267         :type list_name: str
268         :type data: dict
269         :returns: Content of response.
270         :rtype: bytearray
271         :raises HoneycombError: If the operation fails.
272         """
273
274         path = "/acl/{0}".format(list_name)
275
276         status_code, resp = HcUtil.put_honeycomb_data(
277             node, "config_plugin_acl", data, path)
278
279         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
280             raise HoneycombError(
281                 "Could not create classify chain."
282                 "Status code: {0}.".format(status_code))
283
284         return resp
285
286     @staticmethod
287     def set_acl_plugin_interface(node, interface, acl_name, direction):
288         """Assign an interface to an ietf-acl classify chain.
289
290         :param node: Honeycomb node.
291         :param interface: Name of an interface on the node.
292         :param acl_name: Name of an ACL chain configured through ACL-plugin.
293         :param direction: Classify incoming or outgoing packets.
294             Valid options are: ingress, egress
295         :type node: dict
296         :type interface: str or int
297         :type acl_name: str
298         :type direction: str
299         :returns: Content of response.
300         :rtype: bytearray
301         :raises ValueError: If the direction argument is incorrect.
302         :raises HoneycombError: If the operation fails.
303         """
304
305         interface = Topology.convert_interface_reference(
306             node, interface, "name")
307
308         interface = interface.replace("/", "%2F")
309
310         if direction not in ("ingress", "egress"):
311             raise ValueError("Unknown traffic direction {0}. "
312                              "Valid options are: ingress, egress."
313                              .format(direction))
314
315         path = "/attachment-points/interface/{0}/{1}/acl-sets/".format(
316             interface, direction)
317
318         data = {
319             "acl-sets": {
320                 "acl-set": {
321                     "name": acl_name
322                 }
323             }
324         }
325
326         status_code, resp = HcUtil.put_honeycomb_data(
327             node, "config_plugin_acl", data, path)
328
329         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
330             raise HoneycombError(
331                 "Could not configure ACL on interface. "
332                 "Status code: {0}.".format(status_code))
333
334         return resp
335
336     @staticmethod
337     def delete_interface_plugin_acls(node, interface):
338         """Remove all plugin-acl assignments from an interface.
339
340         :param node: Honeycomb node.
341         :param interface: Name of an interface on the node.
342         :type node: dict
343         :type interface: str or int
344         """
345
346         interface = Topology.convert_interface_reference(
347             node, interface, "name")
348
349         interface = interface.replace("/", "%2F")
350
351         path = "/attachment-points/interface/{0}/".format(interface)
352         status_code, _ = HcUtil.delete_honeycomb_data(
353             node, "config_plugin_acl", path)
354
355         if status_code != HTTPCodes.OK:
356             raise HoneycombError(
357                 "Could not remove ACL assignment from interface. "
358                 "Status code: {0}.".format(status_code))
359
360     @staticmethod
361     def delete_acl_plugin_classify_chains(node):
362         """Remove all plugin-ACL classify chains.
363
364         :param node: Honeycomb node.
365         :type node: dict
366         """
367
368         status_code, _ = HcUtil.delete_honeycomb_data(
369             node, "config_plugin_acl")
370
371         if status_code != HTTPCodes.OK:
372             raise HoneycombError(
373                 "Could not remove plugin-acl chain. "
374                 "Status code: {0}.".format(status_code))