X-Git-Url: https://gerrit.fd.io/r/gitweb?p=csit.git;a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2Fhoneycomb%2FHcAPIKwInterfaces.py;h=e78696cd1516b9344de59111c66d22c392709292;hp=5658eea1463cbc52449315a6f726e6febd5451d3;hb=fa14d9f454a7248a71135375bfb0758cdb532ca7;hpb=cf561a6e3d4c4fbd78ab6c9d0a9aa817bb3300fc diff --git a/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py b/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py index 5658eea146..e78696cd15 100644 --- a/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py +++ b/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 Cisco and/or its affiliates. +# Copyright (c) 2017 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: @@ -44,7 +44,7 @@ class InterfaceKeywords(object): "temporary-valid-lifetime", "temporary-preferred-lifetime") ETH_PARAMS = ("mtu", ) - ROUTING_PARAMS = ("vrf-id", ) + ROUTING_PARAMS = ("ipv4-vrf-id", "ipv6-vrf-id") VXLAN_PARAMS = ("src", "dst", "vni", "encap-vrf-id") L2_PARAMS = ("bridge-domain", "split-horizon-group", "bridged-virtual-interface") @@ -201,6 +201,16 @@ class InterfaceKeywords(object): :rtype: dict """ + try: + interface = Topology.convert_interface_reference( + node, interface, "name") + except RuntimeError: + if isinstance(interface, basestring): + # Probably name of a custom interface (TAP, VxLAN, Vhost, ...) + pass + else: + raise + intfs = InterfaceKeywords.get_all_interfaces_oper_data(node) for intf in intfs: if intf["name"] == interface: @@ -513,9 +523,9 @@ class InterfaceKeywords(object): path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4", "address") if isinstance(network, basestring): - address = {"address": [{"ip": ip_addr, "netmask": network}, ]} + address = [{"ip": ip_addr, "netmask": network}] elif isinstance(network, int) and (0 < network < 33): - address = {"address": [{"ip": ip_addr, "prefix-length": network}, ]} + address = [{"ip": ip_addr, "prefix-length": network}] else: raise HoneycombError("Value {0} is not a valid netmask or network " "prefix length.".format(network)) @@ -555,6 +565,9 @@ class InterfaceKeywords(object): :rtype: bytearray """ + interface = Topology.convert_interface_reference( + node, interface, "name") + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4", "neighbor") neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ] @@ -626,6 +639,9 @@ class InterfaceKeywords(object): :rtype: bytearray """ + interface = Topology.convert_interface_reference( + node, interface, "name") + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6") address = {"address": [{"ip": ip_addr, "prefix-length": prefix_len}, ]} return InterfaceKeywords._set_interface_properties( @@ -647,6 +663,9 @@ class InterfaceKeywords(object): :rtype: bytearray """ + interface = Topology.convert_interface_reference( + node, interface, "name") + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6", "address") address = [{"ip": ip_addr, "prefix-length": prefix_len}, ] @@ -686,6 +705,9 @@ class InterfaceKeywords(object): :rtype: bytearray """ + interface = Topology.convert_interface_reference( + node, interface, "name") + path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6", "neighbor") neighbor = [{"ip": ip_addr, "link-layer-address": link_layer_address}, ] @@ -752,6 +774,9 @@ class InterfaceKeywords(object): :raises HoneycombError: If the parameter is not valid. """ + interface = Topology.convert_interface_reference( + node, interface, "name") + if param not in InterfaceKeywords.ROUTING_PARAMS: raise HoneycombError("The parameter {0} is invalid.".format(param)) @@ -1137,13 +1162,16 @@ class InterfaceKeywords(object): :rtype: bytearray """ + super_interface = Topology.convert_interface_reference( + node, super_interface, "name") + intf_state = {"up": "true", "down": "false"} path = ("interfaces", ("interface", "name", super_interface), "vpp-vlan:sub-interfaces", - ("sub-interface", "identifier", identifier), + ("sub-interface", "identifier", int(identifier)), "enabled") return InterfaceKeywords._set_interface_properties( @@ -1248,8 +1276,8 @@ class InterfaceKeywords(object): "information about the tag-rewrite.") @staticmethod - def add_ipv4_address_to_sub_interface(node, super_interface, identifier, - ip_addr, network): + def add_ip_address_to_sub_interface(node, super_interface, identifier, + ip_addr, network, ip_version): """Add an ipv4 address to the specified sub-interface, with the provided netmask or network prefix length. Any existing ipv4 addresses on the sub-interface will be replaced. @@ -1259,11 +1287,13 @@ class InterfaceKeywords(object): :param identifier: The ID of sub-interface. :param ip_addr: IPv4 address to be set. :param network: Network mask or network prefix length. + :param ip_version: ipv4 or ipv6 :type node: dict :type super_interface: str :type identifier: int :type ip_addr: str :type network: str or int + :type ip_version: string :returns: Content of response. :rtype: bytearray :raises HoneycombError: If the provided netmask or prefix is not valid. @@ -1273,9 +1303,9 @@ class InterfaceKeywords(object): ("interface", "name", super_interface), "vpp-vlan:sub-interfaces", ("sub-interface", "identifier", int(identifier)), - "ipv4") + ip_version.lower()) - if isinstance(network, basestring): + if isinstance(network, basestring) and ip_version.lower() == "ipv4": address = {"address": [{"ip": ip_addr, "netmask": network}, ]} elif isinstance(network, int) and 0 < network < 33: @@ -1289,16 +1319,18 @@ class InterfaceKeywords(object): node, super_interface, path, address) @staticmethod - def remove_all_ipv4_addresses_from_sub_interface(node, super_interface, - identifier): + def remove_all_ip_addresses_from_sub_interface(node, super_interface, + identifier, ip_version): """Remove all ipv4 addresses from the specified sub-interface. :param node: Honeycomb node. :param super_interface: Super interface. :param identifier: The ID of sub-interface. + :param ip_version: ipv4 or ipv6 :type node: dict :type super_interface: str :type identifier: int + :type ip_version: string :returns: Content of response. :rtype: bytearray """ @@ -1307,49 +1339,79 @@ class InterfaceKeywords(object): ("interface", "name", super_interface), "vpp-vlan:sub-interfaces", ("sub-interface", "identifier", int(identifier)), - "ipv4", "address") + str(ip_version), "address") return InterfaceKeywords._set_interface_properties( node, super_interface, path, None) @staticmethod - def compare_data_structures(data, ref, ignore=(), list_order=True): - """Checks if data obtained from UUT is as expected. + def compare_data_structures(data, ref, _path=''): + """Checks if data obtained from UUT is as expected. If it is not, + proceeds down the list/dictionary tree and finds the point of mismatch. :param data: Data to be checked. :param ref: Referential data used for comparison. - :param ignore: Dictionary keys to be ignored. - :param list_order: Whether to consider the order of list items\ - in comparison. + :param _path: Used in recursive calls, stores the path taken down + the JSON tree. :type data: dict :type ref: dict - :type ignore: iterable - :type list_order: bool + :type _path: str - :raises HoneycombError: If a parameter from referential data is not - present in operational data or if it has different value. + :raises HoneycombError: If the data structures do not match in some way, + or if they are not in deserialized JSON format. """ - errors = "" - - for key, item in ref.items(): - if key in ignore: - continue - try: - if data[key] != item: - if not list_order and sorted(data[key]) == sorted(item): - pass + if data == ref: + return True + + elif isinstance(data, dict) and isinstance(ref, dict): + for key in ref: + if key not in data: + raise HoneycombError( + "Key {key} is not present in path {path}. Keys in path:" + "{data_keys}".format( + key=key, + path=_path, + data_keys=data.keys())) + + if data[key] != ref[key]: + if isinstance(data[key], list) \ + or isinstance(data[key], dict): + InterfaceKeywords.compare_data_structures( + data[key], ref[key], + _path + '[{0}]'.format(key)) else: - errors += ("\nThe value of parameter '{0}' is " - "incorrect. It should be " - "'{1}' but it is '{2}'". - format(key, item, data[key])) - except KeyError: - errors += ("\nThe parameter '{0}' is not present in " - "operational data".format(key)) + raise HoneycombError( + "Data mismatch, key {key} in path {path} has value" + " {data}, but should be {ref}".format( + key=key, + path=_path, + data=data[key], + ref=ref[key])) + + elif isinstance(data, list) and isinstance(ref, list): + for item in ref: + if item not in data: + if isinstance(item, dict): + InterfaceKeywords.compare_data_structures( + data[0], item, + _path + '[{0}]'.format(ref.index(item))) + else: + raise HoneycombError( + "Data mismatch, list item {index} in path {path}" + " has value {data}, but should be {ref}".format( + index=ref.index(item), + path=_path, + data=data[0], + ref=item)) - if errors: - raise HoneycombError(errors) + else: + raise HoneycombError( + "Unexpected data type {data_type} in path {path}, reference" + " type is {ref_type}. Must be list or dictionary.".format( + data_type=type(data), + ref_type=type(ref), + path=_path)) @staticmethod def compare_interface_lists(list1, list2): @@ -1430,7 +1492,7 @@ class InterfaceKeywords(object): interface = interface.replace("/", "%2F") data = { - "v3po:acl": { + "vpp-interface-acl:acl": { "ingress": { "ip4-acl": { "classify-table": table_name @@ -1442,7 +1504,42 @@ class InterfaceKeywords(object): } } - path = "/interface/" + interface + "/v3po:acl" + path = "/interface/" + interface + "/vpp-interface-acl:acl" + status_code, resp = HcUtil.\ + put_honeycomb_data(node, "config_vpp_interfaces", data, path, + data_representation=DataRepresentation.JSON) + if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): + raise HoneycombError( + "The configuration of interface '{0}' was not successful. " + "Status code: {1}.".format(interface, status_code)) + return resp + + @staticmethod + def enable_policer_on_interface(node, interface, table_name): + """Enable Policer on the given interface. + + :param node: Honeycomb node. + :param interface: The interface where policer will be enabled. + :param table_name: Name of the classify table. + :type node: dict + :type interface: str + :type table_name: str + :returns: Content of response. + :rtype: bytearray + :raises HoneycombError: If the configuration of interface is not + successful. + """ + interface = Topology.convert_interface_reference( + node, interface, "name") + interface = interface.replace("/", "%2F") + + data = { + "interface-policer:policer": { + "ip4-table": table_name + } + } + + path = "/interface/" + interface + "/interface-policer:policer" status_code, resp = HcUtil.\ put_honeycomb_data(node, "config_vpp_interfaces", data, path, data_representation=DataRepresentation.JSON) @@ -1452,6 +1549,34 @@ class InterfaceKeywords(object): "Status code: {1}.".format(interface, status_code)) return resp + @staticmethod + def disable_policer_on_interface(node, interface): + """Disable Policer on the given interface. + + :param node: Honeycomb node. + :param interface: The interface where policer will be disabled. + :param table_name: Name of the classify table. + :type node: dict + :type interface: str + :type table_name: str + :returns: Content of response. + :rtype: bytearray + :raises HoneycombError: If the configuration of interface is not + successful. + """ + interface = Topology.convert_interface_reference( + node, interface, "name") + interface = interface.replace("/", "%2F") + + path = "/interface/" + interface + "/interface-policer:policer" + status_code, resp = HcUtil.\ + delete_honeycomb_data(node, "config_vpp_interfaces", path) + if status_code != HTTPCodes.OK: + raise HoneycombError( + "The configuration of interface '{0}' was not successful. " + "Status code: {1}.".format(interface, status_code)) + return resp + @staticmethod def disable_acl_on_interface(node, interface): """Disable ACL on the given interface. @@ -1468,7 +1593,7 @@ class InterfaceKeywords(object): interface = interface.replace("/", "%2F") - path = "/interface/" + interface + "/v3po:acl" + path = "/interface/" + interface + "/vpp-interface-acl:acl" status_code, resp = HcUtil.\ delete_honeycomb_data(node, "config_vpp_interfaces", path) @@ -1498,7 +1623,7 @@ class InterfaceKeywords(object): """ interface = intf.replace("/", "%2F") - path = "/interface/{0}/pbb-rewrite/".format(interface) + path = "/interface/{0}/pbb-rewrite".format(interface) status_code, resp = HcUtil. \ put_honeycomb_data(node, "config_vpp_interfaces", params, path, data_representation=DataRepresentation.JSON) @@ -1576,7 +1701,7 @@ class InterfaceKeywords(object): " of disabled interfaces.".format(interface)) @staticmethod - def configure_interface_span(node, dst_interface, *src_interfaces): + def configure_interface_span(node, dst_interface, src_interfaces=None): """Configure SPAN port mirroring on the specified interfaces. If no source interface is provided, SPAN will be disabled. @@ -1584,30 +1709,88 @@ class InterfaceKeywords(object): :param dst_interface: Interface to mirror packets to. :param src_interfaces: List of interfaces to mirror packets from. :type node: dict - :type dst_interface: str - :type src_interfaces: list of str + :type dst_interface: str or int + :type src_interfaces: list of dict :returns: Content of response. :rtype: bytearray :raises HoneycombError: If SPAN could not be configured. """ - interface = dst_interface.replace("/", "%2F") + interface = Topology.convert_interface_reference( + node, dst_interface, "name") + interface = interface.replace("/", "%2F") path = "/interface/" + interface + "/span" if not src_interfaces: status_code, _ = HcUtil.delete_honeycomb_data( node, "config_vpp_interfaces", path) + else: + for src_interface in src_interfaces: + src_interface["iface-ref"] = Topology.\ + convert_interface_reference( + node, src_interface["iface-ref"], "name") + data = { + "span": { + "mirrored-interfaces": { + "mirrored-interface": src_interfaces + } + } + } - data = { - "span": { - "mirrored-interfaces": { - "mirrored-interface": src_interfaces + status_code, _ = HcUtil.put_honeycomb_data( + node, "config_vpp_interfaces", data, path) + + if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): + raise HoneycombError( + "Configuring SPAN failed. Status code:{0}".format(status_code)) + + @staticmethod + def configure_sub_interface_span(node, super_interface, dst_interface_index, + src_interfaces=None): + """Configure SPAN port mirroring on the specified sub-interface. If no + source interface is provided, SPAN will be disabled. + + Note: Does not support source sub-interfaces, only destination. + + :param node: Honeycomb node. + :param super_interface: Name, link name or sw_if_index + of the destination interface's super-interface. + :param dst_interface_index: Index of sub-interface to mirror packets to. + :param src_interfaces: List of interfaces to mirror packets from. + :type node: dict + :type super_interface: str or int + :type dst_interface_index: int + :type src_interfaces: list of dict + :returns: Content of response. + :rtype: bytearray + :raises HoneycombError: If SPAN could not be configured. + """ + + super_interface = Topology.convert_interface_reference( + node, super_interface, "name") + super_interface = super_interface.replace("/", "%2F") + + path = "/interface/{0}/vpp-vlan:sub-interfaces/sub-interface/{1}/span"\ + .format(super_interface, dst_interface_index) + + if not src_interfaces: + status_code, _ = HcUtil.delete_honeycomb_data( + node, "config_vpp_interfaces", path) + else: + for src_interface in src_interfaces: + src_interface["iface-ref"] = Topology. \ + convert_interface_reference( + node, src_interface["iface-ref"], "name") + data = { + "span": { + "mirrored-interfaces": { + "mirrored-interface": src_interfaces + } } } - } - status_code, _ = HcUtil.put_honeycomb_data( - node, "config_vpp_interfaces", data, path) + status_code, _ = HcUtil.put_honeycomb_data( + node, "config_vpp_interfaces", data, path) if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): raise HoneycombError(