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