def remove_bridge_domain(node, bd_name): """Remove a bridge domain. :param node: Honeycomb node. :param bd_name: The name of bridge domain to be removed. :type node: dict :type bd_name: str :return: Content of response. :rtype: bytearray :raises HoneycombError:If it is not possible to remove the bridge domain. """ path = ("bridge-domains", ("bridge-domain", "name", bd_name)) status_code, resp = HcUtil.\ get_honeycomb_data(node, "config_bridge_domain") if status_code != HTTPCodes.OK: raise HoneycombError( "Not possible to get configuration information about the " "bridge domains. Status code: {0}.".format(status_code)) new_data = HcUtil.remove_item(resp, path) status_code, resp = HcUtil.\ put_honeycomb_data(node, "config_bridge_domain", new_data) if status_code != HTTPCodes.OK: raise HoneycombError("Not possible to remove bridge domain {0}. " "Status code: {1}.".format( bd_name, status_code)) return resp
def get_lispgpe_mapping(node, name): """Retrieve LISP GPE operational data and parse for a specific mapping. :param node: Honeycomb node. :param name: Name of the mapping to look for. :type node: dict :type name: str :returns: LISP GPE mapping. :rtype: dict :raises HoneycombError: If the mapping is not present in operational data. """ data = LispGPEKeywords.get_lispgpe_operational_data(node) try: data = data["gpe-state"]["gpe-feature-data"]["gpe-entry-table"] \ ["gpe-entry"] except KeyError: raise HoneycombError("No mappings present in operational data.") for item in data: if item["id"] == name: mapping = item break else: raise HoneycombError("Mapping with name {name} not found in " "operational data.".format(name=name)) return mapping
def configure_policer(node, policy_name, policer_data=None): """Configure Policer on the specified node. :param node: Honeycomb node. :param policer_data: Dictionary of configurations to apply. \ If it is None then the existing configuration is removed. :type node: dict :type policer_data: dict :returns: Content of response. :rtype: bytearray :raises HoneycombError: If policer could not be configured. """ path = '/' + policy_name if not policer_data: status_code, _ = HcUtil.delete_honeycomb_data( node, 'config_policer', path) else: data = {'policer': policer_data} status_code, _ = HcUtil.put_honeycomb_data(node, 'config_policer', data, path) if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): raise HoneycombError( 'Configuring policer failed. Status code:{0}'\ .format(status_code))
def get_interface_slaac_oper_data(node, interface): """Get operational data about SLAAC table present on the node. :param node: Honeycomb node. :param interface: Interface SLAAC data are retrieved from. :type node: dict :type interface: str :returns: dict of SLAAC operational data. :rtype: dict :raises HoneycombError: If status code differs from successful. """ interface = Topology.convert_interface_reference( node, interface, 'name') interface = interface.replace('/', '%2F') path = 'interface/' + interface status_code, resp = HcUtil.\ get_honeycomb_data(node, "config_slaac", path) if status_code != HTTPCodes.OK: raise HoneycombError( "Not possible to get operational information about SLAAC. " "Status code: {0}.".format(status_code)) try: dict_of_str = resp['interface'][0][ 'hc2vpp-ietf-ipv6-unicast-routing:ipv6-router-advertisements'] return {k: str(v) for k, v in dict_of_str.items()} except (KeyError, TypeError): return {}
def get_routing_table_oper(node, name, ip_version): """Retrieve operational data about the specified routing table. :param node: Honeycomb node. :param name: Name of the routing table. :param ip_version: IP protocol version, ipv4 or ipv6. :type node: dict :type name: str :type ip_version: str :returns: Routing table operational data. :rtype: list :raises HoneycombError: If the operation fails. """ path = "/routing-protocol/{0}".format(name) status_code, resp = HcUtil.\ get_honeycomb_data(node, "oper_routing_table", path) if status_code != HTTPCodes.OK: raise HoneycombError( "Not possible to get operational information about the " "classify tables. Status code: {0}.".format(status_code)) data = RoutingKeywords.clean_routing_oper_data( resp['routing-protocol'][0]['static-routes'][ 'hc2vpp-ietf-{0}-unicast-routing:{0}'.format( ip_version)]['route']) return data
def configure_interface_slaac(node, interface, slaac_data=None): """Configure SLAAC on the specified interfaces. :param node: Honeycomb node. :param interface: Interface to configure SLAAC. :param slaac_data: Dictionary of configurations to apply. \ If it is None then the existing configuration is removed. :type node: dict :type interface: str :type slaac_data: dict of dicts :returns: Content of response. :rtype: bytearray :raises HoneycombError: If RA could not be configured. """ interface = Topology.convert_interface_reference( node, interface, 'name') interface = interface.replace('/', '%2F') path = 'interface/' + interface + '/ipv6/ipv6-router-advertisements' if not slaac_data: status_code, _ = HcUtil.delete_honeycomb_data( node, 'config_slaac', path) else: data = { 'ipv6-router-advertisements': slaac_data } status_code, _ = HcUtil.put_honeycomb_data( node, 'config_slaac', data, path) if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): raise HoneycombError( 'Configuring SLAAC failed. Status code:{0}'.format(status_code))
def set_proxyarp_interface_config(node, interface, state): """Enable or disable the proxyARP feature on the specified interface. :param node: Honeycomb node. :param interface: Name or sw_if_index of an interface on the node. :param state: Desired proxyARP state: enable, disable. :type node: dict :type interface: str :type state: str :raises ValueError: If the state argument is incorrect. :raises HoneycombError: If the status code in response is not 200 = OK or 201 = ACCEPTED. """ interface = Topology.convert_interface_reference( node, interface, "name") interface = interface.replace("/", "%2F") path = "/interface/{0}/proxy-arp".format(interface) if state == "disable": status_code, _ = HcUtil.delete_honeycomb_data( node, "config_vpp_interfaces", path) elif state == "enable": data = {"proxy-arp": {}} status_code, _ = HcUtil.put_honeycomb_data( node, "config_vpp_interfaces", data, path) else: raise ValueError("State argument has to be enable or disable.") if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): raise HoneycombError( "Interface proxyARP configuration on node {0} was not" " successful.".format(node["host"]))
def configure_proxyarp(node, data): """Configure the proxyARP feature and check the return code. :param node: Honeycomb node. :param data: Configuration to use. :type node: dict :type data: dict :returns: Content of response. :rtype: bytearray :raises HoneycombError: If the status code in response to PUT is not 200 = OK or 201 = ACCEPTED. """ data = { "proxy-ranges": { "proxy-range": [ data, ] } } status_code, resp = HcUtil.\ put_honeycomb_data(node, "config_proxyarp_ranges", data, data_representation=DataRepresentation.JSON) if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): raise HoneycombError("proxyARP configuration unsuccessful. " "Status code: {0}.".format(status_code)) else: return resp
def _configure_bd(node, bd_name, data, data_representation=DataRepresentation.JSON): """Send bridge domain configuration data and check the response. :param node: Honeycomb node. :param bd_name: The name of bridge domain. :param data: Configuration data to be sent in PUT request. :param data_representation: How the data is represented. :type node: dict :type bd_name: str :type data: dict :type data_representation: DataRepresentation :return: Content of response. :rtype: bytearray :raises HoneycombError: If the status code in response on PUT is not 200 = OK. """ status_code, resp = HcUtil.\ put_honeycomb_data(node, "config_bridge_domain", data, data_representation=data_representation) if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): raise HoneycombError( "The configuration of bridge domain '{0}' was not successful. " "Status code: {1}.".format(bd_name, status_code)) return resp
def _set_bd_properties(node, bd_name, path, new_value=None): """Set bridge domain properties. This method reads bridge domain configuration data, creates, changes or removes the requested data and puts it back to Honeycomb. :param node: Honeycomb node. :param bd_name: The name of bridge domain. :param path: Path to data we want to change, create or remove. :param new_value: The new value to be set. If None, the item will be removed. :type node: dict :type bd_name: str :type path: tuple :type new_value: str, dict or list :return: Content of response. :rtype: bytearray :raises HoneycombError: If it is not possible to get or set the data. """ status_code, resp = HcUtil.\ get_honeycomb_data(node, "config_bridge_domain") if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): raise HoneycombError( "Not possible to get configuration information about the " "bridge domains. Status code: {0}.".format(status_code)) if new_value: new_data = HcUtil.set_item_value(resp, path, new_value) else: new_data = HcUtil.remove_item(resp, path) return BridgeDomainKeywords._configure_bd(node, bd_name, new_data)
def create_acl_plugin_classify_chain(node, list_name, data, macip=False): """Create classify chain using the ietf-acl node. :param node: Honeycomb node. :param list_name: Name for the classify list. :param data: Dictionary of settings to send to Honeycomb. :param macip: Use simple MAC+IP classifier. Optional. :type node: dict :type list_name: str :type data: dict :type macip: bool :returns: Content of response. :rtype: bytearray :raises HoneycombError: If the operation fails. """ if macip: path = "/acl/vpp-acl:vpp-macip-acl/{0}".format(list_name) else: path = "/acl/vpp-acl:vpp-acl/{0}".format(list_name) status_code, resp = HcUtil.put_honeycomb_data(node, "config_plugin_acl", data, path) if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): raise HoneycombError("Could not create classify chain." "Status code: {0}.".format(status_code)) return resp
def get_nsh_oper_data(node, entry_name=None, map_name=None): """Get all NSH operational data present on the node. Optionally filter out data for a specific entry or map. :param node: Honeycomb node. :param entry_name: Name of a specific NSH entry. Optional. :param map_name: Name of a specific NSH map. Optional. Do not use together with entry_name. :type node: dict :type entry_name: str :type map_name: str :return: List of classify tables. :rtype: list """ if entry_name: path = "/nsh-entries/nsh-entry/{0}".format(entry_name) elif map_name: path = "/nsh-maps/nsh-map/{0}".format(map_name) else: path = '' status_code, resp = HcUtil. \ get_honeycomb_data(node, "oper_nsh", path) if status_code != HTTPCodes.OK: raise HoneycombError( "Not possible to get operational information about the " "classify tables. Status code: {0}.".format(status_code)) return resp
def _configure_bgp_route(node, path, data=None): """Send BGP route configuration data and check the response. :param node: Honeycomb node. :param path: Additional path to append to the base BGP config path. :param data: Configuration data to be sent in PUT request. :type node: dict :type path: str :type data: dict :returns: Content of response. :rtype: bytearray :raises HoneycombError: If the status code in response to PUT is not 200 = OK or 201 = ACCEPTED. """ if data is None: status_code, resp = HcUtil. \ delete_honeycomb_data(node, "config_bgp_route", path) else: status_code, resp = HcUtil. \ put_honeycomb_data(node, "config_bgp_route", data, path) if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): raise HoneycombError( "The configuration of BGP route was not successful. " "Status code: {0}.".format(status_code)) return resp
def get_bgp_peer(node, address, datastore='config'): """Get BGP configuration of the specified peer from the node. :param node: Honeycomb node. :param address: IP address of the peer. :param datastore: Get data from config or operational datastore. :type node: dict :type address: str :type datastore; str :returns: BGP peer configuration data. :rtype: dict :raises HoneycombError: If the status code in response is not 200 = OK. """ path = "bgp-openconfig-extensions:neighbors/" \ "neighbor/{0}".format(address) if datastore != "operational": url = "config_bgp_peer" else: url = "oper_bgp" path = "peer/bgp:%2F%2F{0}".format(address) status_code, resp = HcUtil. \ get_honeycomb_data(node, url, path) if status_code != HTTPCodes.OK: raise HoneycombError( "Not possible to get configuration information about the BGP" " peer. Status code: {0}.".format(status_code)) return resp
def get_all_peer_routes(node, peer_address, ip_version): """Get all configured routes for the given BGP peer. :param node: Honeycomb node. :param peer_address: IP address of the peer. :param ip_version: IP protocol version. ipv4 or ipv6 :type node: dict :type peer_address: str :type ip_version: str :returns: Content of response. :rtype: bytearray :raises HoneycombError: If the status code in response is not 200 = OK. """ if ip_version.lower() == "ipv4": path = "{0}/tables/bgp-types:ipv4-address-family/" \ "bgp-types:unicast-subsequent-address-family/" \ "bgp-inet:ipv4-routes".format(peer_address) else: path = "{0}/tables/bgp-types:ipv6-address-family/" \ "bgp-types:unicast-subsequent-address-family/" \ "bgp-inet:ipv6-routes".format(peer_address) status_code, resp = HcUtil. \ get_honeycomb_data(node, "config_bgp_route", path) if status_code != HTTPCodes.OK: raise HoneycombError( "Not possible to get configuration information about BGP" " routes. Status code: {0}.".format(status_code)) return resp
def get_ipv6nd_configuration(node, interface): """Read IPv6 Neighbor Discovery proxy configuration on the specified interface. :param node: Honeycomb node. :param interface: Name of an interface on the node. :type node: dict :type interface: str :returns: Content of response. :rtype: bytearray :raises HoneycombError: If the configuration could not be read. """ interface = Topology.convert_interface_reference( node, interface, "name") interface = interface.replace("/", "%2F") path = "/interface/{0}/ietf-ip:ipv6/nd-proxies".format(interface) status_code, resp = HcUtil.get_honeycomb_data(node, "config_vpp_interfaces", path) if status_code != HTTPCodes.OK: raise HoneycombError("Could not read IPv6 ND proxy configuration. " "Status code: {0}.".format(status_code)) else: return resp
def get_fib_table_oper(node, ip_version, vrf=1): """Retrieve operational data about the specified FIB table. :param node: Honeycomb node. :param ip_version: IP protocol version, ipv4 or ipv6. :param vrf: vrf-id to attach configuration to. :type node: dict :type ip_version: str :type vrf: int :returns: FIB table operational data. :rtype: list :raises HoneycombError: If the operation fails. """ path = "/table/{0}/vpp-fib-table-management:{1}".format( vrf, ip_version) status_code, resp = HcUtil. \ get_honeycomb_data(node, "oper_fib_table", path) if status_code != HTTPCodes.OK: raise HoneycombError( "Not possible to get operational information about the " "FIB tables. Status code: {0}.".format(status_code)) data = resp['vpp-fib-table-management:table'][0] return data
def _set_dhcp_relay_properties(node, path, data=None): """Set DHCP relay properties and check the return code. :param node: Honeycomb node. :param path: Path which is added to the base path to identify the data. :param data: The new data to be set. If None, the item will be removed. :type node: dict :type path: str :type data: dict :returns: Content of response. :rtype: bytearray :raises HoneycombError: If the status code in response is not 200 = OK or 201 = ACCEPTED. """ if data: status_code, resp = HcUtil. \ put_honeycomb_data(node, "config_dhcp_relay", data, path, data_representation=DataRepresentation.JSON) else: status_code, resp = HcUtil. \ delete_honeycomb_data(node, "config_dhcp_relay", path) if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): raise HoneycombError( "The configuration of DHCP relay was not successful. " "Status code: {0}.".format(status_code)) return resp
def _set_classify_table_properties(node, path, data=None): """Set classify table properties and check the return code. :param node: Honeycomb node. :param path: Path which is added to the base path to identify the data. :param data: The new data to be set. If None, the item will be removed. :type node: dict :type path: str :type data: dict :returns: Content of response. :rtype: bytearray :raises HoneycombError: If the status code in response to PUT is not 200 = OK. """ if data: status_code, resp = HcUtil.\ put_honeycomb_data(node, "config_classify_table", data, path, data_representation=DataRepresentation.JSON) else: status_code, resp = HcUtil.\ delete_honeycomb_data(node, "config_classify_table", path) if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): if data is None and '"error-tag":"data-missing"' in resp: logger.debug("data does not exist in path.") else: raise HoneycombError( "The configuration of classify table was not successful. " "Status code: {0}.".format(status_code)) return resp
def get_nat_oper_data(node): """Read NAT operational data. :param node: Honeycomb node. :type node: dict :returns: Content of response. :rtype: bytearray :raises HoneycombError: If the operation fails or the response is not as expected. """ status_code, resp = HcUtil.get_honeycomb_data(node, "oper_nat") if status_code != HTTPCodes.OK: raise HoneycombError("Could not retrieve NAT operational data.") if "nat-state" not in resp.keys(): raise HoneycombError( "Unexpected format, response does not contain nat-state.") return resp['nat-state']
def delete_acl_plugin_classify_chains(node): """Remove all plugin-ACL classify chains. :param node: Honeycomb node. :type node: dict """ status_code, _ = HcUtil.delete_honeycomb_data(node, "config_plugin_acl") if status_code != HTTPCodes.OK: raise HoneycombError("Could not remove plugin-acl chain. " "Status code: {0}.".format(status_code))
def remove_l2_fib_entry(node, bd_name, mac): """Remove an L2 FIB entry from bridge domain's L2 FIB table. The entry is specified by MAC address. :param node: Honeycomb node. :param bd_name: Bridge domain's name. :param mac: MAC address used as the key in L2 FIB data structure. :type node: dict :type bd_name: str :type mac: str :return: Content of response. :rtype: bytearray :raises HoneycombError: If it is not possible to remove the specified entry. """ path = ("bridge-domains", ("bridge-domain", "name", bd_name), "l2-fib-table", ("l2-fib-entry", "phys-address", str(mac))) status_code, resp = HcUtil.\ get_honeycomb_data(node, "config_bridge_domain") if status_code != HTTPCodes.OK: raise HoneycombError( "Not possible to get configuration information" " about the L2 FIB entry {0} from bridge " "domain {1}. Status code: {2}.".format(mac, bd_name, status_code)) new_data = HcUtil.remove_item(resp, path) status_code, resp = HcUtil.\ put_honeycomb_data(node, "config_bridge_domain", new_data) if status_code != HTTPCodes.OK: raise HoneycombError( "Not possible to remove L2 FIB entry {0} from " "bridge domain {1}. Status code: {2}.".format( mac, bd_name, status_code)) return resp
def get_classify_table_oper_data(node, table_name): """Get operational data about the given classify table. :param node: Honeycomb node. :param table_name: Name of the classify table. :type node: dict :type table_name: str :returns: Operational data about the given classify table. :rtype: dict """ tables = ACLKeywords.get_all_classify_tables_oper_data(node) for table in tables: if table["name"] == table_name: return table raise HoneycombError( "Table {0} not found in ACL table list.".format(table_name))
def get_full_bgp_configuration(node): """Get BGP configuration from the node. :param node: Honeycomb node. :type node: dict :returns: BGP configuration data. :rtype: dict :raises HoneycombError: If the status code in response is not 200 = OK. """ status_code, resp = HcUtil. \ get_honeycomb_data(node, "config_bgp_peer") if status_code != HTTPCodes.OK: raise HoneycombError( "Not possible to get configuration information about BGP." " Status code: {0}.".format(status_code)) return resp
def get_all_classify_tables_oper_data(node): """Get operational data about all classify tables present on the node. :param node: Honeycomb node. :type node: dict :returns: List of classify tables. :rtype: list """ status_code, resp = HcUtil.\ get_honeycomb_data(node, "oper_classify_table") if status_code != HTTPCodes.OK: raise HoneycombError( "Not possible to get operational information about the " "classify tables. Status code: {0}.".format(status_code)) return resp["vpp-classifier-state"]["classify-table"]
def remove_proxyarp_configuration(node): """Delete the proxyARP node, removing all of its configuration. :param node: Honeycomb node. :type node: dict :returns: Content of response. :rtype: bytearray :raises HoneycombError: If the status code in response is not 200 = OK. """ status_code, resp = HcUtil. \ delete_honeycomb_data(node, "config_proxyarp_ranges") if status_code != HTTPCodes.OK: raise HoneycombError("proxyARP removal unsuccessful. " "Status code: {0}.".format(status_code)) else: return resp
def compare_rib_tables(data, ref): """Compare provided RIB table with reference. All reference entries must be present in data. Data entries not present in reference are ignored. :param data: Data from Honeycomb node. :param ref: Reference data to compare against. :type data: dict :type ref: dict :raises HoneycombError: If the tables do not match.""" # Remove runtime attributes from data for item in data: item.pop("attributes", "") for item in ref: if item not in data: raise HoneycombError( "RIB entry {0} not found in operational data.")
def get_lispgpe_config_data(node): """Retrieve LISP GPE properties from Honeycomb config data. :param node: Honeycomb node. :type node: dict :returns: LISP GPE config data. :rtype: bytearray :raises HoneycombError: If the status code in response to GET is not 200 = OK. """ status_code, resp = HcUtil.get_honeycomb_data(node, "config_lisp_gpe") if status_code != HTTPCodes.OK: raise HoneycombError("Could not retrieve Lisp GPE config data." "Status code: {0}.".format(status_code)) else: return resp
def get_dhcp_relay_oper_data(node): """Get operational data about the DHCP relay feature. :param node: Honeycomb node. :type node: dict :returns: Content of response. :rtype: bytearray :raises HoneycombError: If the status code in response is not 200 = OK. """ status_code, resp = HcUtil. \ get_honeycomb_data(node, "config_dhcp_relay") if status_code != HTTPCodes.OK: raise HoneycombError( "Could not retrieve DHCP relay configuration. " "Status code: {0}.".format(status_code)) return resp
def configure_ipv6nd(node, interface, addresses=None): """Configure IPv6 Neighbor Discovery proxy on the specified interface, or remove/replace an existing configuration. :param node: Honeycomb node. :param interface: Name of an interface on the node. :param addresses: IPv6 addresses to configure ND proxy with. If no address is provided, ND proxy configuration will be removed. :type node: dict :type interface: str :type addresses: list :returns: Content of response. :rtype: bytearray :raises HoneycombError: If the operation fails. """ interface = Topology.convert_interface_reference( node, interface, "name") interface = interface.replace("/", "%2F") path = "/interface/{0}/ietf-ip:ipv6/nd-proxies".format(interface) if addresses is None: status_code, resp = HcUtil. \ delete_honeycomb_data(node, "config_vpp_interfaces", path) else: data = { "nd-proxies": { "nd-proxy": [{ "address": x } for x in addresses] } } 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("IPv6 ND proxy configuration unsuccessful. " "Status code: {0}.".format(status_code)) else: return resp