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