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