HC Test: improve functional suite setup and teardown
[csit.git] / resources / libraries / python / honeycomb / HcAPIKwInterfaces.py
1 # Copyright (c) 2017 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 """Keywords to manipulate interface configuration using Honeycomb REST API.
15
16 The keywords make possible to put and get configuration data and to get
17 operational data.
18 """
19 from robot.api import logger
20
21 from resources.libraries.python.topology import Topology
22 from resources.libraries.python.HTTPRequest import HTTPCodes
23 from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError
24 from resources.libraries.python.honeycomb.HoneycombUtil \
25     import DataRepresentation
26 from resources.libraries.python.honeycomb.HoneycombUtil \
27     import HoneycombUtil as HcUtil
28
29
30 class InterfaceKeywords(object):
31     """Keywords for Interface manipulation.
32
33     Implements keywords which get configuration and operational data about
34     vpp interfaces and set the interface's parameters using Honeycomb REST API.
35     """
36
37     INTF_PARAMS = ("name", "description", "type", "enabled",
38                    "link-up-down-trap-enable", "v3po:l2", "v3po:vxlan-gpe",
39                    "vpp-vlan:sub-interfaces")
40     IPV4_PARAMS = ("enabled", "forwarding", "mtu")
41     IPV6_PARAMS = ("enabled", "forwarding", "mtu", "dup-addr-detect-transmits")
42     IPV6_AUTOCONF_PARAMS = ("create-global-addresses",
43                             "create-temporary-addresses",
44                             "temporary-valid-lifetime",
45                             "temporary-preferred-lifetime")
46     ETH_PARAMS = ("mtu", )
47     ROUTING_PARAMS = ("ipv4-vrf-id", "ipv6-vrf-id")
48     VXLAN_PARAMS = ("src", "dst", "vni", "encap-vrf-id")
49     L2_PARAMS = ("bridge-domain", "split-horizon-group",
50                  "bridged-virtual-interface")
51     TAP_PARAMS = ("tap-name", "mac", "device-instance")
52     VHOST_USER_PARAMS = ("socket", "role")
53     SUB_IF_PARAMS = ("identifier",
54                      "vlan-type",
55                      "enabled")
56     SUB_IF_MATCH = ("default",
57                     "untagged",
58                     "vlan-tagged",
59                     "vlan-tagged-exact-match")
60     BD_PARAMS = ("bridge-domain",
61                  "split-horizon-group",
62                  "bridged-virtual-interface")
63     VXLAN_GPE_PARAMS = ("local",
64                         "remote",
65                         "vni",
66                         "next-protocol",
67                         "encap-vrf-id",
68                         "decap-vrf-id")
69
70     def __init__(self):
71         pass
72
73     @staticmethod
74     def _configure_interface(node, interface, data,
75                              data_representation=DataRepresentation.JSON):
76         """Send interface configuration data and check the response.
77
78         :param node: Honeycomb node.
79         :param interface: The name of interface.
80         :param data: Configuration data to be sent in PUT request.
81         :param data_representation: How the data is represented.
82         :type node: dict
83         :type interface: str
84         :type data: dict
85         :type data_representation: DataRepresentation
86         :returns: Content of response.
87         :rtype: bytearray
88         :raises HoneycombError: If the status code in response on PUT is not
89         200 = OK.
90         """
91
92         status_code, resp = HcUtil.\
93             put_honeycomb_data(node, "config_vpp_interfaces", data,
94                                data_representation=data_representation)
95         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
96             raise HoneycombError(
97                 "The configuration of interface '{0}' was not successful. "
98                 "Status code: {1}.".format(interface, status_code))
99         return resp
100
101     @staticmethod
102     def get_all_interfaces_cfg_data(node):
103         """Get configuration data about all interfaces from Honeycomb.
104
105         :param node: Honeycomb node.
106         :type node: dict
107         :returns: Configuration data about all interfaces from Honeycomb.
108         :rtype: list
109         :raises HoneycombError: If it is not possible to get configuration data.
110         """
111
112         status_code, resp = HcUtil.\
113             get_honeycomb_data(node, "config_vpp_interfaces")
114         if status_code != HTTPCodes.OK:
115             raise HoneycombError(
116                 "Not possible to get configuration information about the "
117                 "interfaces. Status code: {0}.".format(status_code))
118         try:
119             return resp["interfaces"]["interface"]
120
121         except (KeyError, TypeError):
122             return []
123
124     @staticmethod
125     def get_interface_cfg_data(node, interface):
126         """Get configuration data about the given interface from Honeycomb.
127
128         :param node: Honeycomb node.
129         :param interface: The name of interface.
130         :type node: dict
131         :type interface: str
132         :returns: Configuration data about the given interface from Honeycomb.
133         :rtype: dict
134         """
135
136         intfs = InterfaceKeywords.get_all_interfaces_cfg_data(node)
137         for intf in intfs:
138             if intf["name"] == interface:
139                 return intf
140         return {}
141
142     @staticmethod
143     def get_all_interfaces_oper_data(node):
144         """Get operational data about all interfaces from Honeycomb.
145
146         :param node: Honeycomb node.
147         :type node: dict
148         :returns: Operational data about all interfaces from Honeycomb.
149         :rtype: list
150         :raises HoneycombError: If it is not possible to get operational data.
151         """
152
153         status_code, resp = HcUtil.\
154             get_honeycomb_data(node, "oper_vpp_interfaces")
155         if status_code != HTTPCodes.OK:
156             raise HoneycombError(
157                 "Not possible to get operational information about the "
158                 "interfaces. Status code: {0}.".format(status_code))
159         try:
160             return resp["interfaces-state"]["interface"]
161
162         except (KeyError, TypeError):
163             return []
164
165     @staticmethod
166     def get_disabled_interfaces_oper_data(node):
167         """Get operational data about all disabled interfaces from Honeycomb.
168
169         :param node: Honeycomb node.
170         :type node: dict
171         :returns: Operational data about disabled interfaces.
172         :rtype: list
173         :raises HoneycombError: If it is not possible to get operational data.
174         """
175
176         status_code, resp = HcUtil. \
177             get_honeycomb_data(node, "oper_disabled_interfaces")
178         if status_code == HTTPCodes.NOT_FOUND:
179             raise HoneycombError(
180                 "No disabled interfaces present on node."
181             )
182         if status_code != HTTPCodes.OK:
183             raise HoneycombError(
184                 "Not possible to get operational information about the "
185                 "interfaces. Status code: {0}.".format(status_code))
186         try:
187             return resp["disabled-interfaces"]["disabled-interface-index"]
188
189         except (KeyError, TypeError):
190             return []
191
192     @staticmethod
193     def get_interface_oper_data(node, interface):
194         """Get operational data about the given interface from Honeycomb.
195
196         :param node: Honeycomb node.
197         :param interface: The name of interface.
198         :type node: dict
199         :type interface: str
200         :returns: Operational data about the given interface from Honeycomb.
201         :rtype: dict
202         """
203
204         try:
205             interface = Topology.convert_interface_reference(
206                 node, interface, "name")
207         except RuntimeError:
208             if isinstance(interface, basestring):
209                 # Probably name of a custom interface (TAP, VxLAN, Vhost, ...)
210                 pass
211             else:
212                 raise
213
214         intfs = InterfaceKeywords.get_all_interfaces_oper_data(node)
215         for intf in intfs:
216             if intf["name"] == interface:
217                 return intf
218         return {}
219
220     @staticmethod
221     def _set_interface_properties(node, interface, path, new_value=None):
222         """Set interface properties.
223
224         This method reads interface configuration data, creates, changes or
225         removes the requested data and puts it back to Honeycomb.
226
227         :param node: Honeycomb node.
228         :param interface: The name of interface.
229         :param path:  Path to data we want to change / create / remove.
230         :param new_value: The new value to be set. If None, the item will be
231         removed.
232         :type node: dict
233         :type interface: str
234         :type path: tuple
235         :type new_value: str, dict or list
236         :returns: Content of response.
237         :rtype: bytearray
238         :raises HoneycombError: If it is not possible to get or set the data.
239         """
240
241         status_code, resp = HcUtil.\
242             get_honeycomb_data(node, "config_vpp_interfaces")
243         if status_code != HTTPCodes.OK:
244             raise HoneycombError(
245                 "Not possible to get configuration information about the "
246                 "interfaces. Status code: {0}.".format(status_code))
247
248         if new_value:
249             new_data = HcUtil.set_item_value(resp, path, new_value)
250         else:
251             new_data = HcUtil.remove_item(resp, path)
252         return InterfaceKeywords._configure_interface(node, interface, new_data)
253
254     @staticmethod
255     def honeycomb_set_interface_state(node, interface, state="up"):
256         """Set VPP interface state.
257
258         The keyword changes the administration state of interface to up or down
259         depending on the parameter "state".
260
261         :param node: Honeycomb node.
262         :param interface: Interface name, key, link name or sw_if_index.
263         :param state: The requested state, only "up" and "down" are valid
264         values.
265         :type node: dict
266         :type interface: str
267         :type state: str
268         :returns: Content of response.
269         :rtype: bytearray
270         :raises KeyError: If the argument "state" is nor "up" or "down".
271         :raises HoneycombError: If the interface is not present on the node.
272         """
273
274         intf_state = {"up": "true",
275                       "down": "false"}
276
277         interface = Topology.convert_interface_reference(
278             node, interface, "name")
279
280         intf = interface.replace("/", "%2F")
281         path = "/interface/{0}".format(intf)
282
283         status_code, resp = HcUtil.\
284             get_honeycomb_data(node, "config_vpp_interfaces", path)
285         if status_code != HTTPCodes.OK:
286             raise HoneycombError(
287                 "Not possible to get configuration information about the "
288                 "interfaces. Status code: {0}.".format(status_code))
289
290         resp["interface"][0]["enabled"] = intf_state[state.lower()]
291
292         status_code, resp = HcUtil. \
293             put_honeycomb_data(node, "config_vpp_interfaces", resp, path,
294                                data_representation=DataRepresentation.JSON)
295         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
296             raise HoneycombError(
297                 "The configuration of interface '{0}' was not successful. "
298                 "Status code: {1}.".format(interface, status_code))
299         return resp
300
301     @staticmethod
302     def set_interface_up(node, interface):
303         """Set the administration state of VPP interface to up.
304
305         :param node: Honeycomb node.
306         :param interface: The name of interface.
307         :type node: dict
308         :type interface: str
309         :returns: Content of response
310         :rtype: bytearray
311         """
312
313         return InterfaceKeywords.honeycomb_set_interface_state(
314             node, interface, "up")
315
316     @staticmethod
317     def set_interface_down(node, interface):
318         """Set the administration state of VPP interface to down.
319
320         :param node: Honeycomb node.
321         :param interface: The name of interface.
322         :type node: dict
323         :type interface: str
324         :returns: Content of response.
325         :rtype: bytearray
326         """
327
328         return InterfaceKeywords.honeycomb_set_interface_state(
329             node, interface, "down")
330
331     @staticmethod
332     def add_bridge_domain_to_interface(node, interface, bd_name,
333                                        split_horizon_group=None, bvi=None):
334         """Add a new bridge domain to an interface and set its parameters.
335
336         :param node: Honeycomb node.
337         :param interface: Interface name, key, link name or sw_if_index.
338         :param bd_name: Bridge domain name.
339         :param split_horizon_group: Split-horizon group name.
340         :param bvi: The bridged virtual interface.
341         :type node: dict
342         :type interface: str
343         :type bd_name: str
344         :type split_horizon_group: str
345         :type bvi: str
346         :returns: Content of response.
347         :rtype: bytearray
348         :raises HoneycombError: If the interface is not present on the node.
349         """
350
351         interface = Topology.convert_interface_reference(
352             node, interface, "name")
353
354         v3po_l2 = {"bridge-domain": str(bd_name)}
355         if split_horizon_group:
356             v3po_l2["split-horizon-group"] = str(split_horizon_group)
357         if bvi:
358             v3po_l2["bridged-virtual-interface"] = str(bvi)
359
360         path = ("interfaces", ("interface", "name", str(interface)), "v3po:l2")
361
362         return InterfaceKeywords._set_interface_properties(
363             node, interface, path, v3po_l2)
364
365     @staticmethod
366     def remove_bridge_domain_from_interface(node, interface):
367         """Remove bridge domain assignment from interface.
368
369         :param node: Honeycomb node.
370         :param interface: Interface name, key, link name or sw_if_index.
371         :type node: dict
372         :type interface: str or int
373
374         :raises HoneycombError: If the operation fails.
375         """
376
377         interface = Topology.convert_interface_reference(
378             node, interface, "name")
379
380         intf = interface.replace("/", "%2F")
381
382         path = "/interface/{0}/v3po:l2".format(intf)
383
384         status_code, response = HcUtil.delete_honeycomb_data(
385             node, "config_vpp_interfaces", path)
386
387         if status_code != HTTPCodes.OK:
388             if '"error-tag":"data-missing"' in response:
389                 logger.debug("Data does not exist in path.")
390             else:
391                 raise HoneycombError(
392                     "Could not remove bridge domain assignment from interface "
393                     "'{0}'. Status code: {1}.".format(interface, status_code))
394
395     @staticmethod
396     def get_bd_oper_data_from_interface(node, interface):
397         """Returns operational data about bridge domain settings in the
398         interface.
399
400         :param node: Honeycomb node.
401         :param interface: The name of interface.
402         :type node: dict
403         :type interface: str
404         :returns: Operational data about bridge domain settings in the
405         interface.
406         :rtype: dict
407         """
408
409         if_data = InterfaceKeywords.get_interface_oper_data(node, interface)
410
411         if if_data:
412             try:
413                 return if_data["v3po:l2"]
414             except KeyError:
415                 return {}
416         return {}
417
418     @staticmethod
419     def configure_interface_base(node, interface, param, value):
420         """Configure the base parameters of interface.
421
422         :param node: Honeycomb node.
423         :param interface: The name of interface.
424         :param param: Parameter to configure (set, change, remove)
425         :param value: The value of parameter. If None, the parameter will be
426         removed.
427         :type node: dict
428         :type interface: str
429         :type param: str
430         :type value: str
431         :returns: Content of response.
432         :rtype: bytearray
433         :raises HoneycombError: If the parameter is not valid.
434         """
435
436         if param not in InterfaceKeywords.INTF_PARAMS:
437             raise HoneycombError("The parameter {0} is invalid.".format(param))
438
439         path = ("interfaces", ("interface", "name", interface), param)
440         return InterfaceKeywords._set_interface_properties(
441             node, interface, path, value)
442
443     @staticmethod
444     def configure_interface_ipv4(node, interface, param, value):
445         """Configure IPv4 parameters of interface.
446
447         :param node: Honeycomb node.
448         :param interface: The name of interface.
449         :param param: Parameter to configure (set, change, remove)
450         :param value: The value of parameter. If None, the parameter will be
451         removed.
452         :type node: dict
453         :type interface: str
454         :type param: str
455         :type value: str
456         :returns: Content of response.
457         :rtype: bytearray
458         :raises HoneycombError: If the parameter is not valid.
459         """
460
461         interface = Topology.convert_interface_reference(
462             node, interface, "name")
463
464         if param not in InterfaceKeywords.IPV4_PARAMS:
465             raise HoneycombError("The parameter {0} is invalid.".format(param))
466
467         path = ("interfaces", ("interface", "name", interface),
468                 "ietf-ip:ipv4", param)
469         return InterfaceKeywords._set_interface_properties(
470             node, interface, path, value)
471
472     @staticmethod
473     def add_first_ipv4_address(node, interface, ip_addr, network):
474         """Add the first IPv4 address.
475
476         If there are any other addresses configured, they will be removed.
477
478         :param node: Honeycomb node.
479         :param interface: The name of interface.
480         :param ip_addr: IPv4 address to be set.
481         :param network: Netmask or length of network prefix.
482         :type node: dict
483         :type interface: str
484         :type ip_addr: str
485         :type network: str or int
486         :returns: Content of response.
487         :rtype: bytearray
488         :raises ValueError: If the provided netmask or prefix is not valid.
489         :raises HoneycombError: If the operation fails.
490         """
491
492         interface = InterfaceKeywords.handle_interface_reference(
493             node, interface)
494
495         path = "/interface/{0}/ietf-ip:ipv4".format(interface)
496         if isinstance(network, basestring):
497             data = {
498                 "ietf-ip:ipv4": {
499                     "address": [{"ip": ip_addr, "netmask": network}, ]}}
500         elif isinstance(network, int) and (0 < network < 33):
501             data = {
502                 "ietf-ip:ipv4": {
503                     "address": [{"ip": ip_addr, "prefix-length": network}, ]}}
504         else:
505             raise ValueError("Value {0} is not a valid netmask or network "
506                              "prefix length.".format(network))
507         status_code, _ = HcUtil.put_honeycomb_data(
508             node, "config_vpp_interfaces", data, path)
509
510         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
511             raise HoneycombError(
512                 "Configuring IPv4 address failed. "
513                 "Status code:{0}".format(status_code))
514
515     @staticmethod
516     def add_ipv4_address(node, interface, ip_addr, network):
517         """Add IPv4 address.
518
519         :param node: Honeycomb node.
520         :param interface: The name of interface.
521         :param ip_addr: IPv4 address to be set.
522         :param network: Netmask or length of network prefix.
523         :type node: dict
524         :type interface: str
525         :type ip_addr: str
526         :type network: str or int
527         :returns: Content of response.
528         :rtype: bytearray
529         :raises HoneycombError: If the provided netmask or prefix is not valid.
530         """
531
532         interface = Topology.convert_interface_reference(
533             node, interface, "name")
534
535         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
536                 "address")
537         if isinstance(network, basestring):
538             address = [{"ip": ip_addr, "netmask": network}]
539         elif isinstance(network, int) and (0 < network < 33):
540             address = [{"ip": ip_addr, "prefix-length": network}]
541         else:
542             raise HoneycombError("Value {0} is not a valid netmask or network "
543                                  "prefix length.".format(network))
544         return InterfaceKeywords._set_interface_properties(
545             node, interface, path, address)
546
547     @staticmethod
548     def remove_all_ipv4_addresses(node, interface):
549         """Remove all IPv4 addresses from interface.
550
551         :param node: Honeycomb node.
552         :param interface: The name of interface.
553         :type node: dict
554         :type interface: str
555         :returns: Content of response.
556         :rtype: bytearray
557         """
558
559         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
560                 "address")
561         return InterfaceKeywords._set_interface_properties(
562             node, interface, path, None)
563
564     @staticmethod
565     def add_ipv4_neighbor(node, interface, ip_addr, link_layer_address):
566         """Add the IPv4 neighbour.
567
568         :param node: Honeycomb node.
569         :param interface: The name of interface.
570         :param ip_addr: IPv4 address of neighbour to be set.
571         :param link_layer_address: Link layer address.
572         :type node: dict
573         :type interface: str
574         :type ip_addr: str
575         :type link_layer_address: str
576         :returns: Content of response.
577         :rtype: bytearray
578         """
579
580         interface = Topology.convert_interface_reference(
581             node, interface, "name")
582
583         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
584                 "neighbor")
585         neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ]
586         return InterfaceKeywords._set_interface_properties(
587             node, interface, path, neighbor)
588
589     @staticmethod
590     def remove_all_ipv4_neighbors(node, interface):
591         """Remove all IPv4 neighbours.
592
593         :param node: Honeycomb node.
594         :param interface: The name of interface.
595         :type node: dict
596         :type interface: str
597         :returns: Content of response.
598         :rtype: bytearray
599         """
600
601         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
602                 "neighbor")
603         return InterfaceKeywords._set_interface_properties(
604             node, interface, path, None)
605
606     @staticmethod
607     def configure_interface_ipv6(node, interface, param, value):
608         """Configure IPv6 parameters of interface
609
610         :param node: Honeycomb node.
611         :param interface: The name of interface.
612         :param param: Parameter to configure (set, change, remove)
613         :param value: The value of parameter. If None, the parameter will be
614         removed.
615         :type node: dict
616         :type interface: str
617         :type param: str
618         :type value: str
619         :returns: Content of response.
620         :rtype: bytearray
621         :raises HoneycombError: If the parameter is not valid.
622         """
623
624         if param in InterfaceKeywords.IPV6_PARAMS:
625             path = ("interfaces", ("interface", "name", interface),
626                     "ietf-ip:ipv6", param)
627         elif param in InterfaceKeywords.IPV6_AUTOCONF_PARAMS:
628             path = ("interfaces", ("interface", "name", interface),
629                     "ietf-ip:ipv6", "autoconf", param)
630         else:
631             raise HoneycombError("The parameter {0} is invalid.".format(param))
632
633         return InterfaceKeywords._set_interface_properties(
634             node, interface, path, value)
635
636     @staticmethod
637     def add_first_ipv6_address(node, interface, ip_addr, prefix_len):
638         """Add the first IPv6 address.
639
640         If there are any other addresses configured, they will be removed.
641
642         :param node: Honeycomb node.
643         :param interface: The name of interface.
644         :param ip_addr: IPv6 address to be set.
645         :param prefix_len: Prefix length.
646         :type node: dict
647         :type interface: str
648         :type ip_addr: str
649         :type prefix_len: str
650         :returns: Content of response.
651         :rtype: bytearray
652         """
653
654         interface = Topology.convert_interface_reference(
655             node, interface, "name")
656
657         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6")
658         address = {"address": [{"ip": ip_addr, "prefix-length": prefix_len}, ]}
659         return InterfaceKeywords._set_interface_properties(
660             node, interface, path, address)
661
662     @staticmethod
663     def add_ipv6_address(node, interface, ip_addr, prefix_len):
664         """Add IPv6 address.
665
666         :param node: Honeycomb node.
667         :param interface: The name of interface.
668         :param ip_addr: IPv6 address to be set.
669         :param prefix_len: Prefix length.
670         :type node: dict
671         :type interface: str
672         :type ip_addr: str
673         :type prefix_len: str
674         :returns: Content of response.
675         :rtype: bytearray
676         """
677
678         interface = Topology.convert_interface_reference(
679             node, interface, "name")
680
681         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
682                 "address")
683         address = [{"ip": ip_addr, "prefix-length": prefix_len}, ]
684         return InterfaceKeywords._set_interface_properties(
685             node, interface, path, address)
686
687     @staticmethod
688     def remove_all_ipv6_addresses(node, interface):
689         """Remove all IPv6 addresses from interface.
690
691         :param node: Honeycomb node.
692         :param interface: The name of interface.
693         :type node: dict
694         :type interface: str
695         :returns: Content of response.
696         :rtype: bytearray
697         """
698
699         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
700                 "address")
701         return InterfaceKeywords._set_interface_properties(
702             node, interface, path, None)
703
704     @staticmethod
705     def add_ipv6_neighbor(node, interface, ip_addr, link_layer_address):
706         """Add the IPv6 neighbour.
707
708         :param node: Honeycomb node.
709         :param interface: The name of interface.
710         :param ip_addr: IPv6 address of neighbour to be set.
711         :param link_layer_address: Link layer address.
712         :type node: dict
713         :type interface: str
714         :type ip_addr: str
715         :type link_layer_address: str
716         :returns: Content of response.
717         :rtype: bytearray
718         """
719
720         interface = Topology.convert_interface_reference(
721             node, interface, "name")
722
723         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
724                 "neighbor")
725         neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ]
726         return InterfaceKeywords._set_interface_properties(
727             node, interface, path, neighbor)
728
729     @staticmethod
730     def remove_all_ipv6_neighbors(node, interface):
731         """Remove all IPv6 neighbours.
732
733         :param node: Honeycomb node.
734         :param interface: The name of interface.
735         :type node: dict
736         :type interface: str
737         :returns: Content of response.
738         :rtype: bytearray
739         """
740
741         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
742                 "neighbor")
743         return InterfaceKeywords._set_interface_properties(
744             node, interface, path, None)
745
746     @staticmethod
747     def configure_interface_ethernet(node, interface, param, value):
748         """Configure the ethernet parameters of interface.
749
750         :param node: Honeycomb node.
751         :param interface: The name of interface.
752         :param param: Parameter to configure (set, change, remove)
753         :param value: The value of parameter. If None, the parameter will be
754         removed.
755         :type node: dict
756         :type interface: str
757         :type param: str
758         :type value: str
759         :returns: Content of response.
760         :rtype: bytearray
761         :raises HoneycombError: If the parameter is not valid.
762         """
763
764         if param not in InterfaceKeywords.ETH_PARAMS:
765             raise HoneycombError("The parameter {0} is invalid.".format(param))
766         path = ("interfaces", ("interface", "name", interface), "v3po:ethernet",
767                 param)
768         return InterfaceKeywords._set_interface_properties(
769             node, interface, path, value)
770
771     @staticmethod
772     def configure_interface_routing(node, interface, param, value):
773         """Configure the routing parameters of interface.
774
775         :param node: Honeycomb node.
776         :param interface: The name of interface.
777         :param param: Parameter to configure (set, change, remove)
778         :param value: The value of parameter. If None, the parameter will be
779         removed.
780         :type node: dict
781         :type interface: str
782         :type param: str
783         :type value: str
784         :returns: Content of response.
785         :rtype: bytearray
786         :raises HoneycombError: If the parameter is not valid.
787         """
788
789         interface = Topology.convert_interface_reference(
790             node, interface, "name")
791
792         if param not in InterfaceKeywords.ROUTING_PARAMS:
793             raise HoneycombError("The parameter {0} is invalid.".format(param))
794
795         path = ("interfaces", ("interface", "name", interface), "v3po:routing",
796                 param)
797         return InterfaceKeywords._set_interface_properties(
798             node, interface, path, value)
799
800     @staticmethod
801     def honeycomb_create_vxlan_interface(node, interface, **kwargs):
802         """Create a new VxLAN interface.
803
804         :param node: Honeycomb node.
805         :param interface: The name of interface.
806         :param kwargs: Parameters and their values. The accepted parameters are
807         defined in InterfaceKeywords.VXLAN_PARAMS.
808         :type node: dict
809         :type interface: str
810         :type kwargs: dict
811         :returns: Content of response.
812         :rtype: bytearray
813         :raises HoneycombError: If the parameter is not valid.
814         """
815
816         new_vx_lan = {
817             "name": interface,
818             "type": "v3po:vxlan-tunnel",
819             "v3po:vxlan": {}
820         }
821         for param, value in kwargs.items():
822             if param not in InterfaceKeywords.VXLAN_PARAMS:
823                 raise HoneycombError("The parameter {0} is invalid.".
824                                      format(param))
825             new_vx_lan["v3po:vxlan"][param] = value
826
827         path = ("interfaces", "interface")
828         vx_lan_structure = [new_vx_lan, ]
829         return InterfaceKeywords._set_interface_properties(
830             node, interface, path, vx_lan_structure)
831
832     @staticmethod
833     def delete_interface(node, interface):
834         """Delete an interface.
835
836         :param node: Honeycomb node.
837         :param interface: The name of interface.
838         :type node: dict
839         :type interface: str
840         :returns: Content of response.
841         :rtype: bytearray
842         :raises HoneycombError: If it is not possible to get information about
843         interfaces or it is not possible to delete the interface.
844         """
845
846         path = ("interfaces", ("interface", "name", interface))
847
848         status_code, resp = HcUtil.\
849             get_honeycomb_data(node, "config_vpp_interfaces")
850         if status_code != HTTPCodes.OK:
851             raise HoneycombError(
852                 "Not possible to get configuration information about the "
853                 "interfaces. Status code: {0}.".format(status_code))
854
855         new_data = HcUtil.remove_item(resp, path)
856         status_code, resp = HcUtil.\
857             put_honeycomb_data(node, "config_vpp_interfaces", new_data)
858         if status_code != HTTPCodes.OK:
859             raise HoneycombError("Not possible to remove interface {0}. "
860                                  "Status code: {1}.".
861                                  format(interface, status_code))
862         return resp
863
864     @staticmethod
865     def honeycomb_configure_interface_vxlan(node, interface, **kwargs):
866         """Configure VxLAN on the interface.
867
868         The keyword configures VxLAN parameters on the given interface. The type
869         of interface must be set to "v3po:vxlan-tunnel".
870         The new VxLAN parameters overwrite the current configuration. If a
871         parameter in new configuration is missing, it is removed from VxLAN
872         configuration.
873         If the dictionary kwargs is empty, VxLAN configuration is removed.
874
875         :param node: Honeycomb node.
876         :param interface: The name of interface.
877         :param kwargs: Parameters and their values. The accepted parameters are
878         defined in InterfaceKeywords.VXLAN_PARAMS.
879         :type node: dict
880         :type interface: str
881         :type kwargs: dict
882         :returns: Content of response.
883         :rtype: bytearray
884         :raises HoneycombError: If the parameter is not valid.
885         """
886
887         vx_lan_structure = dict()
888         for param, value in kwargs.items():
889             if param not in InterfaceKeywords.VXLAN_PARAMS:
890                 raise HoneycombError("The parameter {0} is invalid.".
891                                      format(param))
892             vx_lan_structure[param] = value
893
894         path = ("interfaces", ("interface", "name", interface), "v3po:vxlan")
895         return InterfaceKeywords._set_interface_properties(
896             node, interface, path, vx_lan_structure)
897
898     @staticmethod
899     def configure_interface_l2(node, interface, param, value):
900         """Configure the L2 parameters of interface.
901
902         :param node: Honeycomb node.
903         :param interface: The name of interface.
904         :param param: Parameter to configure (set, change, remove)
905         :param value: The value of parameter. If None, the parameter will be
906         removed.
907         :type node: dict
908         :type interface: str
909         :type param: str
910         :type value: str
911         :returns: Content of response.
912         :rtype: bytearray
913         :raises HoneycombError: If the parameter is not valid.
914         """
915
916         if param not in InterfaceKeywords.L2_PARAMS:
917             raise HoneycombError("The parameter {0} is invalid.".format(param))
918         path = ("interfaces", ("interface", "name", interface), "v3po:l2",
919                 param)
920         return InterfaceKeywords._set_interface_properties(
921             node, interface, path, value)
922
923     @staticmethod
924     def create_tap_interface(node, interface, **kwargs):
925         """Create a new TAP interface.
926
927         :param node: Honeycomb node.
928         :param interface: The name of interface.
929         :param kwargs: Parameters and their values. The accepted parameters are
930         defined in InterfaceKeywords.TAP_PARAMS.
931         :type node: dict
932         :type interface: str
933         :type kwargs: dict
934         :returns: Content of response.
935         :rtype: bytearray
936         :raises HoneycombError: If the parameter is not valid.
937         """
938
939         new_tap = {
940             "name": interface,
941             "type": "v3po:tap",
942             "v3po:tap": {}
943         }
944         for param, value in kwargs.items():
945             if param not in InterfaceKeywords.TAP_PARAMS:
946                 raise HoneycombError("The parameter {0} is invalid.".
947                                      format(param))
948             new_tap["v3po:tap"][param] = value
949
950         path = ("interfaces", "interface")
951         new_tap_structure = [new_tap, ]
952         return InterfaceKeywords._set_interface_properties(
953             node, interface, path, new_tap_structure)
954
955     @staticmethod
956     def configure_interface_tap(node, interface, **kwargs):
957         """Configure TAP on the interface.
958
959         The keyword configures TAP parameters on the given interface. The type
960         of interface must be set to "v3po:tap".
961         The new TAP parameters overwrite the current configuration. If a
962         parameter in new configuration is missing, it is removed from TAP
963         configuration.
964         If the dictionary kwargs is empty, TAP configuration is removed.
965
966         :param node: Honeycomb node.
967         :param interface: The name of interface.
968         :param kwargs: Parameters and their values. The accepted parameters are
969         defined in InterfaceKeywords.TAP_PARAMS.
970         :type node: dict
971         :type interface: str
972         :type kwargs: dict
973         :returns: Content of response.
974         :rtype: bytearray
975         :raises HoneycombError: If the parameter is not valid.
976         """
977
978         tap_structure = dict()
979         for param, value in kwargs.items():
980             if param not in InterfaceKeywords.TAP_PARAMS:
981                 raise HoneycombError("The parameter {0} is invalid.".
982                                      format(param))
983             tap_structure[param] = value
984
985         path = ("interfaces", ("interface", "name", interface), "v3po:tap")
986         return InterfaceKeywords._set_interface_properties(
987             node, interface, path, tap_structure)
988
989     @staticmethod
990     def configure_interface_vhost_user(node, interface, **kwargs):
991         """Configure vhost-user on the interface.
992
993         The keyword configures vhost-user parameters on the given interface.
994         The type of interface must be set to "v3po:vhost-user".
995         The new vhost-user parameters overwrite the current configuration. If a
996         parameter in new configuration is missing, it is removed from vhost-user
997         configuration.
998         If the dictionary kwargs is empty, vhost-user configuration is removed.
999
1000         :param node: Honeycomb node.
1001         :param interface: The name of interface.
1002         :param kwargs: Parameters and their values. The accepted parameters are
1003         defined in InterfaceKeywords.VHOST_USER_PARAMS.
1004         :type node: dict
1005         :type interface: str
1006         :type kwargs: dict
1007         :returns: Content of response.
1008         :rtype: bytearray
1009         :raises HoneycombError: If the parameter is not valid.
1010         """
1011
1012         vhost_structure = dict()
1013         for param, value in kwargs.items():
1014             if param not in InterfaceKeywords.VHOST_USER_PARAMS:
1015                 raise HoneycombError("The parameter {0} is invalid.".
1016                                      format(param))
1017             vhost_structure[param] = value
1018
1019         path = ("interfaces", ("interface", "name", interface),
1020                 "v3po:vhost-user")
1021         return InterfaceKeywords._set_interface_properties(
1022             node, interface, path, vhost_structure)
1023
1024     @staticmethod
1025     def create_vhost_user_interface(node, interface, **kwargs):
1026         """Create a new vhost-user interface.
1027
1028         :param node: Honeycomb node.
1029         :param interface: The name of interface.
1030         :param kwargs: Parameters and their values. The accepted parameters are
1031         defined in InterfaceKeywords.VHOST_USER_PARAMS.
1032         :type node: dict
1033         :type interface: str
1034         :type kwargs: dict
1035         :returns: Content of response.
1036         :rtype: bytearray
1037         :raises HoneycombError: If the parameter is not valid.
1038         """
1039
1040         new_vhost = {
1041             "name": interface,
1042             "type": "v3po:vhost-user",
1043             "v3po:vhost-user": {}
1044         }
1045         for param, value in kwargs.items():
1046             if param not in InterfaceKeywords.VHOST_USER_PARAMS:
1047                 raise HoneycombError("The parameter {0} is invalid.".
1048                                      format(param))
1049             new_vhost["v3po:vhost-user"][param] = value
1050
1051         path = ("interfaces", "interface")
1052         new_vhost_structure = [new_vhost, ]
1053         return InterfaceKeywords._set_interface_properties(
1054             node, interface, path, new_vhost_structure)
1055
1056     @staticmethod
1057     def honeycomb_create_sub_interface(node, super_interface, match, tags=None,
1058                                        **kwargs):
1059         """Create a new sub-interface.
1060
1061         :param node: Honeycomb node.
1062         :param super_interface: Super interface.
1063         :param match: Match type. The valid values are defined in
1064         InterfaceKeywords.SUB_IF_MATCH.
1065         :param tags: List of tags.
1066         :param kwargs: Parameters and their values. The accepted parameters are
1067         defined in InterfaceKeywords.SUB_IF_PARAMS.
1068         :type node: dict
1069         :type super_interface: str
1070         :type match: str
1071         :type tags: list
1072         :type kwargs: dict
1073         :returns: Content of response.
1074         :rtype: bytearray
1075         :raises HoneycombError: If the parameter is not valid.
1076         :raises KeyError: If the parameter 'match' is invalid.
1077         """
1078
1079         match_type = {
1080             "default":
1081                 {"default": {}},
1082             "untagged":
1083                 {"untagged": {}},
1084             "vlan-tagged":
1085                 {"vlan-tagged": {"match-exact-tags": "false"}},
1086             "vlan-tagged-exact-match":
1087                 {"vlan-tagged": {"match-exact-tags": "true"}}
1088         }
1089
1090         new_sub_interface = {
1091             "tags": {
1092                 "tag": []
1093             },
1094         }
1095
1096         for param, value in kwargs.items():
1097             if param in InterfaceKeywords.SUB_IF_PARAMS:
1098                 new_sub_interface[param] = value
1099             else:
1100                 raise HoneycombError("The parameter {0} is invalid.".
1101                                      format(param))
1102         try:
1103             new_sub_interface["match"] = match_type[match]
1104         except KeyError:
1105             raise HoneycombError("The value '{0}' of parameter 'match' is "
1106                                  "invalid.".format(match))
1107
1108         if tags:
1109             new_sub_interface["tags"]["tag"].extend(tags)
1110
1111         path = ("interfaces",
1112                 ("interface", "name", super_interface),
1113                 "vpp-vlan:sub-interfaces",
1114                 "sub-interface")
1115         new_sub_interface_structure = [new_sub_interface, ]
1116         return InterfaceKeywords._set_interface_properties(
1117             node, super_interface, path, new_sub_interface_structure)
1118
1119     @staticmethod
1120     def get_sub_interface_oper_data(node, super_interface, identifier):
1121         """Retrieves sub-interface operational data using Honeycomb API.
1122
1123         :param node: Honeycomb node.
1124         :param super_interface: Super interface.
1125         :param identifier: The ID of sub-interface.
1126         :type node: dict
1127         :type super_interface: str
1128         :type identifier: int
1129         :returns: Sub-interface operational data.
1130         :rtype: dict
1131         :raises HoneycombError: If there is no sub-interface with the given ID.
1132         """
1133
1134         if_data = InterfaceKeywords.get_interface_oper_data(node,
1135                                                             super_interface)
1136         for sub_if in if_data["vpp-vlan:sub-interfaces"]["sub-interface"]:
1137             if str(sub_if["identifier"]) == str(identifier):
1138                 return sub_if
1139
1140         raise HoneycombError("The interface {0} does not have sub-interface "
1141                              "with ID {1}".format(super_interface, identifier))
1142
1143     @staticmethod
1144     def remove_all_sub_interfaces(node, super_interface):
1145         """Remove all sub-interfaces from the given interface.
1146
1147         :param node: Honeycomb node.
1148         :param super_interface: Super interface.
1149         :type node: dict
1150         :type super_interface: str
1151         :returns: Content of response.
1152         :rtype: bytearray
1153         """
1154
1155         path = ("interfaces",
1156                 ("interface", "name", super_interface),
1157                 "vpp-vlan:sub-interfaces")
1158
1159         return InterfaceKeywords._set_interface_properties(
1160             node, super_interface, path, {})
1161
1162     @staticmethod
1163     def set_sub_interface_state(node, super_interface, identifier, state):
1164         """Set the administrative state of sub-interface.
1165
1166         :param node: Honeycomb node.
1167         :param super_interface: Super interface.
1168         :param identifier: The ID of sub-interface.
1169         :param state: Required sub-interface state - up or down.
1170         :type node: dict
1171         :type super_interface: str
1172         :type identifier: int
1173         :type state: str
1174         :returns: Content of response.
1175         :rtype: bytearray
1176         """
1177
1178         super_interface = Topology.convert_interface_reference(
1179             node, super_interface, "name")
1180
1181         intf_state = {"up": "true",
1182                       "down": "false"}
1183
1184         path = ("interfaces",
1185                 ("interface", "name", super_interface),
1186                 "vpp-vlan:sub-interfaces",
1187                 ("sub-interface", "identifier", int(identifier)),
1188                 "enabled")
1189
1190         return InterfaceKeywords._set_interface_properties(
1191             node, super_interface, path, intf_state[state])
1192
1193     @staticmethod
1194     def add_bridge_domain_to_sub_interface(node, super_interface, identifier,
1195                                            config):
1196         """Add a sub-interface to a bridge domain and set its parameters.
1197
1198         :param node: Honeycomb node.
1199         :param super_interface: Super interface.
1200         :param identifier: The ID of sub-interface.
1201         :param config: Bridge domain configuration.
1202         :type node: dict
1203         :type super_interface: str
1204         :type identifier: int
1205         :type config: dict
1206         :returns: Content of response.
1207         :rtype: bytearray
1208         """
1209
1210         path = ("interfaces",
1211                 ("interface", "name", super_interface),
1212                 "vpp-vlan:sub-interfaces",
1213                 ("sub-interface", "identifier", int(identifier)),
1214                 "l2")
1215
1216         return InterfaceKeywords._set_interface_properties(
1217             node, super_interface, path, config)
1218
1219     @staticmethod
1220     def get_bd_data_from_sub_interface(node, super_interface, identifier):
1221         """Get the operational data about the bridge domain from sub-interface.
1222
1223         :param node: Honeycomb node.
1224         :param super_interface: Super interface.
1225         :param identifier: The ID of sub-interface.
1226         :type node: dict
1227         :type super_interface: str
1228         :type identifier: int
1229         :returns: Operational data about the bridge domain.
1230         :rtype: dict
1231         :raises HoneycombError: If there is no sub-interface with the given ID.
1232         """
1233
1234         try:
1235             bd_data = InterfaceKeywords.get_sub_interface_oper_data(
1236                 node, super_interface, identifier)["l2"]
1237             return bd_data
1238         except KeyError:
1239             raise HoneycombError("The operational data does not contain "
1240                                  "information about a bridge domain.")
1241
1242     @staticmethod
1243     def configure_tag_rewrite(node, super_interface, identifier, config):
1244         """Add / change / disable vlan tag rewrite on a sub-interface.
1245
1246         :param node: Honeycomb node.
1247         :param super_interface: Super interface.
1248         :param identifier: The ID of sub-interface.
1249         :param config: Rewrite tag configuration.
1250         :type node: dict
1251         :type super_interface: str
1252         :type identifier: int
1253         :type config: dict
1254         :returns: Content of response.
1255         :rtype: bytearray
1256         """
1257
1258         path = ("interfaces",
1259                 ("interface", "name", super_interface),
1260                 "vpp-vlan:sub-interfaces",
1261                 ("sub-interface", "identifier", int(identifier)),
1262                 "l2",
1263                 "rewrite")
1264
1265         return InterfaceKeywords._set_interface_properties(
1266             node, super_interface, path, config)
1267
1268     @staticmethod
1269     def get_tag_rewrite_oper_data(node, super_interface, identifier):
1270         """Get the operational data about tag rewrite.
1271
1272         :param node: Honeycomb node.
1273         :param super_interface: Super interface.
1274         :param identifier: The ID of sub-interface.
1275         :type node: dict
1276         :type super_interface: str
1277         :type identifier: int
1278         :returns: Operational data about tag rewrite.
1279         :rtype: dict
1280         :raises HoneycombError: If there is no sub-interface with the given ID.
1281         """
1282
1283         try:
1284             tag_rewrite = InterfaceKeywords.get_sub_interface_oper_data(
1285                 node, super_interface, identifier)["l2"]["rewrite"]
1286             return tag_rewrite
1287         except KeyError:
1288             raise HoneycombError("The operational data does not contain "
1289                                  "information about the tag-rewrite.")
1290
1291     @staticmethod
1292     def add_ip_address_to_sub_interface(node, super_interface, identifier,
1293                                         ip_addr, network, ip_version):
1294         """Add an ipv4 address to the specified sub-interface, with the provided
1295         netmask or network prefix length. Any existing ipv4 addresses on the
1296         sub-interface will be replaced.
1297
1298         :param node: Honeycomb node.
1299         :param super_interface: Super interface.
1300         :param identifier: The ID of sub-interface.
1301         :param ip_addr: IPv4 address to be set.
1302         :param network: Network mask or network prefix length.
1303         :param ip_version: ipv4 or ipv6
1304         :type node: dict
1305         :type super_interface: str
1306         :type identifier: int
1307         :type ip_addr: str
1308         :type network: str or int
1309         :type ip_version: string
1310         :returns: Content of response.
1311         :rtype: bytearray
1312         :raises HoneycombError: If the provided netmask or prefix is not valid.
1313         """
1314
1315         path = ("interfaces",
1316                 ("interface", "name", super_interface),
1317                 "vpp-vlan:sub-interfaces",
1318                 ("sub-interface", "identifier", int(identifier)),
1319                 ip_version.lower())
1320
1321         if isinstance(network, basestring) and ip_version.lower() == "ipv4":
1322             address = {"address": [{"ip": ip_addr, "netmask": network}, ]}
1323
1324         elif isinstance(network, int) and 0 < network < 33:
1325             address = {"address": [{"ip": ip_addr, "prefix-length": network}, ]}
1326
1327         else:
1328             raise HoneycombError("{0} is not a valid netmask or prefix length."
1329                                  .format(network))
1330
1331         return InterfaceKeywords._set_interface_properties(
1332             node, super_interface, path, address)
1333
1334     @staticmethod
1335     def remove_all_ip_addresses_from_sub_interface(node, super_interface,
1336                                                    identifier, ip_version):
1337         """Remove all ipv4 addresses from the specified sub-interface.
1338
1339         :param node: Honeycomb node.
1340         :param super_interface: Super interface.
1341         :param identifier: The ID of sub-interface.
1342         :param ip_version: ipv4 or ipv6
1343         :type node: dict
1344         :type super_interface: str
1345         :type identifier: int
1346         :type ip_version: string
1347         :returns: Content of response.
1348         :rtype: bytearray
1349         """
1350
1351         path = ("interfaces",
1352                 ("interface", "name", super_interface),
1353                 "vpp-vlan:sub-interfaces",
1354                 ("sub-interface", "identifier", int(identifier)),
1355                 str(ip_version), "address")
1356
1357         return InterfaceKeywords._set_interface_properties(
1358             node, super_interface, path, None)
1359
1360     @staticmethod
1361     def compare_data_structures(data, ref, _path=''):
1362         """Checks if data obtained from UUT is as expected. If it is not,
1363         proceeds down the list/dictionary tree and finds the point of mismatch.
1364
1365         :param data: Data to be checked.
1366         :param ref: Referential data used for comparison.
1367         :param _path: Used in recursive calls, stores the path taken down
1368         the JSON tree.
1369         :type data: dict
1370         :type ref: dict
1371         :type _path: str
1372
1373         :raises HoneycombError: If the data structures do not match in some way,
1374         or if they are not in deserialized JSON format.
1375         """
1376
1377         if data == ref:
1378             return True
1379
1380         elif isinstance(data, dict) and isinstance(ref, dict):
1381             for key in ref:
1382                 if key not in data:
1383                     raise HoneycombError(
1384                         "Key {key} is not present in path {path}. Keys in path:"
1385                         "{data_keys}".format(
1386                             key=key,
1387                             path=_path,
1388                             data_keys=data.keys()))
1389
1390                 if data[key] != ref[key]:
1391                     if isinstance(data[key], list) \
1392                             or isinstance(data[key], dict):
1393                         InterfaceKeywords.compare_data_structures(
1394                             data[key], ref[key],
1395                             _path + '[{0}]'.format(key))
1396                     else:
1397                         raise HoneycombError(
1398                             "Data mismatch, key {key} in path {path} has value"
1399                             " {data}, but should be {ref}".format(
1400                                 key=key,
1401                                 path=_path,
1402                                 data=data[key],
1403                                 ref=ref[key]))
1404
1405         elif isinstance(data, list) and isinstance(ref, list):
1406             for item in ref:
1407                 if item not in data:
1408                     if isinstance(item, dict):
1409                         InterfaceKeywords.compare_data_structures(
1410                             data[0], item,
1411                             _path + '[{0}]'.format(ref.index(item)))
1412                     else:
1413                         raise HoneycombError(
1414                             "Data mismatch, list item {index} in path {path}"
1415                             " has value {data}, but should be {ref}".format(
1416                                 index=ref.index(item),
1417                                 path=_path,
1418                                 data=data[0],
1419                                 ref=item))
1420
1421         else:
1422             raise HoneycombError(
1423                 "Unexpected data type {data_type} in path {path}, reference"
1424                 " type is {ref_type}. Must be list or dictionary.".format(
1425                     data_type=type(data),
1426                     ref_type=type(ref),
1427                     path=_path))
1428
1429     @staticmethod
1430     def compare_interface_lists(list1, list2):
1431         """Compare provided lists of interfaces by name.
1432
1433         :param list1: List of interfaces.
1434         :param list2: List of interfaces.
1435         :type list1: list
1436         :type list2: list
1437         :raises HoneycombError: If an interface exists in only one of the lists.
1438         """
1439
1440         ignore = ["vx_tunnel0", "vxlan_gpe_tunnel0"]
1441         # these have no equivalent in config data and no effect on VPP
1442
1443         names1 = [x['name'] for x in list1]
1444         names2 = [x['name'] for x in list2]
1445
1446         for name in names1:
1447             if name not in names2 and name not in ignore:
1448                 raise HoneycombError("Interface {0} not present in list {1}"
1449                                      .format(name, list2))
1450         for name in names2:
1451             if name not in names1 and name not in ignore:
1452                 raise HoneycombError("Interface {0} not present in list {1}"
1453                                      .format(name, list1))
1454
1455     @staticmethod
1456     def create_vxlan_gpe_interface(node, interface, **kwargs):
1457         """Create a new VxLAN GPE interface.
1458
1459         :param node: Honeycomb node.
1460         :param interface: The name of interface to be created.
1461         :param kwargs: Parameters and their values. The accepted parameters are
1462         defined in InterfaceKeywords.VXLAN_GPE_PARAMS.
1463         :type node: dict
1464         :type interface: str
1465         :type kwargs: dict
1466         :returns: Content of response.
1467         :rtype: bytearray
1468         :raises HoneycombError: If a parameter in kwargs is not valid.
1469         """
1470
1471         new_vxlan_gpe = {
1472             "name": interface,
1473             "type": "v3po:vxlan-gpe-tunnel",
1474             "v3po:vxlan-gpe": {}
1475         }
1476         for param, value in kwargs.items():
1477             if param in InterfaceKeywords.INTF_PARAMS:
1478                 new_vxlan_gpe[param] = value
1479             elif param in InterfaceKeywords.VXLAN_GPE_PARAMS:
1480                 new_vxlan_gpe["v3po:vxlan-gpe"][param] = value
1481             else:
1482                 raise HoneycombError("The parameter {0} is invalid.".
1483                                      format(param))
1484         path = ("interfaces", "interface")
1485         vxlan_gpe_structure = [new_vxlan_gpe, ]
1486         return InterfaceKeywords._set_interface_properties(
1487             node, interface, path, vxlan_gpe_structure)
1488
1489     @staticmethod
1490     def enable_acl_on_interface(node, interface, table_name):
1491         """Enable ACL on the given interface.
1492
1493         :param node: Honeycomb node.
1494         :param interface: The interface where the ACL will be enabled.
1495         :param table_name: Name of the classify table.
1496         :type node: dict
1497         :type interface: str
1498         :type table_name: str
1499         :returns: Content of response.
1500         :rtype: bytearray
1501         :raises HoneycombError: If the configuration of interface is not
1502         successful.
1503         """
1504
1505         interface = interface.replace("/", "%2F")
1506
1507         data = {
1508             "vpp-interface-acl:acl": {
1509                 "ingress": {
1510                     "ip4-acl": {
1511                         "classify-table": table_name
1512                     },
1513                     "l2-acl": {
1514                         "classify-table": table_name
1515                     }
1516                 }
1517             }
1518         }
1519
1520         path = "/interface/" + interface + "/vpp-interface-acl:acl"
1521         status_code, resp = HcUtil.\
1522             put_honeycomb_data(node, "config_vpp_interfaces", data, path,
1523                                data_representation=DataRepresentation.JSON)
1524         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1525             raise HoneycombError(
1526                 "The configuration of interface '{0}' was not successful. "
1527                 "Status code: {1}.".format(interface, status_code))
1528         return resp
1529
1530     @staticmethod
1531     def enable_policer_on_interface(node, interface, table_name):
1532         """Enable Policer on the given interface.
1533
1534         :param node: Honeycomb node.
1535         :param interface: The interface where policer will be enabled.
1536         :param table_name: Name of the classify table.
1537         :type node: dict
1538         :type interface: str
1539         :type table_name: str
1540         :returns: Content of response.
1541         :rtype: bytearray
1542         :raises HoneycombError: If the configuration of interface is not
1543         successful.
1544         """
1545         interface = Topology.convert_interface_reference(
1546             node, interface, "name")
1547         interface = interface.replace("/", "%2F")
1548
1549         data = {
1550             "interface-policer:policer": {
1551                 "ip4-table": table_name
1552                 }
1553             }
1554
1555         path = "/interface/" + interface + "/interface-policer:policer"
1556         status_code, resp = HcUtil.\
1557             put_honeycomb_data(node, "config_vpp_interfaces", data, path,
1558                                data_representation=DataRepresentation.JSON)
1559         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1560             raise HoneycombError(
1561                 "The configuration of interface '{0}' was not successful. "
1562                 "Status code: {1}.".format(interface, status_code))
1563         return resp
1564
1565     @staticmethod
1566     def disable_policer_on_interface(node, interface):
1567         """Disable Policer on the given interface.
1568
1569         :param node: Honeycomb node.
1570         :param interface: The interface where policer will be disabled.
1571         :type node: dict
1572         :type interface: str
1573         :returns: Content of response.
1574         :rtype: bytearray
1575         :raises HoneycombError: If the configuration of interface is not
1576         successful.
1577         """
1578         interface = Topology.convert_interface_reference(
1579             node, interface, "name")
1580         interface = interface.replace("/", "%2F")
1581
1582         path = "/interface/" + interface + "/interface-policer:policer"
1583         status_code, resp = HcUtil.\
1584             delete_honeycomb_data(node, "config_vpp_interfaces", path)
1585         if status_code != HTTPCodes.OK:
1586             raise HoneycombError(
1587                 "The configuration of interface '{0}' was not successful. "
1588                 "Status code: {1}.".format(interface, status_code))
1589         return resp
1590
1591     @staticmethod
1592     def disable_acl_on_interface(node, interface):
1593         """Disable ACL on the given interface.
1594
1595         :param node: Honeycomb node.
1596         :param interface: The interface where the ACL will be disabled.
1597         :type node: dict
1598         :type interface: str
1599         :returns: Content of response.
1600         :rtype: bytearray
1601         :raises HoneycombError: If the configuration of interface is not
1602         successful.
1603         """
1604
1605         interface = interface.replace("/", "%2F")
1606
1607         path = "/interface/" + interface + "/vpp-interface-acl:acl"
1608
1609         status_code, resp = HcUtil.\
1610             delete_honeycomb_data(node, "config_vpp_interfaces", path)
1611
1612         if status_code != HTTPCodes.OK:
1613             raise HoneycombError(
1614                 "The configuration of interface '{0}' was not successful. "
1615                 "Status code: {1}.".format(interface, status_code))
1616         return resp
1617
1618     @staticmethod
1619     def create_pbb_sub_interface(node, intf, params):
1620         """Creates a PBB sub-interface on the given interface and sets its
1621         parameters.
1622
1623         :param node: Honeycomb node.
1624         :param intf: The interface where PBB sub-interface will be configured.
1625         :param params: Configuration parameters of the sub-interface to be
1626         created.
1627         :type node: dict
1628         :type intf: str
1629         :type params: dict
1630         :returns: Content of response.
1631         :rtype: bytearray
1632         :raises HoneycombError: If the configuration of sub-interface is not
1633         successful.
1634         """
1635
1636         interface = intf.replace("/", "%2F")
1637         path = "/interface/{0}/pbb-rewrite".format(interface)
1638         status_code, resp = HcUtil. \
1639             put_honeycomb_data(node, "config_vpp_interfaces", params, path,
1640                                data_representation=DataRepresentation.JSON)
1641         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1642             raise HoneycombError(
1643                 "The configuration of PBB sub-interface '{0}' was not "
1644                 "successful. Status code: {1}.".format(intf, status_code))
1645         return resp
1646
1647     @staticmethod
1648     def delete_pbb_sub_interface(node, intf):
1649         """Deletes the given PBB sub-interface.
1650
1651         :param node: Honeycomb node.
1652         :param intf: The interface where PBB sub-interface will be deleted.
1653         :type node: dict
1654         :type intf: str
1655         :returns: Content of response.
1656         :rtype: bytearray
1657         :raises HoneycombError: If the removal of sub-interface is not
1658         successful.
1659         """
1660
1661         interface = intf.replace("/", "%2F")
1662         path = "/interface/{0}/pbb-rewrite".format(interface)
1663
1664         status_code, resp = HcUtil. \
1665             delete_honeycomb_data(node, "config_vpp_interfaces", path)
1666         if status_code != HTTPCodes.OK:
1667             raise HoneycombError(
1668                 "The removal of pbb sub-interface '{0}' was not successful. "
1669                 "Status code: {1}.".format(intf, status_code))
1670         return resp
1671
1672     @staticmethod
1673     def get_pbb_sub_interface_oper_data(node, intf, sub_if_id):
1674         """Retrieves PBB sub-interface operational data from Honeycomb.
1675
1676         :param node: Honeycomb node.
1677         :param intf: The interface where PBB sub-interface is located.
1678         :param sub_if_id: ID of the PBB sub-interface.
1679         :type node: dict
1680         :type intf: str
1681         :type sub_if_id: str or int
1682         :returns: PBB sub-interface operational data.
1683         :rtype: dict
1684         :raises HoneycombError: If the removal of sub-interface is not
1685         successful.
1686         """
1687
1688         raise NotImplementedError
1689
1690     @staticmethod
1691     def check_disabled_interface(node, interface):
1692         """Retrieves list of disabled interface indices from Honeycomb,
1693         and matches with the provided interface by index.
1694
1695         :param node: Honeycomb node.
1696         :param interface: Index number of an interface on the node.
1697         :type node: dict
1698         :type interface: int
1699         :returns: True if the interface exists in disabled interfaces.
1700         :rtype: bool
1701         :raises HoneycombError: If the interface is not present
1702          in retrieved list of disabled interfaces.
1703          """
1704         data = InterfaceKeywords.get_disabled_interfaces_oper_data(node)
1705         # decrement by one = conversion from HC if-index to VPP sw_if_index
1706         interface -= 1
1707
1708         for item in data:
1709             if item["index"] == interface:
1710                 return True
1711         raise HoneycombError("Interface index {0} not present in list"
1712                              " of disabled interfaces.".format(interface))
1713
1714     @staticmethod
1715     def configure_interface_span(node, dst_interface, src_interfaces=None):
1716         """Configure SPAN port mirroring on the specified interfaces. If no
1717          source interface is provided, SPAN will be disabled.
1718
1719         :param node: Honeycomb node.
1720         :param dst_interface: Interface to mirror packets to.
1721         :param src_interfaces: List of interfaces to mirror packets from.
1722         :type node: dict
1723         :type dst_interface: str or int
1724         :type src_interfaces: list of dict
1725         :returns: Content of response.
1726         :rtype: bytearray
1727         :raises HoneycombError: If SPAN could not be configured.
1728         """
1729
1730         interface = Topology.convert_interface_reference(
1731             node, dst_interface, "name")
1732         interface = interface.replace("/", "%2F")
1733         path = "/interface/" + interface + "/span"
1734
1735         if not src_interfaces:
1736             status_code, _ = HcUtil.delete_honeycomb_data(
1737                 node, "config_vpp_interfaces", path)
1738         else:
1739             for src_interface in src_interfaces:
1740                 src_interface["iface-ref"] = Topology.\
1741                     convert_interface_reference(
1742                         node, src_interface["iface-ref"], "name")
1743             data = {
1744                 "span": {
1745                     "mirrored-interfaces": {
1746                         "mirrored-interface": src_interfaces
1747                     }
1748                 }
1749             }
1750
1751             status_code, _ = HcUtil.put_honeycomb_data(
1752                 node, "config_vpp_interfaces", data, path)
1753
1754         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1755             raise HoneycombError(
1756                 "Configuring SPAN failed. Status code:{0}".format(status_code))
1757
1758     @staticmethod
1759     def configure_sub_interface_span(node, super_interface, dst_interface_index,
1760                                      src_interfaces=None):
1761         """Configure SPAN port mirroring on the specified sub-interface. If no
1762          source interface is provided, SPAN will be disabled.
1763
1764         Note: Does not support source sub-interfaces, only destination.
1765
1766         :param node: Honeycomb node.
1767         :param super_interface: Name, link name or sw_if_index
1768         of the destination interface's super-interface.
1769         :param dst_interface_index: Index of sub-interface to mirror packets to.
1770         :param src_interfaces: List of interfaces to mirror packets from.
1771         :type node: dict
1772         :type super_interface: str or int
1773         :type dst_interface_index: int
1774         :type src_interfaces: list of dict
1775         :returns: Content of response.
1776         :rtype: bytearray
1777         :raises HoneycombError: If SPAN could not be configured.
1778         """
1779
1780         super_interface = Topology.convert_interface_reference(
1781             node, super_interface, "name")
1782         super_interface = super_interface.replace("/", "%2F")
1783
1784         path = "/interface/{0}/vpp-vlan:sub-interfaces/sub-interface/{1}/span"\
1785             .format(super_interface, dst_interface_index)
1786
1787         if not src_interfaces:
1788             status_code, _ = HcUtil.delete_honeycomb_data(
1789                 node, "config_vpp_interfaces", path)
1790         else:
1791             for src_interface in src_interfaces:
1792                 src_interface["iface-ref"] = Topology. \
1793                     convert_interface_reference(
1794                         node, src_interface["iface-ref"], "name")
1795             data = {
1796                 "span": {
1797                     "mirrored-interfaces": {
1798                         "mirrored-interface": src_interfaces
1799                     }
1800                 }
1801             }
1802
1803             status_code, _ = HcUtil.put_honeycomb_data(
1804                 node, "config_vpp_interfaces", data, path)
1805
1806         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1807             raise HoneycombError(
1808                 "Configuring SPAN failed. Status code:{0}".format(status_code))
1809
1810     @staticmethod
1811     def add_interface_local0_to_topology(node):
1812         """Use Topology methods to add interface "local0" to working topology,
1813         if not already present.
1814
1815         :param node: DUT node.
1816         :type node: dict
1817         """
1818
1819         if Topology.get_interface_by_sw_index(node, 0) is None:
1820             local0_key = Topology.add_new_port(node, "localzero")
1821             Topology.update_interface_sw_if_index(node, local0_key, 0)
1822             Topology.update_interface_name(node, local0_key, "local0")
1823
1824     @staticmethod
1825     def configure_interface_unnumbered(node, interface, interface_src=None):
1826         """Configure the specified interface as unnumbered. The interface
1827         borrows IP address from the specified source interface. If not source
1828         interface is provided, unnumbered configuration will be removed.
1829
1830         :param node: Honeycomb node.
1831         :param interface: Name, link name or sw_if_index of an interface.
1832         :param interface_src: Name of source interface.
1833         :type node: dict
1834         :type interface: str or int
1835         :type interface_src: str
1836         :raises HoneycombError: If the configuration fails.
1837         """
1838
1839         interface = InterfaceKeywords.handle_interface_reference(
1840             node, interface)
1841
1842         path = "/interface/{0}/unnumbered-interfaces:unnumbered"\
1843             .format(interface)
1844
1845         if interface_src:
1846             data = {
1847                 "unnumbered": {
1848                     "use": interface_src
1849                 }
1850             }
1851             status_code, _ = HcUtil.put_honeycomb_data(
1852                 node, "config_vpp_interfaces", data, path)
1853         else:
1854             status_code, _ = HcUtil.delete_honeycomb_data(
1855                 node, "config_vpp_interfaces", path)
1856
1857         if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED):
1858             raise HoneycombError(
1859                 "Configuring unnumbered interface failed. "
1860                 "Status code:{0}".format(status_code))
1861
1862     @staticmethod
1863     def handle_interface_reference(node, interface):
1864         """Convert any interface reference to interface name used by Honeycomb.
1865
1866         :param node: Honeycomb node.
1867         :param interface: Name, link name or sw_if_index of an interface,
1868         name of a custom interface or name of a sub-interface.
1869         :type node: Honeycomb node.
1870         :type interface: str or int
1871         :returns: Name of interface that can be used in Honeycomb requests.
1872         :rtype: str
1873         """
1874
1875         try:
1876             interface = Topology.convert_interface_reference(
1877                 node, interface, "name")
1878             interface = interface.replace("/", "%2F")
1879         except RuntimeError:
1880             # interface is not in topology
1881             if "." in interface:
1882                 # Assume it's the name of a sub-interface
1883                 interface, index = interface.split(".")
1884                 interface = interface.replace("/", "%2F")
1885                 interface = "{0}/vpp-vlan:sub-interfaces/sub-interface/{1}".\
1886                     format(interface, index)
1887             else:
1888                 # Assume it's the name of a custom interface (pbb, vxlan, etc.)
1889                 interface = interface.replace("/", "%2F")
1890
1891         return interface