ff1589f217a005f2d0ba5b6b98228cef0682c230
[csit.git] / resources / libraries / python / honeycomb / HcAPIKwInterfaces.py
1 # Copyright (c) 2016 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """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
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 DataRepresentation
24 from resources.libraries.python.honeycomb.HoneycombUtil \
25     import HoneycombUtil as HcUtil
26
27
28 # pylint: disable=too-many-public-methods
29 # pylint: disable=too-many-lines
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 = ("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         :return: 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 != HTTPCodes.OK:
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         :return: 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         :return: 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         :return: 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_interface_oper_data(node, interface):
167         """Get operational data about the given interface from Honeycomb.
168
169         :param node: Honeycomb node.
170         :param interface: The name of interface.
171         :type node: dict
172         :type interface: str
173         :return: Operational data about the given interface from Honeycomb.
174         :rtype: dict
175         """
176
177         intfs = InterfaceKeywords.get_all_interfaces_oper_data(node)
178         for intf in intfs:
179             if intf["name"] == interface:
180                 return intf
181         return {}
182
183     @staticmethod
184     def _set_interface_properties(node, interface, path, new_value=None):
185         """Set interface properties.
186
187         This method reads interface configuration data, creates, changes or
188         removes the requested data and puts it back to Honeycomb.
189
190         :param node: Honeycomb node.
191         :param interface: The name of interface.
192         :param path:  Path to data we want to change / create / remove.
193         :param new_value: The new value to be set. If None, the item will be
194         removed.
195         :type node: dict
196         :type interface: str
197         :type path: tuple
198         :type new_value: str, dict or list
199         :return: Content of response.
200         :rtype: bytearray
201         :raises HoneycombError: If it is not possible to get or set the data.
202         """
203
204         status_code, resp = HcUtil.\
205             get_honeycomb_data(node, "config_vpp_interfaces")
206         if status_code != HTTPCodes.OK:
207             raise HoneycombError(
208                 "Not possible to get configuration information about the "
209                 "interfaces. Status code: {0}.".format(status_code))
210
211         if new_value:
212             new_data = HcUtil.set_item_value(resp, path, new_value)
213         else:
214             new_data = HcUtil.remove_item(resp, path)
215         return InterfaceKeywords._configure_interface(node, interface, new_data)
216
217     @staticmethod
218     def set_interface_state(node, interface, state="up"):
219         """Set VPP interface state.
220
221         The keyword changes the administration state of interface to up or down
222         depending on the parameter "state".
223
224         :param node: Honeycomb node.
225         :param interface: The name of interface.
226         :param state: The requested state, only "up" and "down" are valid
227         values.
228         :type node: dict
229         :type interface: str
230         :type state: str
231         :return: Content of response.
232         :rtype: bytearray
233         :raises KeyError: If the argument "state" is nor "up" or "down".
234         :raises HoneycombError: If the interface is not present on the node.
235         """
236
237         intf_state = {"up": "true",
238                       "down": "false"}
239
240         path = ("interfaces", ("interface", "name", str(interface)), "enabled")
241         return InterfaceKeywords._set_interface_properties(
242             node, interface, path, intf_state[state.lower()])
243
244     @staticmethod
245     def set_interface_up(node, interface):
246         """Set the administration state of VPP interface to up.
247
248         :param node: Honeycomb node.
249         :param interface: The name of interface.
250         :type node: dict
251         :type interface: str
252         :return: Content of response
253         :rtype: bytearray
254         """
255
256         return InterfaceKeywords.set_interface_state(node, interface, "up")
257
258     @staticmethod
259     def set_interface_down(node, interface):
260         """Set the administration state of VPP interface to down.
261
262         :param node: Honeycomb node.
263         :param interface: The name of interface.
264         :type node: dict
265         :type interface: str
266         :return: Content of response.
267         :rtype: bytearray
268         """
269
270         return InterfaceKeywords.set_interface_state(node, interface, "down")
271
272     @staticmethod
273     def add_bridge_domain_to_interface(node, interface, bd_name,
274                                        split_horizon_group=None, bvi=None):
275         """Add a new bridge domain to an interface and set its parameters.
276
277         :param node: Honeycomb node.
278         :param interface: The name of interface.
279         :param bd_name: Bridge domain name.
280         :param split_horizon_group: Split-horizon group name.
281         :param bvi: The bridged virtual interface.
282         :type node: dict
283         :type interface: str
284         :type bd_name: str
285         :type split_horizon_group: str
286         :type bvi: str
287         :return: Content of response.
288         :rtype: bytearray
289         :raises HoneycombError: If the interface is not present on the node.
290         """
291
292         v3po_l2 = {"bridge-domain": str(bd_name)}
293         if split_horizon_group:
294             v3po_l2["split-horizon-group"] = str(split_horizon_group)
295         if bvi:
296             v3po_l2["bridged-virtual-interface"] = str(bvi)
297
298         path = ("interfaces", ("interface", "name", str(interface)), "v3po:l2")
299
300         return InterfaceKeywords._set_interface_properties(
301             node, interface, path, v3po_l2)
302
303     @staticmethod
304     def get_bd_oper_data_from_interface(node, interface):
305         """Returns operational data about bridge domain settings in the
306         interface.
307
308         :param node: Honeycomb node.
309         :param interface: The name of interface.
310         :type interface: str
311         :type node: dict
312         :return: Operational data about bridge domain settings in the
313         interface.
314         :rtype: dict
315         """
316
317         if_data = InterfaceKeywords.get_interface_oper_data(node, interface)
318
319         if if_data:
320             try:
321                 return if_data["v3po:l2"]
322             except KeyError:
323                 return {}
324         return {}
325
326     @staticmethod
327     def configure_interface_base(node, interface, param, value):
328         """Configure the base parameters of interface.
329
330         :param node: Honeycomb node.
331         :param interface: The name of interface.
332         :param param: Parameter to configure (set, change, remove)
333         :param value: The value of parameter. If None, the parameter will be
334         removed.
335         :type node: dict
336         :type interface: str
337         :type param: str
338         :type value: str
339         :return: Content of response.
340         :rtype: bytearray
341         :raises HoneycombError: If the parameter is not valid.
342         """
343
344         if param not in InterfaceKeywords.INTF_PARAMS:
345             raise HoneycombError("The parameter {0} is invalid.".format(param))
346
347         path = ("interfaces", ("interface", "name", interface), param)
348         return InterfaceKeywords._set_interface_properties(
349             node, interface, path, value)
350
351     @staticmethod
352     def configure_interface_ipv4(node, interface, param, value):
353         """Configure IPv4 parameters of interface
354
355         :param node: Honeycomb node.
356         :param interface: The name of interface.
357         :param param: Parameter to configure (set, change, remove)
358         :param value: The value of parameter. If None, the parameter will be
359         removed.
360         :type node: dict
361         :type interface: str
362         :type param: str
363         :type value: str
364         :return: Content of response.
365         :rtype: bytearray
366         :raises HoneycombError: If the parameter is not valid.
367         """
368
369         if param not in InterfaceKeywords.IPV4_PARAMS:
370             raise HoneycombError("The parameter {0} is invalid.".format(param))
371
372         path = ("interfaces", ("interface", "name", interface),
373                 "ietf-ip:ipv4", param)
374         return InterfaceKeywords._set_interface_properties(
375             node, interface, path, value)
376
377     @staticmethod
378     def add_first_ipv4_address(node, interface, ip_addr, network):
379         """Add the first IPv4 address.
380
381         If there are any other addresses configured, they will be removed.
382
383         :param node: Honeycomb node.
384         :param interface: The name of interface.
385         :param ip_addr: IPv4 address to be set.
386         :param network: Netmask or length of network prefix.
387         :type node: dict
388         :type interface: str
389         :type ip_addr: str
390         :type network: str or int
391         :return: Content of response.
392         :rtype: bytearray
393         :raises HoneycombError: If the provided netmask or prefix is not valid.
394         """
395
396         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4")
397         if isinstance(network, basestring):
398             address = {"address": [{"ip": ip_addr, "netmask": network}, ]}
399         elif isinstance(network, int) and (0 < network < 33):
400             address = {"address": [{"ip": ip_addr, "prefix-length": network}, ]}
401         else:
402             raise HoneycombError("Value {0} is not a valid netmask or network "
403                                  "prefix length.".format(network))
404         return InterfaceKeywords._set_interface_properties(
405             node, interface, path, address)
406
407     @staticmethod
408     def add_ipv4_address(node, interface, ip_addr, network):
409         """Add IPv4 address.
410
411         :param node: Honeycomb node.
412         :param interface: The name of interface.
413         :param ip_addr: IPv4 address to be set.
414         :param network: Netmask or length of network prefix.
415         :type node: dict
416         :type interface: str
417         :type ip_addr: str
418         :type network: str or int
419         :return: Content of response.
420         :rtype: bytearray
421         :raises HoneycombError: If the provided netmask or prefix is not valid.
422         """
423
424         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
425                 "address")
426         if isinstance(network, basestring):
427             address = {"address": [{"ip": ip_addr, "netmask": network}, ]}
428         elif isinstance(network, int) and (0 < network < 33):
429             address = {"address": [{"ip": ip_addr, "prefix-length": network}, ]}
430         else:
431             raise HoneycombError("Value {0} is not a valid netmask or network "
432                                  "prefix length.".format(network))
433         return InterfaceKeywords._set_interface_properties(
434             node, interface, path, address)
435
436     @staticmethod
437     def remove_all_ipv4_addresses(node, interface):
438         """Remove all IPv4 addresses from interface.
439
440         :param node: Honeycomb node.
441         :param interface: The name of interface.
442         :type node: dict
443         :type interface: str
444         :return: Content of response.
445         :rtype: bytearray
446         """
447
448         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
449                 "address")
450         return InterfaceKeywords._set_interface_properties(
451             node, interface, path, None)
452
453     @staticmethod
454     def add_ipv4_neighbor(node, interface, ip_addr, link_layer_address):
455         """Add the IPv4 neighbour.
456
457         :param node: Honeycomb node.
458         :param interface: The name of interface.
459         :param ip_addr: IPv4 address of neighbour to be set.
460         :param link_layer_address: Link layer address.
461         :type node: dict
462         :type interface: str
463         :type ip_addr: str
464         :type link_layer_address: str
465         :return: Content of response.
466         :rtype: bytearray
467         """
468
469         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
470                 "neighbor")
471         neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ]
472         return InterfaceKeywords._set_interface_properties(
473             node, interface, path, neighbor)
474
475     @staticmethod
476     def remove_all_ipv4_neighbors(node, interface):
477         """Remove all IPv4 neighbours.
478
479         :param node: Honeycomb node.
480         :param interface: The name of interface.
481         :type node: dict
482         :type interface: str
483         :return: Content of response.
484         :rtype: bytearray
485         """
486
487         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4",
488                 "neighbor")
489         return InterfaceKeywords._set_interface_properties(
490             node, interface, path, None)
491
492     @staticmethod
493     def configure_interface_ipv6(node, interface, param, value):
494         """Configure IPv6 parameters of interface
495
496         :param node: Honeycomb node.
497         :param interface: The name of interface.
498         :param param: Parameter to configure (set, change, remove)
499         :param value: The value of parameter. If None, the parameter will be
500         removed.
501         :type node: dict
502         :type interface: str
503         :type param: str
504         :type value: str
505         :return: Content of response.
506         :rtype: bytearray
507         :raises HoneycombError: If the parameter is not valid.
508         """
509
510         if param in InterfaceKeywords.IPV6_PARAMS:
511             path = ("interfaces", ("interface", "name", interface),
512                     "ietf-ip:ipv6", param)
513         elif param in InterfaceKeywords.IPV6_AUTOCONF_PARAMS:
514             path = ("interfaces", ("interface", "name", interface),
515                     "ietf-ip:ipv6", "autoconf", param)
516         else:
517             raise HoneycombError("The parameter {0} is invalid.".format(param))
518
519         return InterfaceKeywords._set_interface_properties(
520             node, interface, path, value)
521
522     @staticmethod
523     def add_first_ipv6_address(node, interface, ip_addr, prefix_len):
524         """Add the first IPv6 address.
525
526         If there are any other addresses configured, they will be removed.
527
528         :param node: Honeycomb node.
529         :param interface: The name of interface.
530         :param ip_addr: IPv6 address to be set.
531         :param prefix_len: Prefix length.
532         :type node: dict
533         :type interface: str
534         :type ip_addr: str
535         :type prefix_len: str
536         :return: Content of response.
537         :rtype: bytearray
538         """
539
540         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6")
541         address = {"address": [{"ip": ip_addr, "prefix-length": prefix_len}, ]}
542         return InterfaceKeywords._set_interface_properties(
543             node, interface, path, address)
544
545     @staticmethod
546     def add_ipv6_address(node, interface, ip_addr, prefix_len):
547         """Add IPv6 address.
548
549         :param node: Honeycomb node.
550         :param interface: The name of interface.
551         :param ip_addr: IPv6 address to be set.
552         :param prefix_len: Prefix length.
553         :type node: dict
554         :type interface: str
555         :type ip_addr: str
556         :type prefix_len: str
557         :return: Content of response.
558         :rtype: bytearray
559         """
560
561         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
562                 "address")
563         address = [{"ip": ip_addr, "prefix-length": prefix_len}, ]
564         return InterfaceKeywords._set_interface_properties(
565             node, interface, path, address)
566
567     @staticmethod
568     def remove_all_ipv6_addresses(node, interface):
569         """Remove all IPv6 addresses from interface.
570
571         :param node: Honeycomb node.
572         :param interface: The name of interface.
573         :type node: dict
574         :type interface: str
575         :return: Content of response.
576         :rtype: bytearray
577         """
578
579         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
580                 "address")
581         return InterfaceKeywords._set_interface_properties(
582             node, interface, path, None)
583
584     @staticmethod
585     def add_ipv6_neighbor(node, interface, ip_addr, link_layer_address):
586         """Add the IPv6 neighbour.
587
588         :param node: Honeycomb node.
589         :param interface: The name of interface.
590         :param ip_addr: IPv6 address of neighbour to be set.
591         :param link_layer_address: Link layer address.
592         :type node: dict
593         :type interface: str
594         :type ip_addr: str
595         :type link_layer_address: str
596         :return: Content of response.
597         :rtype: bytearray
598         """
599
600         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
601                 "neighbor")
602         neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ]
603         return InterfaceKeywords._set_interface_properties(
604             node, interface, path, neighbor)
605
606     @staticmethod
607     def remove_all_ipv6_neighbors(node, interface):
608         """Remove all IPv6 neighbours.
609
610         :param node: Honeycomb node.
611         :param interface: The name of interface.
612         :type node: dict
613         :type interface: str
614         :return: Content of response.
615         :rtype: bytearray
616         """
617
618         path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6",
619                 "neighbor")
620         return InterfaceKeywords._set_interface_properties(
621             node, interface, path, None)
622
623     @staticmethod
624     def configure_interface_ethernet(node, interface, param, value):
625         """Configure the ethernet parameters of interface.
626
627         :param node: Honeycomb node.
628         :param interface: The name of interface.
629         :param param: Parameter to configure (set, change, remove)
630         :param value: The value of parameter. If None, the parameter will be
631         removed.
632         :type node: dict
633         :type interface: str
634         :type param: str
635         :type value: str
636         :return: Content of response.
637         :rtype: bytearray
638         :raises HoneycombError: If the parameter is not valid.
639         """
640
641         if param not in InterfaceKeywords.ETH_PARAMS:
642             raise HoneycombError("The parameter {0} is invalid.".format(param))
643         path = ("interfaces", ("interface", "name", interface), "v3po:ethernet",
644                 param)
645         return InterfaceKeywords._set_interface_properties(
646             node, interface, path, value)
647
648     @staticmethod
649     def configure_interface_routing(node, interface, param, value):
650         """Configure the routing parameters of interface.
651
652         :param node: Honeycomb node.
653         :param interface: The name of interface.
654         :param param: Parameter to configure (set, change, remove)
655         :param value: The value of parameter. If None, the parameter will be
656         removed.
657         :type node: dict
658         :type interface: str
659         :type param: str
660         :type value: str
661         :return: Content of response.
662         :rtype: bytearray
663         :raises HoneycombError: If the parameter is not valid.
664         """
665
666         if param not in InterfaceKeywords.ROUTING_PARAMS:
667             raise HoneycombError("The parameter {0} is invalid.".format(param))
668
669         path = ("interfaces", ("interface", "name", interface), "v3po:routing",
670                 param)
671         return InterfaceKeywords._set_interface_properties(
672             node, interface, path, value)
673
674     @staticmethod
675     def create_vxlan_interface(node, interface, **kwargs):
676         """Create a new VxLAN interface.
677
678         :param node: Honeycomb node.
679         :param interface: The name of interface.
680         :param kwargs: Parameters and their values. The accepted parameters are
681         defined in InterfaceKeywords.VXLAN_PARAMS.
682         :type node: dict
683         :type interface: str
684         :type kwargs: dict
685         :return: Content of response.
686         :rtype: bytearray
687         :raises HoneycombError: If the parameter is not valid.
688         """
689
690         new_vx_lan = {
691             "name": interface,
692             "type": "v3po:vxlan-tunnel",
693             "v3po:vxlan": {}
694         }
695         for param, value in kwargs.items():
696             if param not in InterfaceKeywords.VXLAN_PARAMS:
697                 raise HoneycombError("The parameter {0} is invalid.".
698                                      format(param))
699             new_vx_lan["v3po:vxlan"][param] = value
700
701         path = ("interfaces", "interface")
702         vx_lan_structure = [new_vx_lan, ]
703         return InterfaceKeywords._set_interface_properties(
704             node, interface, path, vx_lan_structure)
705
706     @staticmethod
707     def delete_interface(node, interface):
708         """Delete an interface.
709
710         :param node: Honeycomb node.
711         :param interface: The name of interface.
712         :type node: dict
713         :type interface: str
714         :return: Content of response.
715         :rtype: bytearray
716         :raises HoneycombError: If it is not possible to get information about
717         interfaces or it is not possible to delete the interface.
718         """
719
720         path = ("interfaces", ("interface", "name", interface))
721
722         status_code, resp = HcUtil.\
723             get_honeycomb_data(node, "config_vpp_interfaces")
724         if status_code != HTTPCodes.OK:
725             raise HoneycombError(
726                 "Not possible to get configuration information about the "
727                 "interfaces. Status code: {0}.".format(status_code))
728
729         new_data = HcUtil.remove_item(resp, path)
730         status_code, resp = HcUtil.\
731             put_honeycomb_data(node, "config_vpp_interfaces", new_data)
732         if status_code != HTTPCodes.OK:
733             raise HoneycombError("Not possible to remove interface {0}. "
734                                  "Status code: {1}.".
735                                  format(interface, status_code))
736         return resp
737
738     @staticmethod
739     def configure_interface_vxlan(node, interface, **kwargs):
740         """Configure VxLAN on the interface.
741
742         The keyword configures VxLAN parameters on the given interface. The type
743         of interface must be set to "v3po:vxlan-tunnel".
744         The new VxLAN parameters overwrite the current configuration. If a
745         parameter in new configuration is missing, it is removed from VxLAN
746         configuration.
747         If the dictionary kwargs is empty, VxLAN configuration is removed.
748
749         :param node: Honeycomb node.
750         :param interface: The name of interface.
751         :param kwargs: Parameters and their values. The accepted parameters are
752         defined in InterfaceKeywords.VXLAN_PARAMS.
753         :type node: dict
754         :type interface: str
755         :type kwargs: dict
756         :return: Content of response.
757         :rtype: bytearray
758         :raises HoneycombError: If the parameter is not valid.
759         """
760
761         vx_lan_structure = dict()
762         for param, value in kwargs.items():
763             if param not in InterfaceKeywords.VXLAN_PARAMS:
764                 raise HoneycombError("The parameter {0} is invalid.".
765                                      format(param))
766             vx_lan_structure[param] = value
767
768         path = ("interfaces", ("interface", "name", interface), "v3po:vxlan")
769         return InterfaceKeywords._set_interface_properties(
770             node, interface, path, vx_lan_structure)
771
772     @staticmethod
773     def configure_interface_l2(node, interface, param, value):
774         """Configure the L2 parameters of interface.
775
776         :param node: Honeycomb node.
777         :param interface: The name of interface.
778         :param param: Parameter to configure (set, change, remove)
779         :param value: The value of parameter. If None, the parameter will be
780         removed.
781         :type node: dict
782         :type interface: str
783         :type param: str
784         :type value: str
785         :return: Content of response.
786         :rtype: bytearray
787         :raises HoneycombError: If the parameter is not valid.
788         """
789
790         if param not in InterfaceKeywords.L2_PARAMS:
791             raise HoneycombError("The parameter {0} is invalid.".format(param))
792         path = ("interfaces", ("interface", "name", interface), "v3po:l2",
793                 param)
794         return InterfaceKeywords._set_interface_properties(
795             node, interface, path, value)
796
797     @staticmethod
798     def create_tap_interface(node, interface, **kwargs):
799         """Create a new TAP interface.
800
801         :param node: Honeycomb node.
802         :param interface: The name of interface.
803         :param kwargs: Parameters and their values. The accepted parameters are
804         defined in InterfaceKeywords.TAP_PARAMS.
805         :type node: dict
806         :type interface: str
807         :type kwargs: dict
808         :return: Content of response.
809         :rtype: bytearray
810         :raises HoneycombError: If the parameter is not valid.
811         """
812
813         new_tap = {
814             "name": interface,
815             "type": "v3po:tap",
816             "v3po:tap": {}
817         }
818         for param, value in kwargs.items():
819             if param not in InterfaceKeywords.TAP_PARAMS:
820                 raise HoneycombError("The parameter {0} is invalid.".
821                                      format(param))
822             new_tap["v3po:tap"][param] = value
823
824         path = ("interfaces", "interface")
825         new_tap_structure = [new_tap, ]
826         return InterfaceKeywords._set_interface_properties(
827             node, interface, path, new_tap_structure)
828
829     @staticmethod
830     def configure_interface_tap(node, interface, **kwargs):
831         """Configure TAP on the interface.
832
833         The keyword configures TAP parameters on the given interface. The type
834         of interface must be set to "v3po:tap".
835         The new TAP parameters overwrite the current configuration. If a
836         parameter in new configuration is missing, it is removed from TAP
837         configuration.
838         If the dictionary kwargs is empty, TAP configuration is removed.
839
840         :param node: Honeycomb node.
841         :param interface: The name of interface.
842         :param kwargs: Parameters and their values. The accepted parameters are
843         defined in InterfaceKeywords.TAP_PARAMS.
844         :type node: dict
845         :type interface: str
846         :type kwargs: dict
847         :return: Content of response.
848         :rtype: bytearray
849         :raises HoneycombError: If the parameter is not valid.
850         """
851
852         tap_structure = dict()
853         for param, value in kwargs.items():
854             if param not in InterfaceKeywords.TAP_PARAMS:
855                 raise HoneycombError("The parameter {0} is invalid.".
856                                      format(param))
857             tap_structure[param] = value
858
859         path = ("interfaces", ("interface", "name", interface), "v3po:tap")
860         return InterfaceKeywords._set_interface_properties(
861             node, interface, path, tap_structure)
862
863     @staticmethod
864     def configure_interface_vhost_user(node, interface, **kwargs):
865         """Configure vhost-user on the interface.
866
867         The keyword configures vhost-user parameters on the given interface.
868         The type of interface must be set to "v3po:vhost-user".
869         The new vhost-user parameters overwrite the current configuration. If a
870         parameter in new configuration is missing, it is removed from vhost-user
871         configuration.
872         If the dictionary kwargs is empty, vhost-user configuration is removed.
873
874         :param node: Honeycomb node.
875         :param interface: The name of interface.
876         :param kwargs: Parameters and their values. The accepted parameters are
877         defined in InterfaceKeywords.VHOST_USER_PARAMS.
878         :type node: dict
879         :type interface: str
880         :type kwargs: dict
881         :return: Content of response.
882         :rtype: bytearray
883         :raises HoneycombError: If the parameter is not valid.
884         """
885
886         vhost_structure = dict()
887         for param, value in kwargs.items():
888             if param not in InterfaceKeywords.VHOST_USER_PARAMS:
889                 raise HoneycombError("The parameter {0} is invalid.".
890                                      format(param))
891             vhost_structure[param] = value
892
893         path = ("interfaces", ("interface", "name", interface),
894                 "v3po:vhost-user")
895         return InterfaceKeywords._set_interface_properties(
896             node, interface, path, vhost_structure)
897
898     @staticmethod
899     def create_vhost_user_interface(node, interface, **kwargs):
900         """Create a new vhost-user interface.
901
902         :param node: Honeycomb node.
903         :param interface: The name of interface.
904         :param kwargs: Parameters and their values. The accepted parameters are
905         defined in InterfaceKeywords.VHOST_USER_PARAMS.
906         :type node: dict
907         :type interface: str
908         :type kwargs: dict
909         :return: Content of response.
910         :rtype: bytearray
911         :raises HoneycombError: If the parameter is not valid.
912         """
913
914         new_vhost = {
915             "name": interface,
916             "type": "v3po:vhost-user",
917             "v3po:vhost-user": {}
918         }
919         for param, value in kwargs.items():
920             if param not in InterfaceKeywords.VHOST_USER_PARAMS:
921                 raise HoneycombError("The parameter {0} is invalid.".
922                                      format(param))
923             new_vhost["v3po:vhost-user"][param] = value
924
925         path = ("interfaces", "interface")
926         new_vhost_structure = [new_vhost, ]
927         return InterfaceKeywords._set_interface_properties(
928             node, interface, path, new_vhost_structure)
929
930     @staticmethod
931     def create_sub_interface(node, super_interface, match, tags=None, **kwargs):
932         """Create a new sub-interface.
933
934         :param node: Honeycomb node.
935         :param super_interface: Super interface.
936         :param match: Match type. The valid values are defined in
937         InterfaceKeywords.SUB_IF_MATCH.
938         :param tags: List of tags.
939         :param kwargs: Parameters and their values. The accepted parameters are
940         defined in InterfaceKeywords.SUB_IF_PARAMS.
941         :type node: dict
942         :type super_interface: str
943         :type match: str
944         :type tags: list
945         :type kwargs: dict
946         :return: Content of response.
947         :rtype: bytearray
948         :raises HoneycombError: If the parameter is not valid.
949         :raises KeyError: If the parameter 'match' is invalid.
950         """
951
952         match_type = {
953             "default":
954                 {"default": {}},
955             "untagged":
956                 {"untagged": {}},
957             "vlan-tagged":
958                 {"vlan-tagged": {"match-exact-tags": "false"}},
959             "vlan-tagged-exact-match":
960                 {"vlan-tagged": {"match-exact-tags": "true"}}
961         }
962
963         new_sub_interface = {
964             "tags": {
965                 "tag": []
966             },
967         }
968
969         for param, value in kwargs.items():
970             if param in InterfaceKeywords.SUB_IF_PARAMS:
971                 new_sub_interface[param] = value
972             else:
973                 raise HoneycombError("The parameter {0} is invalid.".
974                                      format(param))
975         try:
976             new_sub_interface["match"] = match_type[match]
977         except KeyError:
978             raise HoneycombError("The value '{0}' of parameter 'match' is "
979                                  "invalid.".format(match))
980
981         if tags:
982             new_sub_interface["tags"]["tag"].extend(tags)
983
984         path = ("interfaces",
985                 ("interface", "name", super_interface),
986                 "vpp-vlan:sub-interfaces",
987                 "sub-interface")
988         new_sub_interface_structure = [new_sub_interface, ]
989         return InterfaceKeywords._set_interface_properties(
990             node, super_interface, path, new_sub_interface_structure)
991
992     @staticmethod
993     def get_sub_interface_oper_data(node, super_interface, identifier):
994         """Retrieves sub-interface operational data using Honeycomb API.
995
996         :param node: Honeycomb node.
997         :param super_interface: Super interface.
998         :param identifier: The ID of sub-interface.
999         :type node: dict
1000         :type super_interface: str
1001         :type identifier: int
1002         :return: Sub-interface operational data.
1003         :rtype: dict
1004         :raises HoneycombError: If there is no sub-interface with the given ID.
1005         """
1006
1007         if_data = InterfaceKeywords.get_interface_oper_data(node,
1008                                                             super_interface)
1009         for sub_if in if_data["vpp-vlan:sub-interfaces"]["sub-interface"]:
1010             if str(sub_if["identifier"]) == str(identifier):
1011                 return sub_if
1012
1013         raise HoneycombError("The interface {0} does not have sub-interface "
1014                              "with ID {1}".format(super_interface, identifier))
1015
1016     @staticmethod
1017     def remove_all_sub_interfaces(node, super_interface):
1018         """Remove all sub-interfaces from the given interface.
1019
1020         :param node: Honeycomb node.
1021         :param super_interface: Super interface.
1022         :type node: dict
1023         :type super_interface: str
1024         :return: Content of response.
1025         :rtype: bytearray
1026         """
1027
1028         path = ("interfaces",
1029                 ("interface", "name", super_interface),
1030                 "vpp-vlan:sub-interfaces")
1031
1032         return InterfaceKeywords._set_interface_properties(
1033             node, super_interface, path, {})
1034
1035     @staticmethod
1036     def set_sub_interface_state(node, super_interface, identifier, state):
1037         """Set the administrative state of sub-interface.
1038
1039         :param node: Honeycomb node.
1040         :param super_interface: Super interface.
1041         :param identifier: The ID of sub-interface.
1042         :param state: Required sub-interface state - up or down.
1043         :type node: dict
1044         :type super_interface: str
1045         :type identifier: int
1046         :type state: str
1047         :return: Content of response.
1048         :rtype: bytearray
1049         """
1050
1051         intf_state = {"up": "true",
1052                       "down": "false"}
1053
1054         path = ("interfaces",
1055                 ("interface", "name", super_interface),
1056                 "vpp-vlan:sub-interfaces",
1057                 ("sub-interface", "identifier", identifier),
1058                 "enabled")
1059
1060         return InterfaceKeywords._set_interface_properties(
1061             node, super_interface, path, intf_state[state])
1062
1063     @staticmethod
1064     def add_bridge_domain_to_sub_interface(node, super_interface, identifier,
1065                                            config):
1066         """Add a sub-interface to a bridge domain and set its parameters.
1067
1068         :param node: Honeycomb node.
1069         :param super_interface: Super interface.
1070         :param identifier: The ID of sub-interface.
1071         :param config: Bridge domain configuration.
1072         :type node: dict
1073         :type super_interface: str
1074         :type identifier: int
1075         :type config: dict
1076         :return: Content of response.
1077         :rtype: bytearray
1078         """
1079
1080         path = ("interfaces",
1081                 ("interface", "name", super_interface),
1082                 "vpp-vlan:sub-interfaces",
1083                 ("sub-interface", "identifier", int(identifier)),
1084                 "l2")
1085
1086         return InterfaceKeywords._set_interface_properties(
1087             node, super_interface, path, config)
1088
1089     @staticmethod
1090     def get_bd_data_from_sub_interface(node, super_interface, identifier):
1091         """Get the operational data about the bridge domain from sub-interface.
1092
1093         :param node: Honeycomb node.
1094         :param super_interface: Super interface.
1095         :param identifier: The ID of sub-interface.
1096         :type node: dict
1097         :type super_interface: str
1098         :type identifier: int
1099         :return: Operational data about the bridge domain.
1100         :rtype: dict
1101         :raises HoneycombError: If there is no sub-interface with the given ID.
1102         """
1103
1104         try:
1105             bd_data = InterfaceKeywords.get_sub_interface_oper_data(
1106                 node, super_interface, identifier)["l2"]
1107             return bd_data
1108         except KeyError:
1109             raise HoneycombError("The operational data does not contain "
1110                                  "information about a bridge domain.")
1111
1112     @staticmethod
1113     def configure_tag_rewrite(node, super_interface, identifier, config):
1114         """Add / change / disable vlan tag rewrite on a sub-interface.
1115
1116         :param node: Honeycomb node.
1117         :param super_interface: Super interface.
1118         :param identifier: The ID of sub-interface.
1119         :param config: Rewrite tag configuration.
1120         :type node: dict
1121         :type super_interface: str
1122         :type identifier: int
1123         :type config: dict
1124         :return: Content of response.
1125         :rtype: bytearray
1126         """
1127
1128         path = ("interfaces",
1129                 ("interface", "name", super_interface),
1130                 "vpp-vlan:sub-interfaces",
1131                 ("sub-interface", "identifier", int(identifier)),
1132                 "l2",
1133                 "rewrite")
1134
1135         return InterfaceKeywords._set_interface_properties(
1136             node, super_interface, path, config)
1137
1138     @staticmethod
1139     def get_tag_rewrite_oper_data(node, super_interface, identifier):
1140         """Get the operational data about tag rewrite.
1141
1142         :param node: Honeycomb node.
1143         :param super_interface: Super interface.
1144         :param identifier: The ID of sub-interface.
1145         :type node: dict
1146         :type super_interface: str
1147         :type identifier: int
1148         :return: Operational data about tag rewrite.
1149         :rtype: dict
1150         :raises HoneycombError: If there is no sub-interface with the given ID.
1151         """
1152
1153         try:
1154             tag_rewrite = InterfaceKeywords.get_sub_interface_oper_data(
1155                 node, super_interface, identifier)["l2"]["rewrite"]
1156             return tag_rewrite
1157         except KeyError:
1158             raise HoneycombError("The operational data does not contain "
1159                                  "information about the tag-rewrite.")
1160
1161     @staticmethod
1162     def add_ipv4_address_to_sub_interface(node, super_interface, identifier,
1163                                           ip_addr, network):
1164         """Add an ipv4 address to the specified sub-interface, with the provided
1165         netmask or network prefix length. Any existing ipv4 addresses on the
1166         sub-interface will be replaced.
1167
1168         :param node: Honeycomb node.
1169         :param super_interface: Super interface.
1170         :param identifier: The ID of sub-interface.
1171         :param ip_addr: IPv4 address to be set.
1172         :param network: Network mask or network prefix length.
1173         :type node: dict
1174         :type super_interface: str
1175         :type identifier: int
1176         :type ip_addr: str
1177         :type network: str or int
1178         :return: Content of response.
1179         :rtype: bytearray
1180         :raises HoneycombError: If the provided netmask or prefix is not valid.
1181         """
1182
1183         path = ("interfaces",
1184                 ("interface", "name", super_interface),
1185                 "vpp-vlan:sub-interfaces",
1186                 ("sub-interface", "identifier", int(identifier)),
1187                 "ipv4")
1188
1189         if isinstance(network, basestring):
1190             address = {"address": [{"ip": ip_addr, "netmask": network}, ]}
1191
1192         elif isinstance(network, int) and 0 < network < 33:
1193             address = {"address": [{"ip": ip_addr, "prefix-length": network}, ]}
1194
1195         else:
1196             raise HoneycombError("{0} is not a valid netmask or prefix length."
1197                                  .format(network))
1198
1199         return InterfaceKeywords._set_interface_properties(
1200             node, super_interface, path, address)
1201
1202     @staticmethod
1203     def remove_all_ipv4_addresses_from_sub_interface(node, super_interface, # pylint: disable=invalid-name
1204                                                      identifier):
1205         """Remove all ipv4 addresses from the specified sub-interface.
1206
1207         :param node: Honeycomb node.
1208         :param super_interface: Super interface.
1209         :param identifier: The ID of sub-interface.
1210         :type node: dict
1211         :type super_interface: str
1212         :type identifier: int
1213         :return: Content of response.
1214         :rtype: bytearray
1215         """
1216
1217         path = ("interfaces",
1218                 ("interface", "name", super_interface),
1219                 "vpp-vlan:sub-interfaces",
1220                 ("sub-interface", "identifier", int(identifier)),
1221                 "ipv4", "address")
1222
1223         return InterfaceKeywords._set_interface_properties(
1224             node, super_interface, path, None)
1225
1226     @staticmethod
1227     def compare_data_structures(data, ref):
1228         """Checks if data obtained from UUT is as expected.
1229
1230         :param data: Data to be checked.
1231         :param ref: Referential data used for comparison.
1232         :type data: dict
1233         :type ref: dict
1234         :raises HoneycombError: If a parameter from referential data is not
1235         present in operational data or if it has different value.
1236         """
1237
1238         for key, item in ref.items():
1239             try:
1240                 if data[key] != item:
1241                     raise HoneycombError("The value of parameter '{0}' is "
1242                                          "incorrect. It should be "
1243                                          "'{1}' but it is '{2}'".
1244                                          format(key, item, data[key]))
1245             except KeyError:
1246                 raise HoneycombError("The parameter '{0}' is not present in "
1247                                      "operational data".format(key))
1248
1249     @staticmethod
1250     def compare_interface_lists(list1, list2):
1251         """Compare provided lists of interfaces by name.
1252
1253         :param list1: List of interfaces.
1254         :param list2: List of interfaces.
1255         :type list1: list
1256         :type list2: list
1257         :raises HoneycombError: If an interface exists in only one of the lists.
1258         """
1259
1260         ignore = ["vx_tunnel0", "vxlan_gpe_tunnel0"]
1261         # these have no equivalent in config data and no effect on VPP
1262
1263         names1 = [x['name'] for x in list1]
1264         names2 = [x['name'] for x in list2]
1265
1266         for name in names1:
1267             if name not in names2 and name not in ignore:
1268                 raise HoneycombError("Interface {0} not present in list {1}"
1269                                      .format(name, list2))
1270         for name in names2:
1271             if name not in names1 and name not in ignore:
1272                 raise HoneycombError("Interface {0} not present in list {1}"
1273                                      .format(name, list1))
1274
1275     @staticmethod
1276     def create_vxlan_gpe_interface(node, interface, **kwargs):
1277         """Create a new VxLAN GPE interface.
1278
1279         :param node: Honeycomb node.
1280         :param interface: The name of interface to be created.
1281         :param kwargs: Parameters and their values. The accepted parameters are
1282         defined in InterfaceKeywords.VXLAN_GPE_PARAMS.
1283         :type node: dict
1284         :type interface: str
1285         :type kwargs: dict
1286         :return: Content of response.
1287         :rtype: bytearray
1288         :raises HoneycombError: If a parameter in kwargs is not valid.
1289         """
1290
1291         new_vxlan_gpe = {
1292             "name": interface,
1293             "type": "v3po:vxlan-gpe-tunnel",
1294             "v3po:vxlan-gpe": {}
1295         }
1296         for param, value in kwargs.items():
1297             if param in InterfaceKeywords.INTF_PARAMS:
1298                 new_vxlan_gpe[param] = value
1299             elif param in InterfaceKeywords.VXLAN_GPE_PARAMS:
1300                 new_vxlan_gpe["v3po:vxlan-gpe"][param] = value
1301             else:
1302                 raise HoneycombError("The parameter {0} is invalid.".
1303                                      format(param))
1304         path = ("interfaces", "interface")
1305         vxlan_gpe_structure = [new_vxlan_gpe, ]
1306         return InterfaceKeywords._set_interface_properties(
1307             node, interface, path, vxlan_gpe_structure)
1308
1309     @staticmethod
1310     def enable_acl_on_interface(node, interface, table_name):
1311         """Enable ACL on the given interface.
1312
1313         :param node: Honeycomb node.
1314         :param interface: The interface where the ACL will be enabled.
1315         :param table_name: Name of the classify table.
1316         :type node: dict
1317         :type interface: str
1318         :type table_name: str
1319         :return: Content of response.
1320         :rtype: bytearray
1321         :raises HoneycombError: If the configuration of interface is not
1322         successful.
1323         """
1324
1325         interface = interface.replace("/", "%2F")
1326
1327         data = {
1328             "v3po:acl": {
1329                 "l2-acl": {
1330                     "classify-table": table_name
1331                 },
1332                 "ip4-acl": {
1333                     "classify-table": table_name
1334                 }
1335             }
1336         }
1337
1338         path = "/interface/" + interface + "/v3po:acl"
1339         status_code, resp = HcUtil.\
1340             put_honeycomb_data(node, "config_vpp_interfaces", data, path,
1341                                data_representation=DataRepresentation.JSON)
1342         if status_code != HTTPCodes.OK:
1343             raise HoneycombError(
1344                 "The configuration of interface '{0}' was not successful. "
1345                 "Status code: {1}.".format(interface, status_code))
1346         return resp
1347
1348     @staticmethod
1349     def disable_acl_on_interface(node, interface):
1350         """Disable ACL on the given interface.
1351
1352         :param node: Honeycomb node.
1353         :param interface: The interface where the ACL will be disabled.
1354         :type node: dict
1355         :type interface: str
1356         :return: Content of response.
1357         :rtype: bytearray
1358         :raises HoneycombError: If the configuration of interface is not
1359         successful.
1360         """
1361
1362         interface = interface.replace("/", "%2F")
1363
1364         path = "/interface/" + interface + "/v3po:acl"
1365
1366         status_code, resp = HcUtil.\
1367             delete_honeycomb_data(node, "config_vpp_interfaces", path)
1368
1369         if status_code != HTTPCodes.OK:
1370             raise HoneycombError(
1371                 "The configuration of interface '{0}' was not successful. "
1372                 "Status code: {1}.".format(interface, status_code))
1373         return resp