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(
120 return RoutingKeywords._set_routing_table_properties(
121 node, path, full_data)
124 def delete_routing_table(node, name):
125 """Delete the specified routing table from configuration data.
127 :param node: Honeycomb node.
128 :param name: Name of the table.
131 :returns: Content of response.
135 path = "/control-plane-protocol/hc2vpp-ietf-routing:static/{0}".format(
137 return RoutingKeywords._set_routing_table_properties(node, path)
140 def get_routing_table_oper(node, name, ip_version):
141 """Retrieve operational data about the specified routing table.
143 :param node: Honeycomb node.
144 :param name: Name of the routing table.
145 :param ip_version: IP protocol version, ipv4 or ipv6.
148 :type ip_version: str
149 :returns: Routing table operational data.
151 :raises HoneycombError: If the operation fails.
154 path = "/control-plane-protocol/hc2vpp-ietf-routing:static/{0}".format(
156 status_code, resp = HcUtil.\
157 get_honeycomb_data(node, "oper_routing_table", path)
159 if status_code != HTTPCodes.OK:
160 raise HoneycombError(
161 "Not possible to get operational information about the "
162 "routing tables. Status code: {0}.".format(status_code))
164 data = RoutingKeywords.clean_routing_oper_data(
165 resp['control-plane-protocol'][0]['static-routes']
166 ['hc2vpp-ietf-{0}-unicast-routing:{0}'.format(ip_version)]['route'])
171 def clean_routing_oper_data(data):
172 """Prepare received routing operational data to be verified against
175 :param data: Routing operational data.
177 :returns: Routing operational data without entry ID numbers.
182 # ID values are auto-incremented based on existing routes in VPP
184 if "next-hop-list" in item.keys():
185 for item2 in item["next-hop-list"]["next-hop"]:
186 item2.pop("id", None)
188 if "next-hop-list" in item.keys():
189 # List items come in random order
190 item["next-hop-list"]["next-hop"].sort()
195 def log_routing_configuration(node):
196 """Retrieve route configuration using VAT and print the response
199 :param node: VPP node.
203 with VatTerminal(node) as vat:
204 vat.vat_terminal_exec_cmd("ip_fib_dump")
207 def configure_interface_slaac(node, interface, slaac_data=None):
208 """Configure SLAAC on the specified interfaces.
210 :param node: Honeycomb node.
211 :param interface: Interface to configure SLAAC.
212 :param slaac_data: Dictionary of configurations to apply. \
213 If it is None then the existing configuration is removed.
216 :type slaac_data: dict of dicts
217 :returns: Content of response.
219 :raises HoneycombError: If RA could not be configured.
222 interface = Topology.convert_interface_reference(
223 node, interface, 'name')
224 interface = interface.replace('/', '%2F')
225 path = 'interface/' + interface + '/ipv6/ipv6-router-advertisements'
228 status_code, _ = HcUtil.delete_honeycomb_data(
229 node, 'config_slaac', path)
232 'ipv6-router-advertisements': slaac_data
235 status_code, _ = HcUtil.put_honeycomb_data(
236 node, 'config_slaac', data, path)
238 if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
239 raise HoneycombError(
240 'Configuring SLAAC failed. Status code:{0}'.format(status_code))
243 def get_interface_slaac_oper_data(node, interface):
244 """Get operational data about SLAAC table present on the node.
246 :param node: Honeycomb node.
247 :param interface: Interface SLAAC data are retrieved from.
250 :returns: dict of SLAAC operational data.
252 :raises HoneycombError: If status code differs from successful.
254 interface = Topology.convert_interface_reference(
255 node, interface, 'name')
256 interface = interface.replace('/', '%2F')
257 path = 'interface/' + interface + '/ipv6/ipv6-router-advertisements'
259 status_code, resp = HcUtil.\
260 get_honeycomb_data(node, "config_slaac", path)
262 if status_code != HTTPCodes.OK:
263 raise HoneycombError(
264 "Not possible to get operational information about SLAAC. "
265 "Status code: {0}.".format(status_code))
268 'hc2vpp-ietf-ipv6-unicast-routing:ipv6-router-advertisements']
269 return {k: str(v) for k, v in dict_of_str.items()}
270 except (KeyError, TypeError):
274 def configure_policer(node, policy_name, policer_data=None):
275 """Configure Policer on the specified node.
277 :param node: Honeycomb node.
278 :param policer_data: Dictionary of configurations to apply. \
279 If it is None then the existing configuration is removed.
281 :type policer_data: dict
282 :returns: Content of response.
284 :raises HoneycombError: If policer could not be configured.
287 path = '/' + policy_name
290 status_code, _ = HcUtil.delete_honeycomb_data(
291 node, 'config_policer', path)
294 'policer': policer_data
297 status_code, _ = HcUtil.put_honeycomb_data(
298 node, 'config_policer', data, path)
300 if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
301 raise HoneycombError(
302 'Configuring policer failed. Status code:{0}'\
303 .format(status_code))
306 def get_policer_oper_data(node, policy_name):
307 """Get operational data about Policer on the node.
309 :param node: Honeycomb node.
311 :returns: dict of Policer operational data.
313 :raises HoneycombError: If status code differs from successful.
316 path = '/' + policy_name
318 status_code, resp = HcUtil.\
319 get_honeycomb_data(node, "oper_policer", path)
321 if status_code != HTTPCodes.OK:
322 raise HoneycombError(
323 "Not possible to get operational information about Policer. "
324 "Status code: {0}.".format(status_code))
326 return resp['policer']
327 except (KeyError, TypeError):