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:
6 # http://www.apache.org/licenses/LICENSE-2.0
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.
14 """This module implements keywords to manipulate ACL data structures using
15 Honeycomb REST API."""
16 from robot.api import logger
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
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).
41 def _set_classify_table_properties(node, path, data=None):
42 """Set classify table properties and check the return code.
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.
50 :return: Content of response.
52 :raises HoneycombError: If the status code in response to PUT is not
57 status_code, resp = HcUtil.\
58 put_honeycomb_data(node, "config_classify_table", data, path,
59 data_representation=DataRepresentation.JSON)
61 status_code, resp = HcUtil.\
62 delete_honeycomb_data(node, "config_classify_table", path)
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.")
69 "The configuration of classify table was not successful. "
70 "Status code: {0}.".format(status_code))
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.
78 :param node: Honeycomb node.
79 :param table: Classify table to be added.
82 :return: Content of response.
86 path = "/classify-table/" + table["name"]
87 data = {"classify-table": [table, ]}
88 return ACLKeywords._set_classify_table_properties(node, path, data)
91 def remove_all_classify_tables(node):
92 """Remove all classify tables defined on the node.
94 :param node: Honeycomb node.
96 :return: Content of response.
100 return ACLKeywords._set_classify_table_properties(node, path="")
103 def remove_classify_table(node, table_name):
104 """Remove the given classify table.
106 :param node: Honeycomb node.
107 :param table_name: Name of the classify table to be removed.
109 :type table_name: str
110 :return: Content of response.
114 path = "/classify-table/" + table_name
115 return ACLKeywords._set_classify_table_properties(node, path)
118 def get_all_classify_tables_oper_data(node):
119 """Get operational data about all classify tables present on the node.
121 :param node: Honeycomb node.
123 :return: List of classify tables.
127 status_code, resp = HcUtil.\
128 get_honeycomb_data(node, "oper_classify_table")
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))
135 return resp["vpp-classifier"]["classify-table"]
136 except (KeyError, TypeError):
140 def get_classify_table_oper_data(node, table_name):
141 """Get operational data about the given classify table.
143 :param node: Honeycomb node.
144 :param table_name: Name of the classify table.
146 :type table_name: str
147 :return: Operational data about the given classify table.
151 path = "/classify-table/" + table_name
152 status_code, resp = HcUtil.\
153 get_honeycomb_data(node, "oper_classify_table", path)
155 if status_code != HTTPCodes.OK:
156 raise HoneycombError(
157 "Not possible to get operational information about the "
158 "classify tables. Status code: {0}.".format(status_code))
160 return resp["classify-table"][0]
161 except (KeyError, TypeError):
165 def get_all_classify_tables_cfg_data(node):
166 """Get configuration data about all classify tables present on the node.
168 :param node: Honeycomb node.
170 :return: List of classify tables.
174 status_code, resp = HcUtil.\
175 get_honeycomb_data(node, "config_classify_table")
177 if status_code != HTTPCodes.OK:
178 raise HoneycombError(
179 "Not possible to get operational information about the "
180 "classify tables. Status code: {0}.".format(status_code))
182 return resp["vpp-classifier"]["classify-table"]
183 except (KeyError, TypeError):
187 def add_classify_session(node, table_name, session):
188 """Add a classify session to the classify table.
190 :param node: Honeycomb node.
191 :param table_name: Name of the classify table.
192 :param session: Classify session to be added to the classify table.
194 :type table_name: str
196 :return: Content of response.
200 path = "/classify-table/" + table_name + \
201 "/classify-session/" + session["match"]
202 data = {"classify-session": [session, ]}
203 return ACLKeywords._set_classify_table_properties(node, path, data)
206 def remove_classify_session(node, table_name, session_match):
207 """Remove the given classify session from the classify table.
209 :param node: Honeycomb node.
210 :param table_name: Name of the classify table.
211 :param session_match: Classify session match.
213 :type table_name: str
214 :type session_match: str
215 :return: Content of response.
219 path = "/classify-table/" + table_name + \
220 "/classify-session/" + session_match
221 return ACLKeywords._set_classify_table_properties(node, path)
224 def get_all_classify_sessions_oper_data(node, table_name):
225 """Get operational data about all classify sessions in the classify
228 :param node: Honeycomb node.
229 :param table_name: Name of the classify table.
231 :type table_name: str
232 :return: List of classify sessions present in the classify table.
236 table_data = ACLKeywords.get_classify_table_oper_data(node, table_name)
238 return table_data["classify-table"][0]["classify-session"]
239 except (KeyError, TypeError):
243 def get_classify_session_oper_data(node, table_name, session_match):
244 """Get operational data about the given classify session in the classify
247 :param node: Honeycomb node.
248 :param table_name: Name of the classify table.
249 :param session_match: Classify session match.
251 :type table_name: str
252 :type session_match: str
253 :return: Classify session operational data.
257 path = "/classify-table/" + table_name + \
258 "/classify-session/" + session_match
259 status_code, resp = HcUtil.\
260 get_honeycomb_data(node, "oper_classify_table", path)
262 if status_code != HTTPCodes.OK:
263 raise HoneycombError(
264 "Not possible to get operational information about the "
265 "classify tables. Status code: {0}.".format(status_code))
267 return resp["classify-session"][0]
268 except (KeyError, TypeError):
272 def create_ietf_classify_chain(node, list_name, layer, data):
273 """Create classify chain using the ietf-acl node.
275 :param node: Honeycomb node.
276 :param list_name: Name for the classify list.
277 :param layer: Network layer to classify on.
278 :param data: Dictionary of settings to send to Honeycomb.
284 :return: Content of response.
286 :raises HoneycombError: If the operation fails.
288 layer = layer.lower()
289 suffix_dict = {"l2": "eth",
295 suffix = suffix_dict[layer]
297 raise ValueError("Unexpected value of layer argument {0}."
298 "Valid options are: {1}"
299 .format(layer, suffix_dict.keys()))
302 path = "/acl/vpp-acl:{0}-acl/{1}"
304 path = "/acl/ietf-access-control-list:{0}-acl/{1}"
306 path = path.format(suffix, list_name)
308 status_code, resp = HcUtil.put_honeycomb_data(
309 node, "config_ietf_classify_chain", data, path)
311 if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
312 raise HoneycombError(
313 "Could not create classify chain."
314 "Status code: {0}.".format(status_code))
319 def set_ietf_interface_acl(node, interface, layer, direction, list_name,
320 default_action, mode=None):
321 """Assign an interface to an ietf-acl classify chain.
323 :param node: Honeycomb node.
324 :param interface: Name of an interface on the node.
325 :param layer: Network layer to classify packets on.
326 Valid options are: L2, L3, L4. Mixed ACL not supported yet.
327 :param direction: Classify incoming or outgiong packets.
328 Valid options are: ingress, egress
329 :param list_name: Name of an ietf-acl classify chain.
330 :param default_action: Default classifier action: permit or deny.
331 :param mode: When using mixed layers, this specifies operational mode
332 of the interface - L2 or L3. If layer is not "mixed", this argument
335 :type interface: str or int
339 :type default_action: str
342 :return: Content of response.
344 :raises HoneycombError: If the operation fails.
347 layer = layer.lower()
350 interface = Topology.convert_interface_reference(
351 node, interface, "name")
353 interface = interface.replace("/", "%2F")
355 if direction not in ("ingress", "egress"):
356 raise ValueError("Unknown traffic direction {0}. "
357 "Valid options are: ingress, egress."
360 path = "/interface/{0}/ietf-acl/{1}/access-lists".format(
361 interface, direction)
364 "ietf": "ietf-access-control-list:{0}-acl",
365 "vpp": "vpp-acl:{0}-acl"}
367 "l2": {"mode": "l2", "acl_type": types['ietf'].format("eth")},
368 "l3_ip4": {"mode": "l3", "acl_type": types['ietf'].format("ipv4")},
369 "l3_ip6": {"mode": "l3", "acl_type": types['ietf'].format("ipv6")},
370 "mixed": {"mode": mode, "acl_type": types['vpp'].format("mixed")}
378 "type": layers[layer]['acl_type'],
382 "default-action": default_action,
383 "mode": layers[layer]['mode']
387 raise ValueError("Unknown network layer {0}. "
388 "Valid options are: {1}".format(
389 layer, layers.keys()))
391 status_code, resp = HcUtil.put_honeycomb_data(
392 node, "config_vpp_interfaces", data, path)
394 if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
395 raise HoneycombError(
396 "Could not configure ACL on interface. "
397 "Status code: {0}.".format(status_code))
402 def delete_ietf_interface_acls(node, interface):
403 """Remove all ietf-acl assignments from an interface.
405 :param node: Honeycomb node.
406 :param interface: Name of an interface on the node.
408 :type interface: str or int"""
410 interface = Topology.convert_interface_reference(
411 node, interface, "name")
413 interface = interface.replace("/", "%2F")
415 path = "/interface/{0}/ietf-acl/".format(interface)
416 status_code, _ = HcUtil.delete_honeycomb_data(
417 node, "config_vpp_interfaces", path)
419 if status_code != HTTPCodes.OK:
420 raise HoneycombError(
421 "Could not remove ACL assignment from interface. "
422 "Status code: {0}.".format(status_code))
425 def delete_ietf_classify_chains(node):
426 """Remove all classify chains from the ietf-acl node.
428 :param node: Honeycomb node.
432 status_code, _ = HcUtil.delete_honeycomb_data(
433 node, "config_ietf_classify_chain")
435 if status_code != HTTPCodes.OK:
436 raise HoneycombError(
437 "Could not remove ietf-acl chain. "
438 "Status code: {0}.".format(status_code))