1 # Copyright (c) 2018 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 routing tables using
15 Honeycomb REST API."""
17 from robot.api import logger
19 from resources.libraries.python.topology import Topology
20 from resources.libraries.python.HTTPRequest import HTTPCodes
21 from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError
22 from resources.libraries.python.honeycomb.HoneycombUtil \
23 import HoneycombUtil as HcUtil
24 from resources.libraries.python.honeycomb.HoneycombUtil \
25 import DataRepresentation
26 from resources.libraries.python.VatExecutor import VatTerminal
29 class RoutingKeywords(object):
30 """Implementation of keywords which make it possible to:
31 - add/remove routing tables,
32 - add/remove routing table entries
33 - get operational data about routing tables,
40 def _set_routing_table_properties(node, path, data=None):
41 """Set routing table properties and check the return code.
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.
49 :returns: Content of response.
51 :raises HoneycombError: If the status code in response is not
56 status_code, resp = HcUtil.\
57 put_honeycomb_data(node, "config_routing_table", data, path,
58 data_representation=DataRepresentation.JSON)
60 status_code, resp = HcUtil.\
61 delete_honeycomb_data(node, "config_routing_table", path)
63 if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
64 if data is None and '"error-tag":"data-missing"' in resp:
65 logger.debug("data does not exist in path.")
68 "The configuration of routing table was not successful. "
69 "Status code: {0}.".format(status_code))
73 def configure_routing_table(node, name, ip_version, data, vrf=1,
75 """Configure a routing table according to the data provided.
77 :param node: Honeycomb node.
78 :param name: Name for the table.
79 :param ip_version: IP protocol version, ipv4 or ipv6.
80 :param data: Route configuration that should be set.
81 :param vrf: vrf-id to attach configuration to.
82 :param special: Must be True if the configuration is a special route.
89 :returns: Content of response.
93 ip_version = "hc2vpp-ietf-{0}-unicast-routing:{0}".format(
95 protocol = "vpp-routing:vpp-protocol-attributes"
97 ip_version = ip_version
98 protocol = "vpp-protocol-attributes"
101 "control-plane-protocol": [
104 "description": "hc2vpp-csit test route",
118 path = "/control-plane-protocol/hc2vpp-ietf-routing:static/{0}".format(name)
119 return RoutingKeywords._set_routing_table_properties(
120 node, path, full_data)
123 def delete_routing_table(node, name):
124 """Delete the specified routing table from configuration data.
126 :param node: Honeycomb node.
127 :param name: Name of the table.
130 :returns: Content of response.
134 path = "/control-plane-protocol/hc2vpp-ietf-routing:static/{0}".format(name)
135 return RoutingKeywords._set_routing_table_properties(node, path)
138 def get_routing_table_oper(node, name, ip_version):
139 """Retrieve operational data about the specified routing table.
141 :param node: Honeycomb node.
142 :param name: Name of the routing table.
143 :param ip_version: IP protocol version, ipv4 or ipv6.
146 :type ip_version: str
147 :returns: Routing table operational data.
149 :raises HoneycombError: If the operation fails.
152 path = "/control-plane-protocol/hc2vpp-ietf-routing:static/{0}".format(name)
153 status_code, resp = HcUtil.\
154 get_honeycomb_data(node, "oper_routing_table", path)
156 if status_code != HTTPCodes.OK:
157 raise HoneycombError(
158 "Not possible to get operational information about the "
159 "routing tables. Status code: {0}.".format(status_code))
161 data = RoutingKeywords.clean_routing_oper_data(
162 resp['control-plane-protocol'][0]['static-routes']
163 ['hc2vpp-ietf-{0}-unicast-routing:{0}'.format(ip_version)]['route'])
168 def clean_routing_oper_data(data):
169 """Prepare received routing operational data to be verified against
172 :param data: Routing operational data.
174 :returns: Routing operational data without entry ID numbers.
179 # ID values are auto-incremented based on existing routes in VPP
181 if "next-hop-list" in item.keys():
182 for item2 in item["next-hop-list"]["next-hop"]:
183 item2.pop("id", None)
185 if "next-hop-list" in item.keys():
186 # List items come in random order
187 item["next-hop-list"]["next-hop"].sort()
192 def log_routing_configuration(node):
193 """Retrieve route configuration using VAT and print the response
196 :param node: VPP node.
200 with VatTerminal(node) as vat:
201 vat.vat_terminal_exec_cmd("ip_fib_dump")
204 def configure_interface_slaac(node, interface, slaac_data=None):
205 """Configure SLAAC on the specified interfaces.
207 :param node: Honeycomb node.
208 :param interface: Interface to configure SLAAC.
209 :param slaac_data: Dictionary of configurations to apply. \
210 If it is None then the existing configuration is removed.
213 :type slaac_data: dict of dicts
214 :returns: Content of response.
216 :raises HoneycombError: If RA could not be configured.
219 interface = Topology.convert_interface_reference(
220 node, interface, 'name')
221 interface = interface.replace('/', '%2F')
222 path = 'interface/' + interface + '/ipv6/ipv6-router-advertisements'
225 status_code, _ = HcUtil.delete_honeycomb_data(
226 node, 'config_slaac', path)
229 'ipv6-router-advertisements': slaac_data
232 status_code, _ = HcUtil.put_honeycomb_data(
233 node, 'config_slaac', data, path)
235 if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
236 raise HoneycombError(
237 'Configuring SLAAC failed. Status code:{0}'.format(status_code))
240 def get_interface_slaac_oper_data(node, interface):
241 """Get operational data about SLAAC table present on the node.
243 :param node: Honeycomb node.
244 :param interface: Interface SLAAC data are retrieved from.
247 :returns: dict of SLAAC operational data.
249 :raises HoneycombError: If status code differs from successful.
251 interface = Topology.convert_interface_reference(
252 node, interface, 'name')
253 interface = interface.replace('/', '%2F')
254 path = 'interface/' + interface + '/ipv6/ipv6-router-advertisements'
256 status_code, resp = HcUtil.\
257 get_honeycomb_data(node, "config_slaac", path)
259 if status_code != HTTPCodes.OK:
260 raise HoneycombError(
261 "Not possible to get operational information about SLAAC. "
262 "Status code: {0}.".format(status_code))
265 'hc2vpp-ietf-ipv6-unicast-routing:ipv6-router-advertisements']
266 return {k: str(v) for k, v in dict_of_str.items()}
267 except (KeyError, TypeError):
271 def configure_policer(node, policy_name, policer_data=None):
272 """Configure Policer on the specified node.
274 :param node: Honeycomb node.
275 :param policer_data: Dictionary of configurations to apply. \
276 If it is None then the existing configuration is removed.
278 :type policer_data: dict
279 :returns: Content of response.
281 :raises HoneycombError: If policer could not be configured.
284 path = '/' + policy_name
287 status_code, _ = HcUtil.delete_honeycomb_data(
288 node, 'config_policer', path)
291 'policer': policer_data
294 status_code, _ = HcUtil.put_honeycomb_data(
295 node, 'config_policer', data, path)
297 if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
298 raise HoneycombError(
299 'Configuring policer failed. Status code:{0}'\
300 .format(status_code))
303 def get_policer_oper_data(node, policy_name):
304 """Get operational data about Policer on the node.
306 :param node: Honeycomb node.
308 :returns: dict of Policer operational data.
310 :raises HoneycombError: If status code differs from successful.
313 path = '/' + policy_name
315 status_code, resp = HcUtil.\
316 get_honeycomb_data(node, "oper_policer", path)
318 if status_code != HTTPCodes.OK:
319 raise HoneycombError(
320 "Not possible to get operational information about Policer. "
321 "Status code: {0}.".format(status_code))
323 return resp['policer']
324 except (KeyError, TypeError):