375820283b8be4861e41d7fea6e931a69cff0eb5
[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 not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
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                        "mixed": "mixed"
289                        }
290         try:
291             suffix = suffix_dict[layer]
292         except KeyError:
293             raise ValueError("Unexpected value of layer argument {0}."
294                              "Valid options are: {1}"
295                              .format(layer, suffix_dict.keys()))
296
297         if layer == "mixed":
298             path = "/acl/vpp-acl:{0}-acl/{1}"
299         else:
300             path = "/acl/ietf-access-control-list:{0}-acl/{1}"
301
302         path = path.format(suffix, list_name)
303
304         status_code, resp = HcUtil.put_honeycomb_data(
305             node, "config_ietf_classify_chain", data, path)
306
307         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
308             raise HoneycombError(
309                 "Could not create classify chain."
310                 "Status code: {0}.".format(status_code))
311
312         return resp
313
314     @staticmethod
315     def set_ietf_interface_acl(node, interface, layer, direction, list_name,
316                                default_action, mode=None):
317         """Assign an interface to an ietf-acl classify chain.
318
319         :param node: Honeycomb node.
320         :param interface: Name of an interface on the node.
321         :param layer: Network layer to classify packets on.
322         Valid options are: L2, L3, L4. Mixed ACL not supported yet.
323         :param direction: Classify incoming or outgiong packets.
324         Valid options are: ingress, egress
325         :param list_name: Name of an ietf-acl classify chain.
326         :param default_action: Default classifier action: permit or deny.
327         :param mode: When using mixed layers, this specifies operational mode
328         of the interface - L2 or L3. If layer is not "mixed", this argument
329         will be ignored.
330         :type node: dict
331         :type interface: str or int
332         :type layer: str
333         :type direction: str
334         :type list_name: str
335         :type default_action: str
336         :type mode: str
337
338         :return: Content of response.
339         :rtype: bytearray
340         :raises HoneycombError: If the operation fails.
341         """
342
343         layer = layer.lower()
344         if mode is not None:
345             mode = mode.lower()
346         interface = Topology.convert_interface_reference(
347             node, interface, "name")
348
349         interface = interface.replace("/", "%2F")
350
351         if direction not in ("ingress", "egress"):
352             raise ValueError("Unknown traffic direction {0}. "
353                              "Valid options are: ingress, egress."
354                              .format(direction))
355
356         path = "/interface/{0}/ietf-acl/{1}/access-lists".format(
357             interface, direction)
358
359         types = {
360             "ietf": "ietf-access-control-list:{0}-acl",
361             "vpp": "vpp-acl:{0}-acl"}
362         layers = {
363             "l2": {"mode": "l2", "acl_type": types['ietf'].format("eth")},
364             "l3_ip4": {"mode": "l3", "acl_type": types['ietf'].format("ipv4")},
365             "l3_ip6": {"mode": "l3", "acl_type": types['ietf'].format("ipv6")},
366             "mixed": {"mode": mode, "acl_type": types['vpp'].format("mixed")}
367             }
368
369         try:
370             data = {
371                 "access-lists": {
372                     "acl": [
373                         {
374                             "type": layers[layer]['acl_type'],
375                             "name": list_name
376                         }
377                     ],
378                     "default-action": default_action,
379                     "mode": layers[layer]['mode']
380                 }
381             }
382         except KeyError:
383             raise ValueError("Unknown network layer {0}. "
384                              "Valid options are: {1}".format(
385                                 layer, layers.keys()))
386
387         status_code, resp = HcUtil.put_honeycomb_data(
388             node, "config_vpp_interfaces", data, path)
389
390         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
391             raise HoneycombError(
392                 "Could not configure ACL on interface. "
393                 "Status code: {0}.".format(status_code))
394
395         return resp
396
397     @staticmethod
398     def delete_ietf_interface_acls(node, interface):
399         """Remove all ietf-acl assignments from an interface.
400
401         :param node: Honeycomb node.
402         :param interface: Name of an interface on the node.
403         :type node: dict
404         :type interface: str or int"""
405
406         interface = Topology.convert_interface_reference(
407             node, interface, "name")
408
409         interface = interface.replace("/", "%2F")
410
411         path = "/interface/{0}/ietf-acl/".format(interface)
412         status_code, _ = HcUtil.delete_honeycomb_data(
413             node, "config_vpp_interfaces", path)
414
415         if status_code != HTTPCodes.OK:
416             raise HoneycombError(
417                 "Could not remove ACL assignment from interface. "
418                 "Status code: {0}.".format(status_code))
419
420     @staticmethod
421     def delete_ietf_classify_chains(node):
422         """Remove all classify chains from the ietf-acl node.
423
424         :param node: Honeycomb node.
425         :type node: dict
426         """
427
428         status_code, _ = HcUtil.delete_honeycomb_data(
429             node, "config_ietf_classify_chain")
430
431         if status_code != HTTPCodes.OK:
432             raise HoneycombError(
433                 "Could not remove ietf-acl chain. "
434                 "Status code: {0}.".format(status_code))