diff options
author | Peter Mikus <pmikus@cisco.com> | 2019-11-11 16:14:32 +0000 |
---|---|---|
committer | Peter Mikus <pmikus@cisco.com> | 2019-11-19 06:43:59 +0000 |
commit | e7ad66f3147662973039caaac33015de7e0c6f8c (patch) | |
tree | 809a056325425bad672a8a9274c3c2d696a35030 /resources/libraries/python | |
parent | 20cc67d5f23a7f4e05b08012bf3d3a63be4bcf63 (diff) |
HONEYCOMB: Remove
Signed-off-by: Peter Mikus <pmikus@cisco.com>
Change-Id: I60d80564050cb786c7b1e0a08f31f8292f82197e
Diffstat (limited to 'resources/libraries/python')
20 files changed, 0 insertions, 6972 deletions
diff --git a/resources/libraries/python/Constants.py b/resources/libraries/python/Constants.py index 0b0d6f866e..3fa9ae28dc 100644 --- a/resources/libraries/python/Constants.py +++ b/resources/libraries/python/Constants.py @@ -187,21 +187,6 @@ class Constants(object): # TRex install directory TREX_INSTALL_DIR = '/opt/trex-core-2.61' - # Honeycomb directory location at topology nodes: - REMOTE_HC_DIR = '/opt/honeycomb' - - # Honeycomb persistence files location - REMOTE_HC_PERSIST = '/var/lib/honeycomb/persist' - - # Honeycomb log file location - REMOTE_HC_LOG = '/var/log/honeycomb/honeycomb.log' - - # Honeycomb templates location - RESOURCES_TPL_HC = 'resources/templates/honeycomb' - - # ODL Client Restconf listener port - ODL_PORT = 8181 - # Sysctl kernel.core_pattern KERNEL_CORE_PATTERN = '/tmp/%p-%u-%g-%s-%t-%h-%e.core' diff --git a/resources/libraries/python/honeycomb/BGP.py b/resources/libraries/python/honeycomb/BGP.py deleted file mode 100644 index 976e41d379..0000000000 --- a/resources/libraries/python/honeycomb/BGP.py +++ /dev/null @@ -1,396 +0,0 @@ -# Copyright (c) 2018 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Keywords to manipulate BGP configuration using Honeycomb REST API.""" - -from resources.libraries.python.Constants import Constants as Const -from resources.libraries.python.HTTPRequest import HTTPCodes -from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError -from resources.libraries.python.honeycomb.HoneycombUtil \ - import HoneycombUtil as HcUtil - - -class BGPKeywords(object): - """Keywords to manipulate BGP configuration. - - Implements keywords which read configuration and operational data for - the BGP feature, and configure BGP parameters using Honeycomb REST API. - """ - - def __init__(self): - """Initializer.""" - pass - - @staticmethod - def _configure_bgp_peer(node, path, data=None): - """Send BGP peer 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_peer", path) - else: - status_code, resp = HcUtil.\ - put_honeycomb_data(node, "config_bgp_peer", data, path) - if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): - raise HoneycombError( - "The configuration of BGP peer was not successful. " - "Status code: {0}.".format(status_code)) - return resp - - @staticmethod - 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 - - @staticmethod - 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 - - @staticmethod - 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 - - @staticmethod - def add_bgp_peer(node, address, data): - """Configure a BGP peer on the node. - - :param node: Honeycomb node. - :param address: IP address of the peer. - :param data: Peer configuration data. - :type node: dict - :type address: str - :type data: dict - :returns: Content of response. - :rtype: bytearray - """ - - path = "bgp-openconfig-extensions:neighbors/neighbor/{address}".format( - address=address) - return BGPKeywords._configure_bgp_peer(node, path, data) - - @staticmethod - def remove_bgp_peer(node, address): - """Remove a BGP peer from the configuration. - - :param node: Honeycomb node. - :param address: IP address of the peer. - :type node: dict - :type address: str - :returns: Content of response. - :rtype: bytearray - """ - - path = "bgp-openconfig-extensions:neighbors/neighbor/{address}".format( - address=address) - return BGPKeywords._configure_bgp_peer(node, path) - - @staticmethod - def configure_bgp_route(node, peer_address, data, route_address, - index, ip_version): - """Configure a route for the BGP peer specified by peer IP address. - - :param node: Honeycomb node. - :param peer_address: IP address of the BGP peer. - :param data: Route configuration data. - :param route_address: IP address of the route. - :param index: Index number of the route within specified peer. - :param ip_version: IP protocol version. ipv4 or ipv6 - :type node: dict - :type peer_address: str - :type data: dict - :type route_address: str - :type index: int - :type ip_version: str - :returns: Content of response. - :rtype: bytearray - """ - - route_address = route_address.replace("/", "%2F") - - if ip_version.lower() == "ipv4": - path = "{0}/tables/bgp-types:ipv4-address-family/" \ - "bgp-types:unicast-subsequent-address-family/" \ - "bgp-inet:ipv4-routes/ipv4-route/{1}/{2}" \ - .format(peer_address, route_address, index) - else: - path = "{0}/tables/bgp-types:ipv6-address-family/" \ - "bgp-types:unicast-subsequent-address-family/" \ - "bgp-inet:ipv6-routes/ipv6-route/{1}/{2}" \ - .format(peer_address, route_address, index) - - return BGPKeywords._configure_bgp_route(node, path, data) - - @staticmethod - def get_bgp_route(node, peer_address, route_address, index, ip_version): - """Get all BGP peers from operational data. - - :param node: Honeycomb node. - :param peer_address: IP address of the BGP peer. - :param route_address: IP address of the route. - :param index: Index number of the route within specified peer. - :param ip_version: IP protocol version. ipv4 or ipv6 - :type node: dict - :type peer_address: str - :type route_address: str - :type index: int - :type ip_version: str - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the status code in response is not 200 = OK. - """ - - route_address = route_address.replace("/", "%2F") - - if ip_version.lower() == "ipv4": - path = "{0}/tables/bgp-types:ipv4-address-family/" \ - "bgp-types:unicast-subsequent-address-family/" \ - "bgp-inet:ipv4-routes/ipv4-route/{1}/{2}" \ - .format(peer_address, route_address, index) - else: - path = "{0}/tables/bgp-types:ipv6-address-family/" \ - "bgp-types:unicast-subsequent-address-family/" \ - "bgp-inet:ipv6-routes/ipv6-route/{1}/{2}" \ - .format(peer_address, route_address, index) - 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 the BGP" - " route. Status code: {0}.".format(status_code)) - - return resp - - @staticmethod - 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 - - @staticmethod - def remove_bgp_route(node, peer_address, route_address, index, ip_version): - """Remove the specified BGP route from configuration. - - :param node: Honeycomb node. - :param peer_address: IP address of the BGP peer. - :param route_address: IP address of the route. - :param index: Index number of the route within specified peer. - :param ip_version: IP protocol version. ipv4 or ipv6 - :type node: dict - :type peer_address: str - :type route_address: str - :type index: int - :type ip_version: str - :returns: Content of response. - :rtype: bytearray - """ - - route_address = route_address.replace("/", "%2F") - - if ip_version.lower() == "ipv4": - path = "{0}/tables/bgp-types:ipv4-address-family/" \ - "bgp-types:unicast-subsequent-address-family/" \ - "bgp-inet:ipv4-routes/ipv4-route/{1}/{2}" \ - .format(peer_address, route_address, index) - else: - path = "{0}/tables/bgp-types:ipv6-address-family/" \ - "bgp-types:unicast-subsequent-address-family/" \ - "bgp-inet:ipv6-routes/ipv6-route/{1}/{2}" \ - .format(peer_address, route_address, index) - - return BGPKeywords._configure_bgp_route(node, path) - - @staticmethod - def get_bgp_local_rib(node): - """Get local RIB table from the Honeycomb node. - - :param node: Honeycomb node. - :type node: dict - :returns: RIB operational data. - :rtype: dict - :raises HoneycombError: If the status code in response is not 200 = OK. - """ - - path = "loc-rib" - - status_code, resp = HcUtil. \ - get_honeycomb_data(node, "oper_bgp", path) - - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get operational data from BGP local RIB." - " Status code: {0}.".format(status_code)) - - return resp - - @staticmethod - def configure_bgp_base(node, ip_address, port, as_number): - """Modify BGP config file. Requires a restart of Honeycomb to take - effect. - - :param node: Honeycomb node. - :param ip_address: BGP peer identifier/binding address. - :param port: BGP binding port. - :param as_number: Autonomous System ID number. - :type node: dict - :type ip_address: str - :type port: int - :type as_number: int - :raises HoneycombError: If modifying the configuration fails. - """ - - from resources.libraries.python.ssh import SSH - - config = { - '\\"bgp-binding-address\\"': '\\"{0}\\"'.format(ip_address), - '\\"bgp-port\\"': port, - '\\"bgp-as-number\\"': as_number} - - path = "{0}/config/bgp.json".format(Const.REMOTE_HC_DIR) - - for key, value in config.items(): - find = key - replace = '"{0}": "{1}",'.format(key, value) - - argument = '"/{0}/c\\ {1}"'.format(find, replace) - command = "sed -i {0} {1}".format(argument, path) - - ssh = SSH() - ssh.connect(node) - (ret_code, _, stderr) = ssh.exec_command_sudo(command) - if ret_code != 0: - raise HoneycombError("Failed to modify configuration on " - "node {0}, {1}".format(node, stderr)) - - @staticmethod - 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 {1}." - .format(item, data)) diff --git a/resources/libraries/python/honeycomb/DHCP.py b/resources/libraries/python/honeycomb/DHCP.py deleted file mode 100644 index 56cfdb2a78..0000000000 --- a/resources/libraries/python/honeycomb/DHCP.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright (c) 2018 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Keywords to manipulate NAT configuration using Honeycomb REST API.""" - -from resources.libraries.python.HTTPRequest import HTTPCodes -from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError -from resources.libraries.python.honeycomb.HoneycombUtil \ - import DataRepresentation -from resources.libraries.python.honeycomb.HoneycombUtil \ - import HoneycombUtil as HcUtil - - -class DHCPRelayKeywords(object): - """Keywords for NAT configuration.""" - - def __init__(self): - pass - - @staticmethod - 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 - - @staticmethod - def add_dhcp_relay(node, data, ip_version, entry_id): - """Add a DHCP relay entry to the list on entries. - - :param node: Honeycomb node. - :param data: Configuration for the relay entry. - :param ip_version: IP protocol version, ipv4 or ipv6. - :param entry_id: Numeric ID. - :type node: dict - :type data: dict - :type ip_version: str - :type entry_id: int - :returns: Content of response. - :rtype: bytearray - """ - - path = "/relay/vpp-fib-table-management:{0}/{1}".format(ip_version, - entry_id) - - return DHCPRelayKeywords._set_dhcp_relay_properties(node, path, data) - - @staticmethod - def clear_dhcp_relay_configuration(node): - """Remove all DHCP relay configuration from the node. - - :param node: Honeycomb node. - :type node: dict - :returns: Content of response. - :rtype: bytearray - """ - return DHCPRelayKeywords._set_dhcp_relay_properties(node, "") - - @staticmethod - 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 diff --git a/resources/libraries/python/honeycomb/FIB.py b/resources/libraries/python/honeycomb/FIB.py deleted file mode 100644 index bfccf5a029..0000000000 --- a/resources/libraries/python/honeycomb/FIB.py +++ /dev/null @@ -1,139 +0,0 @@ -# Copyright (c) 2018 Bell Canada, Pantheon Technologies 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""This module implements keywords to manipulate FIB tables using -Honeycomb REST API.""" - -from robot.api import logger - -from resources.libraries.python.HTTPRequest import HTTPCodes -from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError -from resources.libraries.python.honeycomb.HoneycombUtil \ - import DataRepresentation -from resources.libraries.python.honeycomb.HoneycombUtil \ - import HoneycombUtil as HcUtil - - -class FibKeywords(object): - """Implementation of keywords which make it possible to: - - add/remove FIB tables, - - add/remove FIB table entries - - get operational data about FIB tables, - """ - - def __init__(self): - pass - - @staticmethod - def _set_fib_table_properties(node, path, data=None): - """Set FIB 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 is not - 200 = OK. - """ - - if data: - status_code, resp = HcUtil. \ - put_honeycomb_data(node, "config_fib_table", data, path, - data_representation=DataRepresentation.JSON) - else: - status_code, resp = HcUtil. \ - delete_honeycomb_data(node, "config_fib_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 FIB table was not successful. " - "Status code: {0}.".format(status_code)) - return resp - - @staticmethod - def configure_fib_table(node, ip_version, vrf=1): - """Configure a FIB table according to the data provided. - - :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: Content of response. - :rtype: bytearray - """ - full_data = { - "vpp-fib-table-management:table": [ - { - "table-id": vrf, - "address-family": "vpp-fib-table-management:{0}" - .format(ip_version), - "name": "{0}-VRF:{1}".format(ip_version, vrf) - } - ] - } - path = "/table/{0}/vpp-fib-table-management:{1}".format(vrf, ip_version) - return FibKeywords._set_fib_table_properties(node, path, full_data) - - @staticmethod - def delete_fib_table(node, ip_version, vrf=1): - """Delete the specified FIB table from configuration data. - - :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: Content of response. - :rtype: bytearray - """ - - path = "/table/{0}/vpp-fib-table-management:{1}".format(vrf, ip_version) - return FibKeywords._set_fib_table_properties(node, path) - - @staticmethod - 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 diff --git a/resources/libraries/python/honeycomb/HcAPIKwACL.py b/resources/libraries/python/honeycomb/HcAPIKwACL.py deleted file mode 100644 index b2848411a1..0000000000 --- a/resources/libraries/python/honeycomb/HcAPIKwACL.py +++ /dev/null @@ -1,374 +0,0 @@ -# Copyright (c) 2019 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""This module implements keywords to manipulate ACL data structures using -Honeycomb REST API.""" - - -from robot.api import logger - -from resources.libraries.python.topology import Topology -from resources.libraries.python.HTTPRequest import HTTPCodes -from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError -from resources.libraries.python.honeycomb.HoneycombUtil \ - import HoneycombUtil as HcUtil -from resources.libraries.python.honeycomb.HoneycombUtil \ - import DataRepresentation - - -class ACLKeywords(object): - """Implementation of keywords which make it possible to: - - add classify table(s), - - remove classify table(s), - - get operational data about classify table(s), - - add classify session(s), - - remove classify session(s), - - get operational data about classify sessions(s). - """ - - def __init__(self): - pass - - @staticmethod - 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 - - @staticmethod - def add_classify_table(node, table): - """Add a classify table to the list of classify tables. The keyword does - not validate given data. - - :param node: Honeycomb node. - :param table: Classify table to be added. - :type node: dict - :type table: dict - :returns: Content of response. - :rtype: bytearray - """ - - path = "/classify-table/" + table["name"] - data = {"classify-table": [table, ]} - return ACLKeywords._set_classify_table_properties(node, path, data) - - @staticmethod - def remove_all_classify_tables(node): - """Remove all classify tables defined on the node. - - :param node: Honeycomb node. - :type node: dict - :returns: Content of response. - :rtype: bytearray - """ - - return ACLKeywords._set_classify_table_properties(node, path="") - - @staticmethod - def remove_classify_table(node, table_name): - """Remove the given classify table. - - :param node: Honeycomb node. - :param table_name: Name of the classify table to be removed. - :type node: dict - :type table_name: str - :returns: Content of response. - :rtype: bytearray - """ - - path = "/classify-table/" + table_name - return ACLKeywords._set_classify_table_properties(node, path) - - @staticmethod - 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"] - - @staticmethod - 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)) - - @staticmethod - def get_all_classify_tables_cfg_data(node): - """Get configuration 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, "config_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)) - try: - return resp["vpp-classifier"]["classify-table"] - except (KeyError, TypeError): - return [] - - @staticmethod - def add_classify_session(node, table_name, session): - """Add a classify session to the classify table. - - :param node: Honeycomb node. - :param table_name: Name of the classify table. - :param session: Classify session to be added to the classify table. - :type node: dict - :type table_name: str - :type session: dict - :returns: Content of response. - :rtype: bytearray - """ - - path = "/classify-table/" + table_name + \ - "/classify-session/" + session["match"] - data = {"classify-session": [session, ]} - return ACLKeywords._set_classify_table_properties(node, path, data) - - @staticmethod - def remove_classify_session(node, table_name, session_match): - """Remove the given classify session from the classify table. - - :param node: Honeycomb node. - :param table_name: Name of the classify table. - :param session_match: Classify session match. - :type node: dict - :type table_name: str - :type session_match: str - :returns: Content of response. - :rtype: bytearray - """ - - path = "/classify-table/" + table_name + \ - "/classify-session/" + session_match - return ACLKeywords._set_classify_table_properties(node, path) - - @staticmethod - def get_all_classify_sessions_oper_data(node, table_name): - """Get operational data about all classify sessions in the classify - table. - - :param node: Honeycomb node. - :param table_name: Name of the classify table. - :type node: dict - :type table_name: str - :returns: List of classify sessions present in the classify table. - :rtype: list - """ - - table_data = ACLKeywords.get_classify_table_oper_data(node, table_name) - - return table_data["classify-session"] - - @staticmethod - def get_classify_session_oper_data(node, table_name, session_match): - """Get operational data about the given classify session in the classify - table. - - :param node: Honeycomb node. - :param table_name: Name of the classify table. - :param session_match: Classify session match. - :type node: dict - :type table_name: str - :type session_match: str - :returns: Classify session operational data. - :rtype: dict - :raises HoneycombError: If no session the specified match Id is found. - """ - - sessions = ACLKeywords.get_all_classify_sessions_oper_data( - node, table_name) - for session in sessions: - if session["match"] == session_match: - return session - raise HoneycombError( - "Session with match value \"{0}\" not found" - " under ACL table {1}.".format(session_match, table_name)) - - @staticmethod - def create_acl_plugin_classify_chain(node, list_name, data): - """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. - :type node: dict - :type list_name: str - :type data: dict - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the operation fails. - """ - - path = "/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 - - @staticmethod - def set_acl_plugin_interface(node, interface, acl_name, direction): - """Assign an interface to an ietf-acl classify chain. - - :param node: Honeycomb node. - :param interface: Name of an interface on the node. - :param acl_name: Name of an ACL chain configured through ACL-plugin. - :param direction: Classify incoming or outgoing packets. - Valid options are: ingress, egress - :type node: dict - :type interface: str or int - :type acl_name: str - :type direction: str - :returns: Content of response. - :rtype: bytearray - :raises ValueError: If the direction argument is incorrect. - :raises HoneycombError: If the operation fails. - """ - - interface = Topology.convert_interface_reference( - node, interface, "name") - - interface = interface.replace("/", "%2F") - - if direction not in ("ingress", "egress"): - raise ValueError("Unknown traffic direction {0}. " - "Valid options are: ingress, egress." - .format(direction)) - - path = "/attachment-points/interface/{0}/{1}/acl-sets/".format( - interface, direction) - - data = { - "acl-sets": { - "acl-set": { - "name": acl_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 configure ACL on interface. " - "Status code: {0}.".format(status_code)) - - return resp - - @staticmethod - def delete_interface_plugin_acls(node, interface): - """Remove all plugin-acl assignments from an interface. - - :param node: Honeycomb node. - :param interface: Name of an interface on the node. - :type node: dict - :type interface: str or int - """ - - interface = Topology.convert_interface_reference( - node, interface, "name") - - interface = interface.replace("/", "%2F") - - path = "/attachment-points/interface/{0}/".format(interface) - status_code, _ = HcUtil.delete_honeycomb_data( - node, "config_plugin_acl", path) - - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Could not remove ACL assignment from interface. " - "Status code: {0}.".format(status_code)) - - @staticmethod - 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)) diff --git a/resources/libraries/python/honeycomb/HcAPIKwBridgeDomain.py b/resources/libraries/python/honeycomb/HcAPIKwBridgeDomain.py deleted file mode 100644 index 576124794c..0000000000 --- a/resources/libraries/python/honeycomb/HcAPIKwBridgeDomain.py +++ /dev/null @@ -1,482 +0,0 @@ -# Copyright (c) 2018 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Keywords to manipulate bridge domain configuration using Honeycomb REST API. - -The keywords make possible to put and get configuration data and to get -operational data. -""" - -from resources.libraries.python.HTTPRequest import HTTPCodes -from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError -from resources.libraries.python.honeycomb.HoneycombUtil \ - import DataRepresentation -from resources.libraries.python.honeycomb.HoneycombUtil \ - import HoneycombUtil as HcUtil - - -class BridgeDomainKeywords(object): - """Keywords to manipulate bridge domain configuration. - - Implements keywords which get configuration and operational data about - bridge domains and put the bridge domains' parameters using Honeycomb REST - API. - """ - - PARAMS = ("flood", "forward", "learn", "unknown-unicast-flood", - "arp-termination") - - def __init__(self): - pass - - @staticmethod - 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 - :returns: 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 - - @staticmethod - 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 - :returns: 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) - - @staticmethod - def _create_bd_structure(bd_name, **kwargs): - """Create the bridge domain data structure as it is expected by - Honeycomb REST API. - - :param bd_name: Bridge domain name. - :param kwargs: Parameters and their values. The accepted parameters are - defined in BridgeDomainKeywords.PARAMS. - :type bd_name: str - :type kwargs: dict - :returns: Bridge domain data structure. - :rtype: dict - """ - - bd_structure = {"name": bd_name} - - for param, value in kwargs.items(): - if param not in BridgeDomainKeywords.PARAMS: - raise HoneycombError("The parameter {0} is invalid.". - format(param)) - bd_structure[param] = str(value) - - return bd_structure - - @staticmethod - def get_all_bds_cfg_data(node): - """Get configuration data about all bridge domains from Honeycomb. - - :param node: Honeycomb node. - :type node: dict - :returns: Configuration data about all bridge domains from Honeycomb. - :rtype: list - :raises HoneycombError: If it is not possible to get configuration data. - """ - - 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)) - try: - return resp["bridge-domains"]["bridge-domain"] - - except (KeyError, TypeError): - return [] - - @staticmethod - def get_bd_cfg_data(node, bd_name): - """Get configuration data about the given bridge domain from Honeycomb. - - :param node: Honeycomb node. - :param bd_name: The name of bridge domain. - :type node: dict - :type bd_name: str - :returns: Configuration data about the given bridge domain from - Honeycomb. - :rtype: dict - """ - - intfs = BridgeDomainKeywords.get_all_bds_cfg_data(node) - for intf in intfs: - if intf["name"] == bd_name: - return intf - return {} - - @staticmethod - def get_all_bds_oper_data(node): - """Get operational data about all bridge domains from Honeycomb. - - :param node: Honeycomb node. - :type node: dict - :returns: Operational data about all bridge domains from Honeycomb. - :rtype: list - :raises HoneycombError: If it is not possible to get operational data. - """ - - status_code, resp = HcUtil.\ - get_honeycomb_data(node, "oper_bridge_domains") - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get operational information about the " - "bridge domains. Status code: {0}.".format(status_code)) - try: - return resp["bridge-domains-state"]["bridge-domain"] - - except (KeyError, TypeError): - return [] - - @staticmethod - def get_bd_oper_data(node, bd_name): - """Get operational data about the given bridge domain from Honeycomb. - - :param node: Honeycomb node. - :param bd_name: The name of bridge domain. - :type node: dict - :type bd_name: str - :returns: Operational data about the given bridge domain from Honeycomb. - :rtype: dict - """ - - intfs = BridgeDomainKeywords.get_all_bds_oper_data(node) - for intf in intfs: - if intf["name"] == bd_name: - return intf - return {} - - @staticmethod - def add_first_bd(node, bd_name, **kwargs): - """Add the first bridge domain. - - If there are any other bridge domains configured, they will be removed. - - :param node: Honeycomb node. - :param bd_name: Bridge domain name. - :param kwargs: Parameters and their values. The accepted parameters are - defined in BridgeDomainKeywords.PARAMS - :type node: dict - :type bd_name: str - :type kwargs: dict - :returns: Bridge domain data structure. - :rtype: dict - """ - - new_bd = BridgeDomainKeywords._create_bd_structure(bd_name, **kwargs) - bridge_domain = {"bridge-domains": {"bridge-domain": [new_bd, ]}} - return BridgeDomainKeywords._configure_bd(node, bd_name, bridge_domain) - - @staticmethod - def add_bd(node, bd_name, **kwargs): - """Add a bridge domain. - - :param node: Honeycomb node. - :param bd_name: Bridge domain name. - :param kwargs: Parameters and their values. The accepted parameters are - defined in BridgeDomainKeywords.PARAMS - :type node: dict - :type bd_name: str - :type kwargs: dict - :returns: Bridge domain data structure. - :rtype: dict - """ - - path = ("bridge-domains", "bridge-domain") - new_bd = BridgeDomainKeywords._create_bd_structure(bd_name, **kwargs) - bridge_domain = [new_bd, ] - return BridgeDomainKeywords._set_bd_properties(node, bd_name, path, - bridge_domain) - - @staticmethod - def remove_all_bridge_domains(node): - """Remove all bridge domains. - - :param node: Honeycomb node. - :type node: dict - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If it is not possible to remove all bridge - domains. - """ - - data = {"bridge-domains": {"bridge-domain": []}} - - status_code, resp = HcUtil.\ - put_honeycomb_data(node, "config_bridge_domain", data) - - if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): - raise HoneycombError("Not possible to remove all bridge domains. " - "Status code: {0}.".format(status_code)) - return resp - - @staticmethod - 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 - :returns: 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 - - @staticmethod - def configure_bridge_domain(node, bd_name, param, value): - """Configure a bridge domain. - - :param node: Honeycomb node. - :param bd_name: Bridge domain name. - :param param: Parameter to set, change or remove. The accepted - parameters are defined in BridgeDomainKeywords.PARAMS - :param value: The new value to be set, change or remove. If None, the - item will be removed. - :type node: dict - :type bd_name: str - :type param: str - :type value: str - :returns: Content of response. - :rtype: bytearray - """ - - if param not in BridgeDomainKeywords.PARAMS: - raise HoneycombError("The parameter {0} is invalid.".format(param)) - - path = ("bridge-domains", ("bridge-domain", "name", bd_name), param) - return BridgeDomainKeywords.\ - _set_bd_properties(node, bd_name, path, value) - - @staticmethod - def add_l2_fib_entry(node, bd_name, l2_fib_entry): - """Add an L2 FIB entry to the bridge domain's list of L2 FIB entries. - - :param node: Honeycomb node. - :param bd_name: Bridge domain's name. - :param l2_fib_entry: L2 FIB entry to be added to the L2 FIB table. - :type node: dict - :type bd_name: str - :type l2_fib_entry: dict - :returns: Content of response. - :rtype: bytearray - """ - - path = ("bridge-domains", - ("bridge-domain", "name", bd_name), - "l2-fib-table", - "l2-fib-entry") - - new_l2_fib_entry = [l2_fib_entry, ] - return BridgeDomainKeywords._set_bd_properties( - node, bd_name, path, new_l2_fib_entry) - - @staticmethod - def modify_l2_fib_entry(node, bd_name, mac, param, value): - """Modify an existing L2 FIB entry in the bridge domain's L2 FIB table. - The L2 FIB 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. - :param param: The parameter to be modified. - :param value: The new value of the parameter. - :type node: dict - :type bd_name: str - :type mac: str - :type param: str - :type value: str or int - :returns: Content of response. - :rtype: bytearray - """ - - path = ("bridge-domains", - ("bridge-domain", "name", bd_name), - "l2-fib-table", - ("l2-fib-entry", "phys-address", mac), - param) - - return BridgeDomainKeywords._set_bd_properties( - node, bd_name, path, value) - - @staticmethod - 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 - :returns: 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 - - - @staticmethod - def remove_all_l2_fib_entries(node, bd_name): - """Remove all entries from the bridge domain's L2 FIB table. - - :param node: Honeycomb node. - :param bd_name: Bridge domain's name. - :type node: dict - :type bd_name: str - :returns: Content of response. - :rtype: bytearray - """ - - path = ("bridge-domains", - ("bridge-domain", "name", bd_name), - "l2-fib-table") - - return BridgeDomainKeywords._set_bd_properties( - node, bd_name, path, None) - - @staticmethod - def get_all_l2_fib_entries(node, bd_name): - """Retrieves all entries from the bridge domain's L2 FIB table. - - :param node: Honeycomb node. - :param bd_name: Bridge domain's name. - :type node: dict - :type bd_name: str - :returns: Bridge domain's L2 FIB table or empty list if the table does - not exist or it is empty. - :rtype: list - """ - - bd_data = BridgeDomainKeywords.get_bd_oper_data(node, bd_name) - try: - return bd_data["l2-fib-table"]["l2-fib-entry"] - except KeyError: - return [] - - @staticmethod - def get_l2_fib_entry(node, bd_name, mac): - """Retrieves an 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 - :returns: The requested entry from bridge domain's L2 FIB table or empty - dictionary if it does not exist in the L2 FIB table. - :rtype: dict - """ - - l2_fib = BridgeDomainKeywords.get_all_l2_fib_entries(node, bd_name) - for entry in l2_fib: - if entry["phys-address"] == mac: - return entry - return {} diff --git a/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py b/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py deleted file mode 100644 index 662fedca10..0000000000 --- a/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py +++ /dev/null @@ -1,1908 +0,0 @@ -# Copyright (c) 2018 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Keywords to manipulate interface configuration using Honeycomb REST API. - -The keywords make possible to put and get configuration data and to get -operational data. -""" -from robot.api import logger - -from resources.libraries.python.HTTPRequest import HTTPCodes -from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError -from resources.libraries.python.honeycomb.HoneycombUtil \ - import DataRepresentation -from resources.libraries.python.honeycomb.HoneycombUtil \ - import HoneycombUtil as HcUtil -from resources.libraries.python.topology import Topology - - -class InterfaceKeywords(object): - """Keywords for Interface manipulation. - - Implements keywords which get configuration and operational data about - vpp interfaces and set the interface's parameters using Honeycomb REST API. - """ - - INTF_PARAMS = ("name", "description", "type", "enabled", - "link-up-down-trap-enable", "v3po:l2", "v3po:vxlan-gpe", - "vpp-vlan:sub-interfaces") - IPV4_PARAMS = ("enabled", "forwarding", "mtu") - IPV6_PARAMS = ("enabled", "forwarding", "mtu", "dup-addr-detect-transmits") - IPV6_AUTOCONF_PARAMS = ("create-global-addresses", - "create-temporary-addresses", - "temporary-valid-lifetime", - "temporary-preferred-lifetime") - ETH_PARAMS = ("mtu", ) - 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") - TAP_PARAMS = ("id", "tx-ring-size", "rx-ring-size", "host-mac", - "host-interface-name", "host-namespace", "host-bridge", - "host-ipv4-address", "host-ipv6-address", "tag", - "host-ipv4-gateway", "host-ipv6-gateway", "mac") - VHOST_USER_PARAMS = ("socket", "role") - SUB_IF_PARAMS = ("identifier", - "vlan-type", - "enabled") - SUB_IF_MATCH = ("default", - "untagged", - "vlan-tagged", - "vlan-tagged-exact-match") - BD_PARAMS = ("bridge-domain", - "split-horizon-group", - "bridged-virtual-interface") - VXLAN_GPE_PARAMS = ("local", - "remote", - "vni", - "next-protocol", - "encap-vrf-id", - "decap-vrf-id") - - def __init__(self): - pass - - @staticmethod - def _configure_interface(node, interface, data, - data_representation=DataRepresentation.JSON): - """Send interface configuration data and check the response. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param data: Configuration data to be sent in PUT request. - :param data_representation: How the data is represented. - :type node: dict - :type interface: str - :type data: dict - :type data_representation: DataRepresentation - :returns: 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_vpp_interfaces", data, - data_representation=data_representation) - 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 get_all_interfaces_cfg_data(node): - """Get configuration data about all interfaces from Honeycomb. - - :param node: Honeycomb node. - :type node: dict - :returns: Configuration data about all interfaces from Honeycomb. - :rtype: list - :raises HoneycombError: If it is not possible to get configuration data. - """ - - status_code, resp = HcUtil.\ - get_honeycomb_data(node, "config_vpp_interfaces") - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get configuration information about the " - "interfaces. Status code: {0}.".format(status_code)) - try: - return resp["interfaces"]["interface"] - - except (KeyError, TypeError): - return [] - - @staticmethod - def get_interface_cfg_data(node, interface): - """Get configuration data about the given interface from Honeycomb. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :returns: Configuration data about the given interface from Honeycomb. - :rtype: dict - """ - - intfs = InterfaceKeywords.get_all_interfaces_cfg_data(node) - for intf in intfs: - if intf["name"] == interface: - return intf - return {} - - @staticmethod - def get_all_interfaces_oper_data(node): - """Get operational data about all interfaces from Honeycomb. - - :param node: Honeycomb node. - :type node: dict - :returns: Operational data about all interfaces from Honeycomb. - :rtype: list - :raises HoneycombError: If it is not possible to get operational data. - """ - - status_code, resp = HcUtil.\ - get_honeycomb_data(node, "oper_vpp_interfaces") - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get operational information about the " - "interfaces. Status code: {0}.".format(status_code)) - try: - return resp["interfaces"]["interface"] - - except (KeyError, TypeError): - return [] - - @staticmethod - def get_disabled_interfaces_oper_data(node): - """Get operational data about all disabled interfaces from Honeycomb. - - :param node: Honeycomb node. - :type node: dict - :returns: Operational data about disabled interfaces. - :rtype: list - :raises HoneycombError: If it is not possible to get operational data. - """ - - status_code, resp = HcUtil. \ - get_honeycomb_data(node, "oper_disabled_interfaces") - if status_code == HTTPCodes.NOT_FOUND: - raise HoneycombError( - "No disabled interfaces present on node." - ) - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get operational information about the " - "interfaces. Status code: {0}.".format(status_code)) - try: - return resp["disabled-interfaces"]["disabled-interface-index"] - - except (KeyError, TypeError): - return [] - - @staticmethod - def get_interface_oper_data(node, interface): - """Get operational data about the given interface from Honeycomb. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :returns: Operational data about the given interface from Honeycomb. - :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: - return intf - return {} - - @staticmethod - def _set_interface_properties(node, interface, path, new_value=None): - """Set interface properties. - - This method reads interface configuration data, creates, changes or - removes the requested data and puts it back to Honeycomb. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param path: Path to data we want to change / create / remove. - :param new_value: The new value to be set. If None, the item will be - removed. - :type node: dict - :type interface: str - :type path: tuple - :type new_value: str, dict or list - :returns: 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_vpp_interfaces") - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get configuration information about the " - "interfaces. 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 InterfaceKeywords._configure_interface(node, interface, new_data) - - @staticmethod - def honeycomb_set_interface_state(node, interface, state="up"): - """Set VPP interface state. - - The keyword changes the administration state of interface to up or down - depending on the parameter "state". - - :param node: Honeycomb node. - :param interface: Interface name, key, link name or sw_if_index. - :param state: The requested state, only "up" and "down" are valid - values. - :type node: dict - :type interface: str - :type state: str - :returns: Content of response. - :rtype: bytearray - :raises KeyError: If the argument "state" is nor "up" or "down". - :raises HoneycombError: If the interface is not present on the node. - """ - - intf_state = {"up": "true", - "down": "false"} - - interface = Topology.convert_interface_reference( - node, interface, "name") - - intf = interface.replace("/", "%2F") - path = "/interface/{0}".format(intf) - - status_code, resp = HcUtil.\ - get_honeycomb_data(node, "config_vpp_interfaces", path) - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get configuration information about the " - "interfaces. Status code: {0}.".format(status_code)) - - resp["interface"][0]["enabled"] = intf_state[state.lower()] - - status_code, resp = HcUtil. \ - put_honeycomb_data(node, "config_vpp_interfaces", resp, 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 set_interface_up(node, interface): - """Set the administration state of VPP interface to up. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :returns: Content of response - :rtype: bytearray - """ - - return InterfaceKeywords.honeycomb_set_interface_state( - node, interface, "up") - - @staticmethod - def set_interface_down(node, interface): - """Set the administration state of VPP interface to down. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :returns: Content of response. - :rtype: bytearray - """ - - return InterfaceKeywords.honeycomb_set_interface_state( - node, interface, "down") - - @staticmethod - def add_bridge_domain_to_interface(node, interface, bd_name, - split_horizon_group=None, bvi=None): - """Add a new bridge domain to an interface and set its parameters. - - :param node: Honeycomb node. - :param interface: Interface name, key, link name or sw_if_index. - :param bd_name: Bridge domain name. - :param split_horizon_group: Split-horizon group name. - :param bvi: The bridged virtual interface. - :type node: dict - :type interface: str - :type bd_name: str - :type split_horizon_group: str - :type bvi: str - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the interface is not present on the node. - """ - - interface = Topology.convert_interface_reference( - node, interface, "name") - - v3po_l2 = {"bridge-domain": str(bd_name)} - if split_horizon_group: - v3po_l2["split-horizon-group"] = str(split_horizon_group) - if bvi: - v3po_l2["bridged-virtual-interface"] = str(bvi) - - path = ("interfaces", ("interface", "name", str(interface)), "v3po:l2") - - return InterfaceKeywords._set_interface_properties( - node, interface, path, v3po_l2) - - @staticmethod - def remove_bridge_domain_from_interface(node, interface): - """Remove bridge domain assignment from interface. - - :param node: Honeycomb node. - :param interface: Interface name, key, link name or sw_if_index. - :type node: dict - :type interface: str or int - :raises HoneycombError: If the operation fails. - """ - - interface = Topology.convert_interface_reference( - node, interface, "name") - - intf = interface.replace("/", "%2F") - - path = "/interface/{0}/v3po:l2".format(intf) - - status_code, response = HcUtil.delete_honeycomb_data( - node, "config_vpp_interfaces", path) - - if status_code != HTTPCodes.OK: - if '"error-tag":"data-missing"' in response: - logger.debug("Data does not exist in path.") - else: - raise HoneycombError( - "Could not remove bridge domain assignment from interface " - "'{0}'. Status code: {1}.".format(interface, status_code)) - - @staticmethod - def get_bd_oper_data_from_interface(node, interface): - """Returns operational data about bridge domain settings in the - interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :returns: Operational data about bridge domain settings in the - interface. - :rtype: dict - """ - - if_data = InterfaceKeywords.get_interface_oper_data(node, interface) - - if if_data: - try: - return if_data["v3po:l2"] - except KeyError: - return {} - return {} - - @staticmethod - def configure_interface_base(node, interface, param, value): - """Configure the base parameters of interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param param: Parameter to configure (set, change, remove) - :param value: The value of parameter. If None, the parameter will be - removed. - :type node: dict - :type interface: str - :type param: str - :type value: str - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - if param not in InterfaceKeywords.INTF_PARAMS: - raise HoneycombError("The parameter {0} is invalid.".format(param)) - - path = ("interfaces", ("interface", "name", interface), param) - return InterfaceKeywords._set_interface_properties( - node, interface, path, value) - - @staticmethod - def configure_interface_ipv4(node, interface, param, value): - """Configure IPv4 parameters of interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param param: Parameter to configure (set, change, remove) - :param value: The value of parameter. If None, the parameter will be - removed. - :type node: dict - :type interface: str - :type param: str - :type value: str - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - interface = Topology.convert_interface_reference( - node, interface, "name") - - if param not in InterfaceKeywords.IPV4_PARAMS: - raise HoneycombError("The parameter {0} is invalid.".format(param)) - - path = ("interfaces", ("interface", "name", interface), - "ietf-ip:ipv4", param) - return InterfaceKeywords._set_interface_properties( - node, interface, path, value) - - @staticmethod - def add_first_ipv4_address(node, interface, ip_addr, network): - """Add the first IPv4 address. - - If there are any other addresses configured, they will be removed. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param ip_addr: IPv4 address to be set. - :param network: Netmask or length of network prefix. - :type node: dict - :type interface: str - :type ip_addr: str - :type network: str or int - :returns: Content of response. - :rtype: bytearray - :raises ValueError: If the provided netmask or prefix is not valid. - :raises HoneycombError: If the operation fails. - """ - - interface = InterfaceKeywords.handle_interface_reference( - node, interface) - - path = "/interface/{0}/ietf-ip:ipv4".format(interface) - if isinstance(network, basestring): - data = { - "ietf-ip:ipv4": { - "address": [{"ip": ip_addr, "netmask": network}, ]}} - elif isinstance(network, int) and (0 < network < 33): - data = { - "ietf-ip:ipv4": { - "address": [{"ip": ip_addr, "prefix-length": network}, ]}} - else: - raise ValueError("Value {0} is not a valid netmask or network " - "prefix length.".format(network)) - status_code, _ = HcUtil.put_honeycomb_data( - node, "config_vpp_interfaces", data, path) - - if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): - raise HoneycombError( - "Configuring IPv4 address failed. " - "Status code:{0}".format(status_code)) - - @staticmethod - def add_ipv4_address(node, interface, ip_addr, network): - """Add IPv4 address. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param ip_addr: IPv4 address to be set. - :param network: Netmask or length of network prefix. - :type node: dict - :type interface: str - :type ip_addr: str - :type network: str or int - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the provided netmask or prefix is not valid. - """ - - interface = Topology.convert_interface_reference( - node, interface, "name") - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4", - "address") - if isinstance(network, basestring): - address = [{"ip": ip_addr, "netmask": network}] - elif isinstance(network, int) and (0 < network < 33): - address = [{"ip": ip_addr, "prefix-length": network}] - else: - raise HoneycombError("Value {0} is not a valid netmask or network " - "prefix length.".format(network)) - return InterfaceKeywords._set_interface_properties( - node, interface, path, address) - - @staticmethod - def remove_all_ipv4_addresses(node, interface): - """Remove all IPv4 addresses from interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :returns: Content of response. - :rtype: bytearray - """ - - interface = Topology.convert_interface_reference( - node, interface, "name") - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4", - "address") - return InterfaceKeywords._set_interface_properties( - node, interface, path, None) - - @staticmethod - def add_ipv4_neighbor(node, interface, ip_addr, link_layer_address): - """Add the IPv4 neighbour. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param ip_addr: IPv4 address of neighbour to be set. - :param link_layer_address: Link layer address. - :type node: dict - :type interface: str - :type ip_addr: str - :type link_layer_address: str - :returns: Content of response. - :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}, ] - return InterfaceKeywords._set_interface_properties( - node, interface, path, neighbor) - - @staticmethod - def remove_all_ipv4_neighbors(node, interface): - """Remove all IPv4 neighbours. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :returns: Content of response. - :rtype: bytearray - """ - - interface = Topology.convert_interface_reference( - node, interface, "name") - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv4", - "neighbor") - return InterfaceKeywords._set_interface_properties( - node, interface, path, None) - - @staticmethod - def configure_interface_ipv6(node, interface, param, value): - """Configure IPv6 parameters of interface - - :param node: Honeycomb node. - :param interface: The name of interface. - :param param: Parameter to configure (set, change, remove) - :param value: The value of parameter. If None, the parameter will be - removed. - :type node: dict - :type interface: str - :type param: str - :type value: str - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - if param in InterfaceKeywords.IPV6_PARAMS: - path = ("interfaces", ("interface", "name", interface), - "ietf-ip:ipv6", param) - elif param in InterfaceKeywords.IPV6_AUTOCONF_PARAMS: - path = ("interfaces", ("interface", "name", interface), - "ietf-ip:ipv6", "autoconf", param) - else: - raise HoneycombError("The parameter {0} is invalid.".format(param)) - - return InterfaceKeywords._set_interface_properties( - node, interface, path, value) - - @staticmethod - def add_first_ipv6_address(node, interface, ip_addr, prefix_len): - """Add the first IPv6 address. - - If there are any other addresses configured, they will be removed. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param ip_addr: IPv6 address to be set. - :param prefix_len: Prefix length. - :type node: dict - :type interface: str - :type ip_addr: str - :type prefix_len: str - :returns: Content of response. - :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( - node, interface, path, address) - - @staticmethod - def add_ipv6_address(node, interface, ip_addr, prefix_len): - """Add IPv6 address. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param ip_addr: IPv6 address to be set. - :param prefix_len: Prefix length. - :type node: dict - :type interface: str - :type ip_addr: str - :type prefix_len: str - :returns: Content of response. - :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( - node, interface, path, address) - - @staticmethod - def remove_all_ipv6_addresses(node, interface): - """Remove all IPv6 addresses from interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :returns: Content of response. - :rtype: bytearray - """ - - interface = Topology.convert_interface_reference( - node, interface, "name") - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6", - "address") - return InterfaceKeywords._set_interface_properties( - node, interface, path, None) - - @staticmethod - def add_ipv6_neighbor(node, interface, ip_addr, link_layer_address): - """Add the IPv6 neighbour. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param ip_addr: IPv6 address of neighbour to be set. - :param link_layer_address: Link layer address. - :type node: dict - :type interface: str - :type ip_addr: str - :type link_layer_address: str - :returns: Content of response. - :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}, ] - return InterfaceKeywords._set_interface_properties( - node, interface, path, neighbor) - - @staticmethod - def remove_all_ipv6_neighbors(node, interface): - """Remove all IPv6 neighbours. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :returns: Content of response. - :rtype: bytearray - """ - - interface = Topology.convert_interface_reference( - node, interface, "name") - - path = ("interfaces", ("interface", "name", interface), "ietf-ip:ipv6", - "neighbor") - return InterfaceKeywords._set_interface_properties( - node, interface, path, None) - - @staticmethod - def configure_interface_ethernet(node, interface, param, value): - """Configure the ethernet parameters of interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param param: Parameter to configure (set, change, remove) - :param value: The value of parameter. If None, the parameter will be - removed. - :type node: dict - :type interface: str - :type param: str - :type value: str - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - if param not in InterfaceKeywords.ETH_PARAMS: - raise HoneycombError("The parameter {0} is invalid.".format(param)) - path = ("interfaces", ("interface", "name", interface), "v3po:ethernet", - param) - return InterfaceKeywords._set_interface_properties( - node, interface, path, value) - - @staticmethod - def configure_interface_routing(node, interface, param, value): - """Configure the routing parameters of interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param param: Parameter to configure (set, change, remove) - :param value: The value of parameter. If None, the parameter will be - removed. - :type node: dict - :type interface: str - :type param: str - :type value: str - :returns: Content of response. - :rtype: bytearray - :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)) - - path = ("interfaces", ("interface", "name", interface), "v3po:routing", - param) - return InterfaceKeywords._set_interface_properties( - node, interface, path, value) - - @staticmethod - def honeycomb_create_vxlan_interface(node, interface, **kwargs): - """Create a new VxLAN interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param kwargs: Parameters and their values. The accepted parameters are - defined in InterfaceKeywords.VXLAN_PARAMS. - :type node: dict - :type interface: str - :type kwargs: dict - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - new_vx_lan = { - "name": interface, - "type": "v3po:vxlan-tunnel", - "v3po:vxlan": {} - } - for param, value in kwargs.items(): - if param not in InterfaceKeywords.VXLAN_PARAMS: - raise HoneycombError("The parameter {0} is invalid.". - format(param)) - new_vx_lan["v3po:vxlan"][param] = value - - path = ("interfaces", "interface") - vx_lan_structure = [new_vx_lan, ] - return InterfaceKeywords._set_interface_properties( - node, interface, path, vx_lan_structure) - - @staticmethod - def delete_interface(node, interface): - """Delete an interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :type node: dict - :type interface: str - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If it is not possible to get information about - interfaces or it is not possible to delete the interface. - """ - - path = ("interfaces", ("interface", "name", interface)) - - status_code, resp = HcUtil.\ - get_honeycomb_data(node, "config_vpp_interfaces") - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get configuration information about the " - "interfaces. Status code: {0}.".format(status_code)) - - new_data = HcUtil.remove_item(resp, path) - status_code, resp = HcUtil.\ - put_honeycomb_data(node, "config_vpp_interfaces", new_data) - if status_code != HTTPCodes.OK: - raise HoneycombError("Not possible to remove interface {0}. " - "Status code: {1}.". - format(interface, status_code)) - return resp - - @staticmethod - def honeycomb_configure_interface_vxlan(node, interface, **kwargs): - """Configure VxLAN on the interface. - - The keyword configures VxLAN parameters on the given interface. The type - of interface must be set to "v3po:vxlan-tunnel". - The new VxLAN parameters overwrite the current configuration. If a - parameter in new configuration is missing, it is removed from VxLAN - configuration. - If the dictionary kwargs is empty, VxLAN configuration is removed. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param kwargs: Parameters and their values. The accepted parameters are - defined in InterfaceKeywords.VXLAN_PARAMS. - :type node: dict - :type interface: str - :type kwargs: dict - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - vx_lan_structure = dict() - for param, value in kwargs.items(): - if param not in InterfaceKeywords.VXLAN_PARAMS: - raise HoneycombError("The parameter {0} is invalid.". - format(param)) - vx_lan_structure[param] = value - - path = ("interfaces", ("interface", "name", interface), "v3po:vxlan") - return InterfaceKeywords._set_interface_properties( - node, interface, path, vx_lan_structure) - - @staticmethod - def configure_interface_l2(node, interface, param, value): - """Configure the L2 parameters of interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param param: Parameter to configure (set, change, remove) - :param value: The value of parameter. If None, the parameter will be - removed. - :type node: dict - :type interface: str - :type param: str - :type value: str - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - if param not in InterfaceKeywords.L2_PARAMS: - raise HoneycombError("The parameter {0} is invalid.".format(param)) - path = ("interfaces", ("interface", "name", interface), "v3po:l2", - param) - return InterfaceKeywords._set_interface_properties( - node, interface, path, value) - - @staticmethod - def create_tap_interface(node, interface, **kwargs): - """Create a new TAP interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param kwargs: Parameters and their values. The accepted parameters are - defined in InterfaceKeywords.TAP_PARAMS. - :type node: dict - :type interface: str - :type kwargs: dict - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - new_tap = { - "name": interface, - "type": "v3po:tap-v2", - "v3po:tap-v2": {} - } - for param, value in kwargs.items(): - if param not in InterfaceKeywords.TAP_PARAMS: - raise HoneycombError( - "The parameter {0} is invalid.".format(param)) - new_tap["v3po:tap-v2"][param] = value - - path = ("interfaces", "interface") - new_tap_structure = [new_tap, ] - return InterfaceKeywords._set_interface_properties( - node, interface, path, new_tap_structure) - - @staticmethod - def configure_interface_tap(node, interface, **kwargs): - """Configure TAP on the interface. - - The keyword configures TAP parameters on the given interface. The type - of interface must be set to "v3po:tap-v2". - The new TAP parameters overwrite the current configuration. If a - parameter in new configuration is missing, it is removed from TAP - configuration. - If the dictionary kwargs is empty, TAP configuration is removed. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param kwargs: Parameters and their values. The accepted parameters are - defined in InterfaceKeywords.TAP_PARAMS. - :type node: dict - :type interface: str - :type kwargs: dict - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - tap_structure = dict() - for param, value in kwargs.items(): - if param not in InterfaceKeywords.TAP_PARAMS: - raise HoneycombError("The parameter {0} is invalid.". - format(param)) - tap_structure[param] = value - - path = ("interfaces", ("interface", "name", interface), "v3po:tap-v2") - return InterfaceKeywords._set_interface_properties( - node, interface, path, tap_structure) - - @staticmethod - def configure_interface_vhost_user(node, interface, **kwargs): - """Configure vhost-user on the interface. - - The keyword configures vhost-user parameters on the given interface. - The type of interface must be set to "v3po:vhost-user". - The new vhost-user parameters overwrite the current configuration. If a - parameter in new configuration is missing, it is removed from vhost-user - configuration. - If the dictionary kwargs is empty, vhost-user configuration is removed. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param kwargs: Parameters and their values. The accepted parameters are - defined in InterfaceKeywords.VHOST_USER_PARAMS. - :type node: dict - :type interface: str - :type kwargs: dict - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - vhost_structure = dict() - for param, value in kwargs.items(): - if param not in InterfaceKeywords.VHOST_USER_PARAMS: - raise HoneycombError("The parameter {0} is invalid.". - format(param)) - vhost_structure[param] = value - - path = ("interfaces", ("interface", "name", interface), - "v3po:vhost-user") - return InterfaceKeywords._set_interface_properties( - node, interface, path, vhost_structure) - - @staticmethod - def create_vhost_user_interface(node, interface, **kwargs): - """Create a new vhost-user interface. - - :param node: Honeycomb node. - :param interface: The name of interface. - :param kwargs: Parameters and their values. The accepted parameters are - defined in InterfaceKeywords.VHOST_USER_PARAMS. - :type node: dict - :type interface: str - :type kwargs: dict - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - """ - - new_vhost = { - "name": interface, - "type": "v3po:vhost-user", - "v3po:vhost-user": {} - } - for param, value in kwargs.items(): - if param not in InterfaceKeywords.VHOST_USER_PARAMS: - raise HoneycombError("The parameter {0} is invalid.". - format(param)) - new_vhost["v3po:vhost-user"][param] = value - - path = ("interfaces", "interface") - new_vhost_structure = [new_vhost, ] - return InterfaceKeywords._set_interface_properties( - node, interface, path, new_vhost_structure) - - @staticmethod - def honeycomb_create_sub_interface(node, super_interface, match, tags=None, - **kwargs): - """Create a new sub-interface. - - :param node: Honeycomb node. - :param super_interface: Super interface. - :param match: Match type. The valid values are defined in - InterfaceKeywords.SUB_IF_MATCH. - :param tags: List of tags. - :param kwargs: Parameters and their values. The accepted parameters are - defined in InterfaceKeywords.SUB_IF_PARAMS. - :type node: dict - :type super_interface: str - :type match: str - :type tags: list - :type kwargs: dict - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the parameter is not valid. - :raises KeyError: If the parameter 'match' is invalid. - """ - - super_interface = Topology.convert_interface_reference( - node, super_interface, "name") - - match_type = { - "default": - {"default": {}}, - "untagged": - {"untagged": {}}, - "vlan-tagged": - {"vlan-tagged": {"match-exact-tags": "false"}}, - "vlan-tagged-exact-match": - {"vlan-tagged": {"match-exact-tags": "true"}} - } - - new_sub_interface = { - "tags": { - "tag": [] - }, - } - - for param, value in kwargs.items(): - if param in InterfaceKeywords.SUB_IF_PARAMS: - new_sub_interface[param] = value - else: - raise HoneycombError("The parameter {0} is invalid.". - format(param)) - try: - new_sub_interface["match"] = match_type[match] - except KeyError: - raise HoneycombError("The value '{0}' of parameter 'match' is " - "invalid.".format(match)) - - if tags: - new_sub_interface["tags"]["tag"].extend(tags) - - path = ("interfaces", - ("interface", "name", super_interface), - "vpp-vlan:sub-interfaces", - "sub-interface") - new_sub_interface_structure = [new_sub_interface, ] - return InterfaceKeywords._set_interface_properties( - node, super_interface, path, new_sub_interface_structure) - - @staticmethod - def get_sub_interface_oper_data(node, super_interface, identifier): - """Retrieves sub-interface operational data using Honeycomb API. - - :param node: Honeycomb node. - :param super_interface: Super interface. - :param identifier: The ID of sub-interface. - :type node: dict - :type super_interface: str - :type identifier: int - :returns: Sub-interface operational data. - :rtype: dict - :raises HoneycombError: If there is no sub-interface with the given ID. - """ - - if_data = InterfaceKeywords.get_interface_oper_data(node, - super_interface) - for sub_if in if_data["vpp-vlan:sub-interfaces"]["sub-interface"]: - if str(sub_if["identifier"]) == str(identifier): - return sub_if - - raise HoneycombError("The interface {0} does not have sub-interface " - "with ID {1}".format(super_interface, identifier)) - - @staticmethod - def remove_all_sub_interfaces(node, super_interface): - """Remove all sub-interfaces from the given interface. - - :param node: Honeycomb node. - :param super_interface: Super interface. - :type node: dict - :type super_interface: str - :returns: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", - ("interface", "name", super_interface), - "vpp-vlan:sub-interfaces") - - return InterfaceKeywords._set_interface_properties( - node, super_interface, path, {}) - - @staticmethod - def set_sub_interface_state(node, super_interface, identifier, state): - """Set the administrative state of sub-interface. - - :param node: Honeycomb node. - :param super_interface: Super interface. - :param identifier: The ID of sub-interface. - :param state: Required sub-interface state - up or down. - :type node: dict - :type super_interface: str - :type identifier: int - :type state: str - :returns: Content of response. - :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", int(identifier)), - "enabled") - - return InterfaceKeywords._set_interface_properties( - node, super_interface, path, intf_state[state]) - - @staticmethod - def add_bridge_domain_to_sub_interface(node, super_interface, identifier, - config): - """Add a sub-interface to a bridge domain and set its parameters. - - :param node: Honeycomb node. - :param super_interface: Super interface. - :param identifier: The ID of sub-interface. - :param config: Bridge domain configuration. - :type node: dict - :type super_interface: str - :type identifier: int - :type config: dict - :returns: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", - ("interface", "name", super_interface), - "vpp-vlan:sub-interfaces", - ("sub-interface", "identifier", int(identifier)), - "l2") - - return InterfaceKeywords._set_interface_properties( - node, super_interface, path, config) - - @staticmethod - def get_bd_data_from_sub_interface(node, super_interface, identifier): - """Get the operational data about the bridge domain from sub-interface. - - :param node: Honeycomb node. - :param super_interface: Super interface. - :param identifier: The ID of sub-interface. - :type node: dict - :type super_interface: str - :type identifier: int - :returns: Operational data about the bridge domain. - :rtype: dict - :raises HoneycombError: If there is no sub-interface with the given ID. - """ - - try: - bd_data = InterfaceKeywords.get_sub_interface_oper_data( - node, super_interface, identifier)["l2"] - return bd_data - except KeyError: - raise HoneycombError("The operational data does not contain " - "information about a bridge domain.") - - @staticmethod - def configure_tag_rewrite(node, super_interface, identifier, config): - """Add / change / disable vlan tag rewrite on a sub-interface. - - :param node: Honeycomb node. - :param super_interface: Super interface. - :param identifier: The ID of sub-interface. - :param config: Rewrite tag configuration. - :type node: dict - :type super_interface: str - :type identifier: int - :type config: dict - :returns: Content of response. - :rtype: bytearray - """ - - path = ("interfaces", - ("interface", "name", super_interface), - "vpp-vlan:sub-interfaces", - ("sub-interface", "identifier", int(identifier)), - "l2", - "rewrite") - - return InterfaceKeywords._set_interface_properties( - node, super_interface, path, config) - - @staticmethod - def get_tag_rewrite_oper_data(node, super_interface, identifier): - """Get the operational data about tag rewrite. - - :param node: Honeycomb node. - :param super_interface: Super interface. - :param identifier: The ID of sub-interface. - :type node: dict - :type super_interface: str - :type identifier: int - :returns: Operational data about tag rewrite. - :rtype: dict - :raises HoneycombError: If there is no sub-interface with the given ID. - """ - - try: - tag_rewrite = InterfaceKeywords.get_sub_interface_oper_data( - node, super_interface, identifier)["l2"]["rewrite"] - return tag_rewrite - except KeyError: - raise HoneycombError("The operational data does not contain " - "information about the tag-rewrite.") - - @staticmethod - 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. - - :param node: Honeycomb node. - :param super_interface: Super interface. - :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. - """ - - path = ("interfaces", - ("interface", "name", super_interface), - "vpp-vlan:sub-interfaces", - ("sub-interface", "identifier", int(identifier)), - ip_version.lower()) - - if isinstance(network, basestring) and ip_version.lower() == "ipv4": - address = {"address": [{"ip": ip_addr, "netmask": network}, ]} - - elif isinstance(network, int) and 0 < network < 33: - address = {"address": [{"ip": ip_addr, "prefix-length": network}, ]} - - else: - raise HoneycombError("{0} is not a valid netmask or prefix length." - .format(network)) - - return InterfaceKeywords._set_interface_properties( - node, super_interface, path, address) - - @staticmethod - 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 - """ - - path = ("interfaces", - ("interface", "name", super_interface), - "vpp-vlan:sub-interfaces", - ("sub-interface", "identifier", int(identifier)), - str(ip_version), "address") - - return InterfaceKeywords._set_interface_properties( - node, super_interface, path, None) - - @staticmethod - 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 _path: Used in recursive calls, stores the path taken down - the JSON tree. - :type data: dict - :type ref: dict - :type _path: str - - :raises HoneycombError: If the data structures do not match in some way, - or if they are not in deserialized JSON format. - """ - - 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: - 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)) - - 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): - """Compare provided lists of interfaces by name. - - :param list1: List of interfaces. - :param list2: List of interfaces. - :type list1: list - :type list2: list - :raises HoneycombError: If an interface exists in only one of the lists. - """ - - ignore = ["vx_tunnel0", "vxlan_gpe_tunnel0"] - # these have no equivalent in config data and no effect on VPP - - names1 = [x['name'] for x in list1] - names2 = [x['name'] for x in list2] - - for name in names1: - if name not in names2 and name not in ignore: - raise HoneycombError("Interface {0} not present in list {1}" - .format(name, list2)) - for name in names2: - if name not in names1 and name not in ignore: - raise HoneycombError("Interface {0} not present in list {1}" - .format(name, list1)) - - @staticmethod - def create_vxlan_gpe_interface(node, interface, **kwargs): - """Create a new VxLAN GPE interface. - - :param node: Honeycomb node. - :param interface: The name of interface to be created. - :param kwargs: Parameters and their values. The accepted parameters are - defined in InterfaceKeywords.VXLAN_GPE_PARAMS. - :type node: dict - :type interface: str - :type kwargs: dict - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If a parameter in kwargs is not valid. - """ - - new_vxlan_gpe = { - "name": interface, - "type": "v3po:vxlan-gpe-tunnel", - "v3po:vxlan-gpe": {} - } - for param, value in kwargs.items(): - if param in InterfaceKeywords.INTF_PARAMS: - new_vxlan_gpe[param] = value - elif param in InterfaceKeywords.VXLAN_GPE_PARAMS: - new_vxlan_gpe["v3po:vxlan-gpe"][param] = value - else: - raise HoneycombError("The parameter {0} is invalid.". - format(param)) - path = ("interfaces", "interface") - vxlan_gpe_structure = [new_vxlan_gpe, ] - return InterfaceKeywords._set_interface_properties( - node, interface, path, vxlan_gpe_structure) - - @staticmethod - def enable_acl_on_interface(node, interface, table_name): - """Enable ACL on the given interface. - - :param node: Honeycomb node. - :param interface: The interface where the ACL 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 = interface.replace("/", "%2F") - - data = { - "vpp-interface-acl:acl": { - "ingress": { - "ip4-acl": { - "classify-table": table_name - }, - "l2-acl": { - "classify-table": table_name - } - } - } - } - - 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) - 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 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. - :type node: dict - :type interface: 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. - - :param node: Honeycomb node. - :param interface: The interface where the ACL will be disabled. - :type node: dict - :type interface: str - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the configuration of interface is not - successful. - """ - - interface = interface.replace("/", "%2F") - - path = "/interface/" + interface + "/vpp-interface-acl:acl" - - 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 create_pbb_sub_interface(node, intf, params): - """Creates a PBB sub-interface on the given interface and sets its - parameters. - - :param node: Honeycomb node. - :param intf: The interface where PBB sub-interface will be configured. - :param params: Configuration parameters of the sub-interface to be - created. - :type node: dict - :type intf: str - :type params: dict - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the configuration of sub-interface is not - successful. - """ - - interface = intf.replace("/", "%2F") - path = "/interface/{0}/pbb-rewrite".format(interface) - status_code, resp = HcUtil. \ - put_honeycomb_data(node, "config_vpp_interfaces", params, path, - data_representation=DataRepresentation.JSON) - if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): - raise HoneycombError( - "The configuration of PBB sub-interface '{0}' was not " - "successful. Status code: {1}.".format(intf, status_code)) - return resp - - @staticmethod - def delete_pbb_sub_interface(node, intf): - """Deletes the given PBB sub-interface. - - :param node: Honeycomb node. - :param intf: The interface where PBB sub-interface will be deleted. - :type node: dict - :type intf: str - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the removal of sub-interface is not - successful. - """ - - interface = intf.replace("/", "%2F") - path = "/interface/{0}/pbb-rewrite".format(interface) - - status_code, resp = HcUtil. \ - delete_honeycomb_data(node, "config_vpp_interfaces", path) - if status_code != HTTPCodes.OK: - raise HoneycombError( - "The removal of pbb sub-interface '{0}' was not successful. " - "Status code: {1}.".format(intf, status_code)) - return resp - - @staticmethod - def get_pbb_sub_interface_oper_data(node, intf, sub_if_id): - """Retrieves PBB sub-interface operational data from Honeycomb. - - :param node: Honeycomb node. - :param intf: The interface where PBB sub-interface is located. - :param sub_if_id: ID of the PBB sub-interface. - :type node: dict - :type intf: str - :type sub_if_id: str or int - :returns: PBB sub-interface operational data. - :rtype: dict - :raises HoneycombError: If the removal of sub-interface is not - successful. - """ - - raise NotImplementedError - - @staticmethod - def check_disabled_interface(node, interface): - """Retrieves list of disabled interface indices from Honeycomb, - and matches with the provided interface by index. - - :param node: Honeycomb node. - :param interface: Index number of an interface on the node. - :type node: dict - :type interface: int - :returns: True if the interface exists in disabled interfaces. - :rtype: bool - :raises HoneycombError: If the interface is not present - in retrieved list of disabled interfaces. - """ - data = InterfaceKeywords.get_disabled_interfaces_oper_data(node) - # decrement by one = conversion from HC if-index to VPP sw_if_index - interface -= 1 - - for item in data: - if item["index"] == interface: - return True - raise HoneycombError("Interface index {0} not present in list" - " of disabled interfaces.".format(interface)) - - @staticmethod - 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. - - :param node: Honeycomb node. - :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 or int - :type src_interfaces: list of dict - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If SPAN could not be configured. - """ - - 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 - } - } - } - - 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) - - if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): - raise HoneycombError( - "Configuring SPAN failed. Status code:{0}".format(status_code)) - - @staticmethod - def add_interface_local0_to_topology(node): - """Use Topology methods to add interface "local0" to working topology, - if not already present. - - :param node: DUT node. - :type node: dict - """ - - if Topology.get_interface_by_sw_index(node, 0) is None: - local0_key = Topology.add_new_port(node, "localzero") - Topology.update_interface_sw_if_index(node, local0_key, 0) - Topology.update_interface_name(node, local0_key, "local0") - - @staticmethod - def configure_interface_unnumbered(node, interface, interface_src=None): - """Configure the specified interface as unnumbered. The interface - borrows IP address from the specified source interface. If not source - interface is provided, unnumbered configuration will be removed. - - :param node: Honeycomb node. - :param interface: Name, link name or sw_if_index of an interface. - :param interface_src: Name of source interface. - :type node: dict - :type interface: str or int - :type interface_src: str - :raises HoneycombError: If the configuration fails. - """ - - interface = InterfaceKeywords.handle_interface_reference( - node, interface) - - path = "/interface/{0}/unnumbered-interfaces:unnumbered"\ - .format(interface) - - if interface_src: - data = { - "unnumbered": { - "use": interface_src - } - } - status_code, _ = HcUtil.put_honeycomb_data( - node, "config_vpp_interfaces", data, path) - else: - status_code, _ = HcUtil.delete_honeycomb_data( - node, "config_vpp_interfaces", path) - - if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): - raise HoneycombError( - "Configuring unnumbered interface failed. " - "Status code:{0}".format(status_code)) - - @staticmethod - def handle_interface_reference(node, interface): - """Convert any interface reference to interface name used by Honeycomb. - - :param node: Honeycomb node. - :param interface: Name, link name or sw_if_index of an interface, - name of a custom interface or name of a sub-interface. - :type node: Honeycomb node. - :type interface: str or int - :returns: Name of interface that can be used in Honeycomb requests. - :rtype: str - """ - - try: - interface = Topology.convert_interface_reference( - node, interface, "name") - interface = interface.replace("/", "%2F") - except RuntimeError: - # interface is not in topology - if "." in interface: - # Assume it's the name of a sub-interface - interface, index = interface.split(".") - interface = interface.replace("/", "%2F") - interface = "{0}/vpp-vlan:sub-interfaces/sub-interface/{1}".\ - format(interface, index) - else: - # Assume it's the name of a custom interface (pbb, vxlan, etc.) - interface = interface.replace("/", "%2F") - - return interface diff --git a/resources/libraries/python/honeycomb/HcAPIKwNSH.py b/resources/libraries/python/honeycomb/HcAPIKwNSH.py deleted file mode 100644 index e042fdd423..0000000000 --- a/resources/libraries/python/honeycomb/HcAPIKwNSH.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright (c) 2018 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""This module implements keywords to manipulate NSH-SFC data structures using -Honeycomb REST API.""" - -from resources.libraries.python.HTTPRequest import HTTPCodes -from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError -from resources.libraries.python.honeycomb.HoneycombUtil \ - import HoneycombUtil as HcUtil -from resources.libraries.python.honeycomb.HoneycombUtil \ - import DataRepresentation - - -class NSHKeywords(object): - """Implementation of keywords which make it possible to: - - add and remove NSH entries, - - get operational data about NSH entries, - - add and remove NSH maps, - - get operational data about NSH maps. - """ - - def __init__(self): - pass - - @staticmethod - def _set_nsh_properties(node, path, data=None): - """Set NSH 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 - OK or ACCEPTED. - """ - - if data: - status_code, resp = HcUtil. \ - put_honeycomb_data(node, "config_nsh", data, path, - data_representation=DataRepresentation.JSON) - else: - status_code, resp = HcUtil. \ - delete_honeycomb_data(node, "config_nsh", path) - - if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): - raise HoneycombError( - "The configuration of NSH-SFC was not successful. " - "Status code: {0}.".format(status_code)) - return resp - - @staticmethod - def add_nsh_entry(node, name, data): - """Add an NSH entry to the list of entries. The keyword does - not validate given data. - - :param node: Honeycomb node. - :param name: Name for the NSH entry. - :param data: Settings for the new entry. - :type node: dict - :type name: str - :type data: dict - :returns: Content of response. - :rtype: bytearray - """ - - path = "/nsh-entries/nsh-entry/{0}".format(name) - - return NSHKeywords._set_nsh_properties(node, path, data) - - @staticmethod - def add_nsh_map(node, name, data): - """Add an NSH map to the list of maps. The keyword does - not validate given data. - - :param node: Honeycomb node. - :param name: Name for the NSH map. - :param data: Settings for the new map. - :type node: dict - :type name: str - :type data: dict - :returns: Content of response. - :rtype: bytearray - """ - path = "/nsh-maps/nsh-map/{0}".format(name) - - return NSHKeywords._set_nsh_properties(node, path, data) - - @staticmethod - def remove_nsh_entry(node, name): - """Remove an NSH entry from the list of entries. - :param node: Honeycomb node. - :param name: Name of the NSH entry. - :type node: dict - :type name: str - :returns: Content of response. - :rtype: bytearray - """ - - path = "/nsh-entries/nsh-entry/{0}".format(name) - return NSHKeywords._set_nsh_properties(node, path) - - @staticmethod - def remove_nsh_map(node, name): - """Remove an NSH map from the list of maps. - :param node: Honeycomb node. - :param name: Name of the NSH map. - :type node: dict - :type name: str - :returns: Content of response. - :rtype: bytearray - """ - - path = "/nsh-maps/nsh-map/{0}".format(name) - return NSHKeywords._set_nsh_properties(node, path) - - @staticmethod - 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 - :returns: 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 - - @staticmethod - def clear_nsh_settings(node): - """Remove the entire NSH container with all of its entries and maps. - - :param node: Honeycomb node. - :type node: dict - :returns: Content of response. - :rtype: bytearray - """ - - return NSHKeywords._set_nsh_properties(node, '') diff --git a/resources/libraries/python/honeycomb/HcPersistence.py b/resources/libraries/python/honeycomb/HcPersistence.py deleted file mode 100644 index 1627375f72..0000000000 --- a/resources/libraries/python/honeycomb/HcPersistence.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright (c) 2018 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Implementation of keywords for managing Honeycomb persistence files.""" - -from robot.api import logger - -from resources.libraries.python.Constants import Constants as Const -from resources.libraries.python.honeycomb.HoneycombUtil import HoneycombError -from resources.libraries.python.ssh import SSH -from resources.libraries.python.topology import NodeType - - -class HcPersistence(object): - """Implements keywords for managing Honeycomb persistence files. - - The keywords implemented in this class make possible to: - - find and replace strings in config.json persistence file - """ - - def __init__(self): - pass - - @staticmethod - def clear_persisted_honeycomb_config(*nodes): - """Remove configuration data persisted from last Honeycomb session. - Default configuration will be used instead. - - :param nodes: List of DUTs to execute on. - :type nodes: list - :raises HoneycombError: If persisted configuration could not be removed. - """ - cmd = "rm -rf {}/*".format(Const.REMOTE_HC_PERSIST) - for node in nodes: - if node['type'] == NodeType.DUT: - ssh = SSH() - ssh.connect(node) - (ret_code, _, stderr) = ssh.exec_command_sudo(cmd) - if ret_code != 0: - if "No such file or directory" not in stderr: - raise HoneycombError('Could not clear persisted ' - 'configuration on node {0}, {1}' - .format(node['host'], stderr)) - else: - logger.info("Persistence data was not present on node" - " {0}".format(node['host'])) - else: - logger.info("Persistence files removed on node {0}" - .format(node['host'])) - - @staticmethod - def modify_persistence_files(node, find, replace): - """Searches contents of persistence file data.json for the provided - string, and replaces all occurrences with another string. - - :param node: Honeycomb node. - :param find: Text to find in file. - :param replace: String to replace anything found with. - :type node: dict - :type find: string - :type replace: string - :raises HoneycombError: If persistent configuration couldn't be - modified. - """ - - argument = "\"s/{0}/{1}/g\"".format(find, replace) - path = "{0}/config/data.json".format(Const.REMOTE_HC_PERSIST) - command = "sed -i {0} {1}".format(argument, path) - - ssh = SSH() - ssh.connect(node) - (ret_code, _, stderr) = ssh.exec_command_sudo(command) - if ret_code != 0: - raise HoneycombError("Failed to modify persistence file on node" - " {0}, {1}".format(node, stderr)) - - @staticmethod - def log_persisted_configuration(node): - """Read contents of Honeycomb persistence files and print them to log. - - :param node: Honeycomb node. - :type node: dict - """ - - commands = [ - "cat {0}/config/data.json".format(Const.REMOTE_HC_PERSIST), - "cat {0}/context/data.json".format(Const.REMOTE_HC_PERSIST), - ] - - ssh = SSH() - ssh.connect(node) - for command in commands: - (_, _, _) = ssh.exec_command_sudo(command) - - @staticmethod - def configure_persistence(node, state): - """Enable or disable Honeycomb configuration data persistence. - - :param node: Honeycomb node. - :param state: Enable or Disable. - :type node: dict - :type state: str - :raises ValueError: If the state argument is incorrect. - :raises HoneycombError: If the operation fails. - """ - - state = state.lower() - if state == "enable": - state = "true" - elif state == "disable": - state = "false" - else: - raise ValueError("Unexpected value of state argument:" - " {0} provided. Must be enable or disable." - .format(state)) - - for setting in ("persist-config", "persist-context"): - # find the setting, replace entire line with 'setting: state' - find = '\\"{setting}\\":'.format(setting=setting) - replace = '\\"{setting}\\": \\"{state}\\",'.format( - setting=setting, state=state) - - argument = '"/{0}/c\\ {1}"'.format(find, replace) - path = "{0}/config/honeycomb.json".format(Const.REMOTE_HC_DIR) - command = "sed -i {0} {1}".format(argument, path) - - ssh = SSH() - ssh.connect(node) - (ret_code, _, stderr) = ssh.exec_command_sudo(command) - if ret_code != 0: - raise HoneycombError("Failed to modify configuration on " - "node {0}, {1}".format(node, stderr)) diff --git a/resources/libraries/python/honeycomb/HoneycombSetup.py b/resources/libraries/python/honeycomb/HoneycombSetup.py deleted file mode 100644 index 796639e879..0000000000 --- a/resources/libraries/python/honeycomb/HoneycombSetup.py +++ /dev/null @@ -1,821 +0,0 @@ -# Copyright (c) 2018 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Implementation of keywords for Honeycomb setup.""" - -from json import loads -from time import time, sleep - -from ipaddress import IPv6Address, AddressValueError - -from robot.api import logger - -from resources.libraries.python.HTTPRequest import HTTPRequest, HTTPCodes, \ - HTTPRequestError -from resources.libraries.python.Constants import Constants as Const -from resources.libraries.python.honeycomb.HoneycombUtil import HoneycombError -from resources.libraries.python.honeycomb.HoneycombUtil \ - import HoneycombUtil as HcUtil -from resources.libraries.python.ssh import SSH -from resources.libraries.python.topology import NodeType - - -class HoneycombSetup(object): - """Implements keywords for Honeycomb setup. - - The keywords implemented in this class make possible to: - - start Honeycomb, - - stop Honeycomb, - - check the Honeycomb start-up state, - - check the Honeycomb shutdown state, - - add VPP to the topology. - """ - - def __init__(self): - pass - - @staticmethod - def start_honeycomb_on_duts(*nodes): - """Start Honeycomb on specified DUT nodes. - - This keyword starts the Honeycomb service on specified DUTs. - The keyword just starts the Honeycomb and does not check its startup - state. Use the keyword "Check Honeycomb Startup State" to check if the - Honeycomb is up and running. - Honeycomb must be installed in "/opt" directory, otherwise the start - will fail. - - :param nodes: List of nodes to start Honeycomb on. - :type nodes: list - :raises HoneycombError: If Honeycomb fails to start. - """ - - HoneycombSetup.print_environment(nodes) - - cmd = "sudo service honeycomb start" - - for node in nodes: - if node['type'] == NodeType.DUT: - logger.console( - "\n(re)Starting Honeycomb service on node {0}".format( - node["host"])) - ssh = SSH() - ssh.connect(node) - (ret_code, _, _) = ssh.exec_command_sudo(cmd) - if int(ret_code) != 0: - raise HoneycombError('Node {0} failed to start Honeycomb.'. - format(node['host'])) - else: - logger.info("Starting the Honeycomb service on node {0} is " - "in progress ...".format(node['host'])) - - @staticmethod - def stop_honeycomb_on_duts(*nodes): - """Stop the Honeycomb service on specified DUT nodes. - - This keyword stops the Honeycomb service on specified nodes. It just - stops the Honeycomb and does not check its shutdown state. Use the - keyword "Check Honeycomb Shutdown State" to check if Honeycomb has - stopped. - - :param nodes: List of nodes to stop Honeycomb on. - :type nodes: list - :raises HoneycombError: If Honeycomb failed to stop. - """ - - cmd = "sudo service honeycomb stop" - errors = [] - - for node in nodes: - if node['type'] == NodeType.DUT: - logger.console( - "\nShutting down Honeycomb service on node {0}".format( - node["host"])) - ssh = SSH() - ssh.connect(node) - (ret_code, _, _) = ssh.exec_command_sudo(cmd) - if int(ret_code) != 0: - errors.append(node['host']) - else: - logger.info("Stopping the Honeycomb service on node {0} is " - "in progress ...".format(node['host'])) - if errors: - raise HoneycombError('Node(s) {0} failed to stop Honeycomb.'. - format(errors)) - - @staticmethod - def restart_honeycomb_on_dut(node): - """Restart Honeycomb on specified DUT nodes. - - This keyword restarts the Honeycomb service on specified DUTs. Use the - keyword "Check Honeycomb Startup State" to check if the Honeycomb is up - and running. - - :param node: Node to restart Honeycomb on. - :type node: dict - :raises HoneycombError: If Honeycomb fails to start. - """ - - logger.console( - "\n(re)Starting Honeycomb service on node {0}".format(node["host"])) - - cmd = "sudo service honeycomb restart" - - ssh = SSH() - ssh.connect(node) - (ret_code, _, _) = ssh.exec_command_sudo(cmd) - if int(ret_code) != 0: - raise HoneycombError('Node {0} failed to restart Honeycomb.'. - format(node['host'])) - else: - logger.info( - "Honeycomb service restart is in progress on node {0}".format( - node['host'])) - - @staticmethod - def check_honeycomb_startup_state(node, timeout=360, retries=20, - interval=15): - """Repeatedly check the status of Honeycomb startup until it is fully - started or until timeout or max retries is reached. - - :param node: Honeycomb node. - :param timeout: Timeout value in seconds. - :param retries: Max number of retries. - :param interval: Interval between checks, in seconds. - :type node: dict - :type timeout: int - :type retries: int - :type interval: int - :raises HoneycombError: If the Honeycomb process IP cannot be found, - or if timeout or number of retries is exceeded. - """ - - ssh = SSH() - ssh.connect(node) - - count = 0 - start = time() - while time() - start < timeout and count < retries: - count += 1 - - try: - status_code_version, _ = HcUtil.get_honeycomb_data( - node, "oper_vpp_version") - status_code_if_cfg, _ = HcUtil.get_honeycomb_data( - node, "config_vpp_interfaces") - status_code_if_oper, _ = HcUtil.get_honeycomb_data( - node, "oper_vpp_interfaces") - except HTTPRequestError: - sleep(interval) - continue - if status_code_if_cfg == HTTPCodes.OK\ - and status_code_if_cfg == HTTPCodes.OK\ - and status_code_if_oper == HTTPCodes.OK: - logger.info("Check successful, Honeycomb is up and running.") - break - else: - logger.debug( - "Attempt ${count} failed on Restconf check. Status codes:\n" - "Version: {version}\n" - "Interface config: {if_cfg}\n" - "Interface operational: {if_oper}".format( - count=count, - version=status_code_version, - if_cfg=status_code_if_cfg, - if_oper=status_code_if_oper)) - sleep(interval) - continue - else: - _, vpp_status, _ = ssh.exec_command("sudo service vpp status") - raise HoneycombError( - "Timeout or max retries exceeded. Status of VPP:\n" - "{vpp_status}".format(vpp_status=vpp_status)) - - @staticmethod - def check_honeycomb_shutdown_state(node): - """Check state of Honeycomb service during shutdown on specified nodes. - - Honeycomb nodes reply with connection refused or the following status - codes depending on shutdown progress: codes 200, 404. - - :param node: List of DUT nodes stopping Honeycomb. - :type node: dict - :returns: True if all GETs fail to connect. - :rtype: bool - """ - cmd = "pgrep honeycomb" - - ssh = SSH() - ssh.connect(node) - (ret_code, _, _) = ssh.exec_command_sudo(cmd) - if ret_code == 0: - raise HoneycombError('Honeycomb on node {0} is still ' - 'running.'.format(node['host']), - enable_logging=False) - else: - logger.info("Honeycomb on node {0} has stopped". - format(node['host'])) - return True - - @staticmethod - def configure_restconf_binding_address(node): - """Configure Honeycomb to accept restconf requests from all IP - addresses. IP version is determined by node data. - - :param node: Information about a DUT node. - :type node: dict - :raises HoneycombError: If the configuration could not be changed. - """ - - find = "restconf-binding-address" - try: - IPv6Address(unicode(node["host"])) - # if management IP of the node is in IPv6 format - replace = '\\"restconf-binding-address\\": \\"0::0\\",' - except (AttributeError, AddressValueError): - replace = '\\"restconf-binding-address\\": \\"0.0.0.0\\",' - - argument = '"/{0}/c\\ {1}"'.format(find, replace) - path = "{0}/config/restconf.json".format(Const.REMOTE_HC_DIR) - command = "sed -i {0} {1}".format(argument, path) - - ssh = SSH() - ssh.connect(node) - (ret_code, _, stderr) = ssh.exec_command_sudo(command) - if ret_code != 0: - raise HoneycombError("Failed to modify configuration on " - "node {0}, {1}".format(node, stderr)) - - @staticmethod - def configure_jvpp_timeout(node, timeout=10): - """Configure timeout value for Java API commands Honeycomb sends to VPP. - - :param node: Information about a DUT node. - :param timeout: Timeout value in seconds. - :type node: dict - :type timeout: int - :raises HoneycombError: If the configuration could not be changed. - """ - - find = "jvpp-request-timeout" - replace = '\\"jvpp-request-timeout\\": {0}'.format(timeout) - - argument = '"/{0}/c\\ {1}"'.format(find, replace) - path = "{0}/config/jvpp.json".format(Const.REMOTE_HC_DIR) - command = "sed -i {0} {1}".format(argument, path) - - ssh = SSH() - ssh.connect(node) - (ret_code, _, stderr) = ssh.exec_command_sudo(command) - if ret_code != 0: - raise HoneycombError("Failed to modify configuration on " - "node {0}, {1}".format(node, stderr)) - - @staticmethod - def print_environment(nodes): - """Print information about the nodes to log. The information is defined - by commands in cmds tuple at the beginning of this method. - - :param nodes: List of DUT nodes to get information about. - :type nodes: list - """ - - # TODO: When everything is set and running in VIRL env, transform this - # method to a keyword checking the environment. - - cmds = ("uname -a", - "df -lh", - "echo $JAVA_HOME", - "echo $PATH", - "which java", - "java -version", - "dpkg --list | grep openjdk", - "ls -la /opt/honeycomb", - "cat /opt/honeycomb/modules/*module-config") - - for node in nodes: - if node['type'] == NodeType.DUT: - logger.info("Checking node {} ...".format(node['host'])) - for cmd in cmds: - logger.info("Command: {}".format(cmd)) - ssh = SSH() - ssh.connect(node) - ssh.exec_command_sudo(cmd) - - @staticmethod - def print_ports(node): - """Uses "sudo netstat -anp | grep java" to print port where a java - application listens. - - :param node: Honeycomb node where we want to print the ports. - :type node: dict - """ - - cmds = ("netstat -anp | grep java", - "ps -ef | grep [h]oneycomb") - - logger.info("Checking node {} ...".format(node['host'])) - for cmd in cmds: - logger.info("Command: {}".format(cmd)) - ssh = SSH() - ssh.connect(node) - ssh.exec_command_sudo(cmd) - - @staticmethod - def configure_log_level(node, level): - """Set Honeycomb logging to the specified level. - - :param node: Honeycomb node. - :param level: Log level (INFO, DEBUG, TRACE). - :type node: dict - :type level: str - """ - - find = 'logger name=\\"io.fd\\"' - replace = '<logger name=\\"io.fd\\" level=\\"{0}\\"/>'.format(level) - - argument = '"/{0}/c\\ {1}"'.format(find, replace) - path = "{0}/config/logback.xml".format(Const.REMOTE_HC_DIR) - command = "sed -i {0} {1}".format(argument, path) - - ssh = SSH() - ssh.connect(node) - (ret_code, _, stderr) = ssh.exec_command_sudo(command) - if ret_code != 0: - raise HoneycombError("Failed to modify configuration on " - "node {0}, {1}".format(node, stderr)) - - @staticmethod - def manage_honeycomb_features(node, feature, disable=False): - """Configure Honeycomb to use features that are disabled by default, or - disable previously enabled features. - - ..Note:: If the module is not enabled in VPP, Honeycomb will - be unable to establish VPP connection. - - :param node: Honeycomb node. - :param feature: Feature to enable. - :param disable: Disable the specified feature instead of enabling it. - :type node: dict - :type feature: string - :type disable: bool - :raises HoneycombError: If the configuration could not be changed. - """ - - disabled_features = { - "NSH": ["io.fd.hc2vpp.vppnsh.impl.VppNshModule"], - "BGP": ["io.fd.hc2vpp.bgp.inet.BgpInetModule", - "io.fd.honeycomb.infra.bgp.BgpModule", - "io.fd.honeycomb.infra.bgp.BgpReadersModule", - "io.fd.honeycomb.infra.bgp.BgpWritersModule", - "io.fd.honeycomb.northbound.bgp.extension.InetModule", - "io.fd.honeycomb.northbound.bgp.extension.EvpnModule", - "io.fd.honeycomb.northbound.bgp.extension.L3VpnV4Module", - "io.fd.honeycomb.northbound.bgp.extension.L3VpnV6Module", - "io.fd.honeycomb.northbound.bgp.extension." - "LabeledUnicastModule", - "io.fd.honeycomb.northbound.bgp.extension.LinkstateModule"] - } - - ssh = SSH() - ssh.connect(node) - - if feature in disabled_features.keys(): - # for every module, uncomment by replacing the entire line - for item in disabled_features[feature]: - find = replace = "{0}".format(item) - if disable: - replace = "// {0}".format(find) - - argument = '"/{0}/c\\ {1}"'.format(find, replace) - path = "{0}/modules/*module-config"\ - .format(Const.REMOTE_HC_DIR) - command = "sed -i {0} {1}".format(argument, path) - - (ret_code, _, stderr) = ssh.exec_command_sudo(command) - if ret_code != 0: - raise HoneycombError("Failed to modify configuration on " - "node {0}, {1}".format(node, stderr)) - else: - raise HoneycombError( - "Unrecognized feature {0}.".format(feature)) - - @staticmethod - def copy_java_libraries(node): - """Copy Java libraries installed by vpp-api-java package to honeycomb - lib folder. - - This is a (temporary?) workaround for jvpp version mismatches. - - :param node: Honeycomb node - :type node: dict - """ - - ssh = SSH() - ssh.connect(node) - (_, stdout, _) = ssh.exec_command_sudo( - "ls /usr/share/java | grep ^jvpp-*") - - files = stdout.split("\n")[:-1] - for item in files: - # example filenames: - # jvpp-registry-17.04.jar - # jvpp-core-17.04.jar - - parts = item.split("-") - version = "{0}-SNAPSHOT".format(parts[2][:5]) - artifact_id = "{0}-{1}".format(parts[0], parts[1]) - - directory = "{0}/lib/io/fd/vpp/{1}/{2}".format( - Const.REMOTE_HC_DIR, artifact_id, version) - cmd = "sudo mkdir -p {0}; " \ - "sudo cp /usr/share/java/{1} {0}/{2}-{3}.jar".format( - directory, item, artifact_id, version) - - (ret_code, _, stderr) = ssh.exec_command(cmd) - if ret_code != 0: - raise HoneycombError("Failed to copy JVPP libraries on " - "node {0}, {1}".format(node, stderr)) - - @staticmethod - def copy_odl_client(node, odl_name, src_path, dst_path): - """Copy ODL Client from source path to destination path. - - :param node: Honeycomb node. - :param odl_name: Name of ODL client version to use. - :param src_path: Source Path where to find ODl client. - :param dst_path: Destination path. - :type node: dict - :type odl_name: str - :type src_path: str - :type dst_path: str - :raises HoneycombError: If the operation fails. - """ - - ssh = SSH() - ssh.connect(node) - - cmd = "sudo rm -rf {dst}/*karaf_{odl_name} && " \ - "cp -r {src}/*karaf_{odl_name}* {dst}".format( - src=src_path, odl_name=odl_name, dst=dst_path) - - ret_code, _, _ = ssh.exec_command_sudo(cmd, timeout=180) - if int(ret_code) != 0: - raise HoneycombError( - "Failed to copy ODL client on node {0}".format(node["host"])) - - @staticmethod - def setup_odl_client(node, path): - """Start ODL client on the specified node. - - Karaf should be located in the provided path, and VPP and Honeycomb - should already be running, otherwise the start will fail. - - :param node: Node to start ODL client on. - :param path: Path to ODL client on node. - :type node: dict - :type path: str - :raises HoneycombError: If Honeycomb fails to start. - """ - - logger.console("\nStarting ODL client ...") - ssh = SSH() - ssh.connect(node) - - cmd = "{path}/*karaf*/bin/start clean".format(path=path) - ret_code, _, _ = ssh.exec_command_sudo(cmd) - - if int(ret_code) != 0: - raise HoneycombError('Node {0} failed to start ODL.'. - format(node['host'])) - else: - logger.info("Starting the ODL client on node {0} is " - "in progress ...".format(node['host'])) - - @staticmethod - def install_odl_features(node, path, *features): - """Install required features on a running ODL client. - - :param node: Honeycomb node. - :param path: Path to ODL client on node. - :param features: Optional, list of additional features to install. - :type node: dict - :type path: str - :type features: list - """ - - ssh = SSH() - ssh.connect(node) - - auth = "-u karaf -p karaf" - - cmd = "{path}/*karaf*/bin/client {auth} feature:install " \ - "odl-restconf-all " \ - "odl-netconf-connector-all " \ - "odl-netconf-topology".format(path=path, auth=auth) - for feature in features: - cmd += " {0}".format(feature) - - ret_code, _, _ = ssh.exec_command_sudo(cmd, timeout=250) - - if int(ret_code) != 0: - raise HoneycombError("Feature install did not succeed.") - - @staticmethod - def check_odl_startup_state(node): - """Check the status of ODL client startup. - - :param node: Honeycomb node. - :param node: dict - :returns: True when ODL is started. - :rtype: bool - :raises HoneycombError: When the response is not code 200: OK. - """ - - path = HcUtil.read_path_from_url_file( - "odl_client/odl_netconf_connector") - expected_status_codes = (HTTPCodes.UNAUTHORIZED, - HTTPCodes.FORBIDDEN, - HTTPCodes.NOT_FOUND, - HTTPCodes.SERVICE_UNAVAILABLE, - HTTPCodes.INTERNAL_SERVER_ERROR) - - status_code, _ = HTTPRequest.get(node, path, timeout=10, - enable_logging=False) - if status_code == HTTPCodes.OK: - logger.info("ODL client on node {0} is up and running". - format(node['host'])) - elif status_code in expected_status_codes: - if status_code == HTTPCodes.UNAUTHORIZED: - logger.info('Unauthorized. If this triggers keyword ' - 'timeout, verify username and password.') - raise HoneycombError('ODL client on node {0} running but ' - 'not yet ready.'.format(node['host']), - enable_logging=False) - else: - raise HoneycombError('Unexpected return code: {0}.'. - format(status_code)) - return True - - @staticmethod - def check_odl_shutdown_state(node): - """Check the status of ODL client shutdown. - - :param node: Honeycomb node. - :type node: dict - :returns: True when ODL is stopped. - :rtype: bool - :raises HoneycombError: When the response is not code 200: OK. - """ - - cmd = "pgrep -f karaf" - path = HcUtil.read_path_from_url_file( - "odl_client/odl_netconf_connector") - - try: - HTTPRequest.get(node, path, timeout=10, enable_logging=False) - raise HoneycombError("ODL client is still running.") - except HTTPRequestError: - logger.debug("Connection refused, checking process state....") - ssh = SSH() - ssh.connect(node) - ret_code, _, _ = ssh.exec_command(cmd) - if ret_code == 0: - raise HoneycombError("ODL client is still running.") - - return True - - @staticmethod - def mount_honeycomb_on_odl(node): - """Tell ODL client to mount Honeycomb instance over netconf. - - :param node: Honeycomb node. - :type node: dict - :raises HoneycombError: When the response is not code 200: OK. - """ - - path = HcUtil.read_path_from_url_file( - "odl_client/odl_netconf_connector") - - url_file = "{0}/{1}".format(Const.RESOURCES_TPL_HC, - "odl_client/mount_honeycomb.json") - - with open(url_file) as template: - data = template.read() - - data = loads(data) - - status_code, _ = HTTPRequest.post( - node, - path, - headers={"Content-Type": "application/json", - "Accept": "text/plain"}, - json=data, - timeout=10, - enable_logging=False) - - if status_code == HTTPCodes.OK: - logger.info("ODL mount point configured successfully.") - elif status_code == HTTPCodes.CONFLICT: - logger.info("ODL mount point was already configured.") - else: - raise HoneycombError('Mount point configuration not successful') - - @staticmethod - def stop_odl_client(node, path): - """Stop ODL client service on the specified node. - - :param node: Node to start ODL client on. - :param path: Path to ODL client. - :type node: dict - :type path: str - :raises HoneycombError: If ODL client fails to stop. - """ - - ssh = SSH() - ssh.connect(node) - - cmd = "{0}/*karaf*/bin/stop".format(path) - - ssh = SSH() - ssh.connect(node) - ret_code, _, _ = ssh.exec_command_sudo(cmd) - if int(ret_code) != 0: - logger.debug("ODL Client refused to shut down.") - cmd = "pkill -f 'karaf'" - (ret_code, _, _) = ssh.exec_command_sudo(cmd) - if int(ret_code) != 0: - raise HoneycombError('Node {0} failed to stop ODL.'. - format(node['host'])) - - logger.info("ODL client service stopped.") - - @staticmethod - def set_static_arp(node, ip_address, mac_address): - """Configure a static ARP entry using arp. - - :param node: Node in topology. - :param ip_address: IP address for the entry. - :param mac_address: MAC adddress for the entry. - :type node: dict - :type ip_address: str - :type mac_address: str - :raises RuntimeError: If the operation fails. - """ - - ssh = SSH() - ssh.connect(node) - ret_code, _, _ = ssh.exec_command_sudo("arp -s {0} {1}".format( - ip_address, mac_address)) - - if ret_code != 0: - raise RuntimeError("Failed to configure static ARP adddress.") - - -class HoneycombStartupConfig(object): - """Generator for Honeycomb startup configuration. - """ - def __init__(self): - """Initializer.""" - - self.template = """#!/bin/sh - - STATUS=100 - - while [ $STATUS -eq 100 ] - do - {java_call} -jar $(dirname $0)/{jar_filename} - STATUS=$? - echo "Honeycomb exited with status: $STATUS" - if [ $STATUS -eq 100 ] - then - echo "Restarting..." - fi - done - """ - - self.java_call = "{scheduler} {affinity} java{jit_mode}{params}" - - self.scheduler = "" - self.core_affinity = "" - self.jit_mode = "" - self.params = "" - self.numa = "" - - self.config = "" - self.ssh = SSH() - - def apply_config(self, node): - """Generate configuration file /opt/honeycomb/honeycomb on the specified - node. - - :param node: Honeycomb node. - :type node: dict - """ - - self.ssh.connect(node) - _, filename, _ = self.ssh.exec_command("ls /opt/honeycomb | grep .jar") - - java_call = self.java_call.format(scheduler=self.scheduler, - affinity=self.core_affinity, - jit_mode=self.jit_mode, - params=self.params) - self.config = self.template.format(java_call=java_call, - jar_filename=filename) - - self.ssh.connect(node) - cmd = "echo '{config}' > /tmp/honeycomb " \ - "&& chmod +x /tmp/honeycomb " \ - "&& sudo mv -f /tmp/honeycomb /opt/honeycomb".\ - format(config=self.config) - self.ssh.exec_command(cmd) - - def set_cpu_scheduler(self, scheduler="FIFO"): - """Use alternate CPU scheduler. - - Note: OTHER scheduler doesn't load-balance over isolcpus. - - :param scheduler: CPU scheduler to use. - :type scheduler: str - """ - - schedulers = {"FIFO": "-f 99", # First In, First Out - "RR": "-r 99", # Round Robin - "OTHER": "-o", # Ubuntu default - } - self.scheduler = "chrt {0}".format(schedulers[scheduler]) - - def set_cpu_core_affinity(self, low, high=None): - """Set core affinity for the honeycomb process and subprocesses. - - :param low: Lowest core ID number. - :param high: Highest core ID number. Leave empty to use a single core. - :type low: int - :type high: int - """ - - self.core_affinity = "taskset -c {low}-{high}".format( - low=low, high=high if high else low) - - def set_jit_compiler_mode(self, jit_mode): - """Set running mode for Java's JIT compiler. - - :param jit_mode: Desiret JIT mode. - :type jit_mode: str - """ - - modes = {"client": " -client", # Default - "server": " -server", # Higher performance but longer warmup - "classic": " -classic" # Disables JIT compiler - } - - self.jit_mode = modes[jit_mode] - - def set_memory_size(self, mem_min, mem_max=None): - """Set minimum and maximum memory use for the JVM. - - :param mem_min: Minimum amount of memory (MB). - :param mem_max: Maximum amount of memory (MB). Default is 4 times - minimum value. - :type mem_min: int - :type mem_max: int - """ - - self.params += " -Xms{min}m -Xmx{max}m".format( - min=mem_min, max=mem_max if mem_max else mem_min*4) - - def set_metaspace_size(self, mem_min, mem_max=None): - """Set minimum and maximum memory used for class metadata in the JVM. - - :param mem_min: Minimum metaspace size (MB). - :param mem_max: Maximum metaspace size (MB). Defailt is 4 times - minimum value. - :type mem_min: int - :type mem_max: int - """ - - self.params += " -XX:MetaspaceSize={min}m " \ - "-XX:MaxMetaspaceSize={max}m".format( - min=mem_min, max=mem_max if mem_max else mem_min*4) - - def set_numa_optimization(self): - """Use optimization of memory use and garbage collection for NUMA - architectures.""" - - self.params += " -XX:+UseNUMA -XX:+UseParallelGC" - - def set_ssh_security_provider(self): - """Disables BouncyCastle for SSHD.""" - # Workaround for issue described in: - # https://wiki.fd.io/view/Honeycomb/Releases/1609/Honeycomb_and_ODL - - self.params += " -Dorg.apache.sshd.registerBouncyCastle=false" diff --git a/resources/libraries/python/honeycomb/HoneycombUtil.py b/resources/libraries/python/honeycomb/HoneycombUtil.py deleted file mode 100644 index 59483f4672..0000000000 --- a/resources/libraries/python/honeycomb/HoneycombUtil.py +++ /dev/null @@ -1,512 +0,0 @@ -# Copyright (c) 2018 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Implementation of low level functionality used in communication with -Honeycomb. - -Exception HoneycombError is used in all methods and in all modules with -Honeycomb keywords. - -Class HoneycombUtil implements methods used by Honeycomb keywords. They must not -be used directly in tests. Use keywords implemented in the module -HoneycombAPIKeywords instead. -""" - -from json import loads, dumps -from enum import Enum, unique - -from robot.api import logger - -from resources.libraries.python.ssh import SSH -from resources.libraries.python.HTTPRequest import HTTPRequest -from resources.libraries.python.Constants import Constants as Const - - -@unique -class DataRepresentation(Enum): - """Representation of data sent by PUT and POST requests.""" - NO_DATA = 0 - JSON = 1 - XML = 2 - TXT = 3 - - -# Headers used in requests. Key - content representation, value - header. -HEADERS = {DataRepresentation.NO_DATA: - {}, # It must be empty dictionary. - DataRepresentation.JSON: - {"Content-Type": "application/json", - "Accept": "text/plain"}, - DataRepresentation.XML: - {"Content-Type": "application/xml", - "Accept": "text/plain"}, - DataRepresentation.TXT: - {"Content-Type": "text/plain", - "Accept": "text/plain"} - } - - -class HoneycombError(Exception): - - """Exception(s) raised by methods working with Honeycomb. - - When raising this exception, put this information to the message in this - order: - - - short description of the encountered problem (parameter msg), - - relevant messages if there are any collected, e.g., from caught - exception (optional parameter details), - - relevant data if there are any collected (optional parameter details). - - The logging is performed on two levels: 1. error - short description of the - problem; 2. debug - detailed information. - """ - - def __init__(self, msg, details='', enable_logging=True): - """Sets the exception message and enables / disables logging. - - It is not wanted to log errors when using these keywords together - with keywords like "Wait until keyword succeeds". So you can disable - logging by setting enable_logging to False. - - :param msg: Message to be displayed and logged. - :param enable_logging: When True, logging is enabled, otherwise - logging is disabled. - :type msg: str - :type enable_logging: bool - """ - super(HoneycombError, self).__init__() - self._msg = "{0}: {1}".format(self.__class__.__name__, msg) - self._details = details - if enable_logging: - logger.debug(self._details) - - def __repr__(self): - return repr(self._msg) - - def __str__(self): - return str(self._msg) - - -class HoneycombUtil(object): - """Implements low level functionality used in communication with Honeycomb. - - There are implemented methods to get, put and delete data to/from Honeycomb. - They are based on functionality implemented in the module HTTPRequests which - uses HTTP requests GET, PUT, POST and DELETE to communicate with Honeycomb. - - It is possible to PUT the data represented as XML or JSON structures or as - plain text. - Data received in the response of GET are always represented as a JSON - structure. - - There are also two supportive methods implemented: - - - read_path_from_url_file which reads URL file and returns a path (see - docs/honeycomb_url_files.rst). - - parse_json_response which parses data from response in JSON - representation according to given path. - """ - - def __init__(self): - pass - - @staticmethod - def read_path_from_url_file(url_file): - """Read path from .url file. - - For more information about .url file see docs/honeycomb_url_files.rst - - :param url_file: URL file. The argument contains only the name of file - without extension, not the full path. - :type url_file: str - :returns: Requested path. - :rtype: str - """ - - url_file = "{0}/{1}.url".format(Const.RESOURCES_TPL_HC, url_file) - with open(url_file) as template: - path = template.readline() - return path - - @staticmethod - def find_item(data, path): - """Find a data item (single leaf or sub-tree) in data received from - Honeycomb REST API. - - Path format: - The path is a tuple with items navigating to requested data. The items - can be strings or tuples: - - - string item represents a dictionary key in data, - - tuple item represents list item in data. - - Example:: - - data = \ - { - "interfaces": { - "interface": [ - { - "name": "GigabitEthernet0/8/0", - "enabled": "true", - "type": "iana-if-type:ethernetCsmacd", - }, - { - "name": "local0", - "enabled": "false", - "type": "iana-if-type:ethernetCsmacd", - } - ] - } - } - - path = ("interfaces", ("interface", "name", "local0"), "enabled") - This path points to "false". - - The tuple ("interface", "name", "local0") consists of:: - - index 0 - dictionary key pointing to a list, - index 1 - key which identifies an item in the list, it is also marked - as the key in corresponding yang file. - index 2 - key value. - - :param data: Data received from Honeycomb REST API. - :param path: Path to data we want to find. - :type data: dict - :type path: tuple - :returns: Data represented by path. - :rtype: str, dict, or list - :raises HoneycombError: If the data has not been found. - """ - - for path_item in path: - try: - if isinstance(path_item, str): - data = data[path_item] - elif isinstance(path_item, tuple): - for data_item in data[path_item[0]]: - if data_item[path_item[1]] == path_item[2]: - data = data_item - except KeyError as err: - raise HoneycombError("Data not found: {0}".format(err)) - - return data - - @staticmethod - def remove_item(data, path): - """Remove a data item (single leaf or sub-tree) in data received from - Honeycomb REST API. - - :param data: Data received from Honeycomb REST API. - :param path: Path to data we want to remove. - :type data: dict - :type path: tuple - :returns: Original data without removed part. - :rtype: dict - """ - - origin_data = previous_data = data - try: - for path_item in path: - previous_data = data - if isinstance(path_item, str): - data = data[path_item] - elif isinstance(path_item, tuple): - for data_item in data[path_item[0]]: - if data_item[path_item[1]] == path_item[2]: - data = data_item - except KeyError as err: - logger.debug("Data not found: {0}".format(err)) - return origin_data - - if isinstance(path[-1], str): - previous_data.pop(path[-1]) - elif isinstance(path[-1], tuple): - previous_data[path[-1][0]].remove(data) - if not previous_data[path[-1][0]]: - previous_data.pop(path[-1][0]) - - return origin_data - - @staticmethod - def set_item_value(data, path, new_value): - """Set or change the value (single leaf or sub-tree) in data received - from Honeycomb REST API. - - If the item is not present in the data structure, it is created. - - :param data: Data received from Honeycomb REST API. - :param path: Path to data we want to change or create. - :param new_value: The value to be set. - :type data: dict - :type path: tuple - :type new_value: str, dict or list - :returns: Original data with the new value. - :rtype: dict - """ - - origin_data = data - for path_item in path[:-1]: - if isinstance(path_item, str): - try: - data = data[path_item] - except KeyError: - data[path_item] = {} - data = data[path_item] - elif isinstance(path_item, tuple): - try: - flag = False - index = 0 - for data_item in data[path_item[0]]: - if data_item[path_item[1]] == path_item[2]: - data = data[path_item[0]][index] - flag = True - break - index += 1 - if not flag: - data[path_item[0]].append({path_item[1]: path_item[2]}) - data = data[path_item[0]][-1] - except KeyError: - data[path_item] = [] - - if not path[-1] in data.keys(): - data[path[-1]] = {} - - if isinstance(new_value, list) and isinstance(data[path[-1]], list): - for value in new_value: - data[path[-1]].append(value) - else: - data[path[-1]] = new_value - - return origin_data - - @staticmethod - def get_honeycomb_data(node, url_file, path=""): - """Retrieve data from Honeycomb according to given URL. - - :param node: Honeycomb node. - :param url_file: URL file. The argument contains only the name of file - without extension, not the full path. - :param path: Path which is added to the base path to identify the data. - :type node: dict - :type url_file: str - :type path: str - :returns: Status code and content of response. - :rtype: tuple - """ - - base_path = HoneycombUtil.read_path_from_url_file(url_file) - path = base_path + path - status_code, resp = HTTPRequest.get(node, path) - - try: - data = loads(resp) - except ValueError: - logger.debug("Failed to deserialize JSON data.") - data = None - - return status_code, data - - @staticmethod - def put_honeycomb_data(node, url_file, data, path="", - data_representation=DataRepresentation.JSON): - """Send configuration data using PUT request and return the status code - and response content. - - :param node: Honeycomb node. - :param url_file: URL file. The argument contains only the name of file - without extension, not the full path. - :param data: Configuration data to be sent to Honeycomb. - :param path: Path which is added to the base path to identify the data. - :param data_representation: How the data is represented. - :type node: dict - :type url_file: str - :type data: dict, str - :type path: str - :type data_representation: DataRepresentation - :returns: Status code and content of response. - :rtype: tuple - :raises HoneycombError: If the given data representation is not defined - in HEADERS. - """ - - try: - header = HEADERS[data_representation] - except AttributeError as err: - raise HoneycombError("Wrong data representation: {0}.". - format(data_representation), repr(err)) - if data_representation == DataRepresentation.JSON: - data = dumps(data) - - logger.trace(data) - - base_path = HoneycombUtil.read_path_from_url_file(url_file) - path = base_path + path - logger.trace(path) - return HTTPRequest.put( - node=node, path=path, headers=header, payload=data) - - @staticmethod - def post_honeycomb_data(node, url_file, data=None, - data_representation=DataRepresentation.JSON, - timeout=10): - """Send a POST request and return the status code and response content. - - :param node: Honeycomb node. - :param url_file: URL file. The argument contains only the name of file - without extension, not the full path. - :param data: Configuration data to be sent to Honeycomb. - :param data_representation: How the data is represented. - :param timeout: How long to wait for the server to send data before - giving up. - :type node: dict - :type url_file: str - :type data: dict, str - :type data_representation: DataRepresentation - :type timeout: int - :returns: Status code and content of response. - :rtype: tuple - :raises HoneycombError: If the given data representation is not defined - in HEADERS. - """ - - try: - header = HEADERS[data_representation] - except AttributeError as err: - raise HoneycombError("Wrong data representation: {0}.". - format(data_representation), repr(err)) - if data_representation == DataRepresentation.JSON: - data = dumps(data) - - path = HoneycombUtil.read_path_from_url_file(url_file) - return HTTPRequest.post( - node=node, path=path, headers=header, payload=data, timeout=timeout) - - @staticmethod - def delete_honeycomb_data(node, url_file, path=""): - """Delete data from Honeycomb according to given URL. - - :param node: Honeycomb node. - :param url_file: URL file. The argument contains only the name of file - without extension, not the full path. - :param path: Path which is added to the base path to identify the data. - :type node: dict - :type url_file: str - :type path: str - :returns: Status code and content of response. - :rtype: tuple - """ - - base_path = HoneycombUtil.read_path_from_url_file(url_file) - path = base_path + path - return HTTPRequest.delete(node, path) - - @staticmethod - def append_honeycomb_log(node, suite_name): - """Append Honeycomb log for the current test suite to the full log. - - :param node: Honeycomb node. - :param suite_name: Name of the current test suite. ${SUITE_NAME} - variable in robotframework. - :type node: dict - :type suite_name: str - """ - - ssh = SSH() - ssh.connect(node) - - ssh.exec_command( - "echo '{separator}' >> /tmp/honeycomb.log".format(separator="="*80)) - ssh.exec_command( - "echo 'Log for suite: {suite}' >> /tmp/honeycomb.log".format( - suite=suite_name)) - ssh.exec_command( - "cat {hc_log} >> /tmp/honeycomb.log".format( - hc_log=Const.REMOTE_HC_LOG)) - - @staticmethod - def append_odl_log(node, odl_name, suite_name): - """Append ODL karaf log for the current test suite to the full log. - - :param node: Honeycomb node. - :param odl_name: Name of ODL client version to use. - :param suite_name: Name of the current test suite. ${SUITE_NAME} - variable in robotframework. - :type node: dict - :type odl_name: str - :type suite_name: str - """ - - ssh = SSH() - ssh.connect(node) - - ssh.exec_command( - "echo '{separator}' >> /tmp/karaf.log".format(separator="="*80)) - ssh.exec_command( - "echo 'Log for suite: {suite}' >> /tmp/karaf.log".format( - suite=suite_name)) - ssh.exec_command( - "cat /tmp/karaf_{odl_name}/data/log/karaf.log >> /tmp/karaf.log" - .format(odl_name=odl_name)) - - @staticmethod - def clear_honeycomb_log(node): - """Delete the Honeycomb log file for the current test suite. - - :param node: Honeycomb node. - :type node: dict - """ - - ssh = SSH() - ssh.connect(node) - - ssh.exec_command("sudo rm {hc_log}".format(hc_log=Const.REMOTE_HC_LOG)) - - @staticmethod - def archive_honeycomb_log(node, perf=False): - """Copy honeycomb log file from DUT node to VIRL for archiving. - - :param node: Honeycomb node. - :param perf: Alternate handling, for use with performance test topology. - :type node: dict - :type perf: bool - """ - - ssh = SSH() - ssh.connect(node) - - if not perf: - cmd = "cp /tmp/honeycomb.log /scratch/" - ssh.exec_command_sudo(cmd, timeout=60) - else: - ssh.scp( - ".", - "/tmp/honeycomb.log", - get=True, - timeout=60) - ssh.exec_command("rm /tmp/honeycomb.log") - - @staticmethod - def archive_odl_log(node): - """Copy ODL karaf log file from DUT node to VIRL for archiving. - - :param node: Honeycomb node. - :type node: dict - """ - - ssh = SSH() - ssh.connect(node) - - cmd = "cp /tmp/karaf.log /scratch/" - ssh.exec_command_sudo(cmd, timeout=60) diff --git a/resources/libraries/python/honeycomb/IPv6Management.py b/resources/libraries/python/honeycomb/IPv6Management.py deleted file mode 100644 index deec041103..0000000000 --- a/resources/libraries/python/honeycomb/IPv6Management.py +++ /dev/null @@ -1,147 +0,0 @@ -# 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Keywords used for setup and testing of Honeycomb's control-plane interface -using IPv6. -""" - -from resources.libraries.python.ssh import SSH - - -class IPv6Management(object): - """Utilities for managing IPv6 contol-plane interfaces.""" - - def __init__(self): - pass - - @staticmethod - def get_interface_name_by_mac(node, mac): - """Get the name of an interface using its MAC address. - - :param node: Node in topology. - :param mac: MAC address. - :type node: dict - :type mac: str - :returns: Name of the interface. - :rtype: str - :raises RuntimeError: If no interface is found. - """ - - cmd = " | ".join([ - "fgrep -ls '{0}' /sys/class/net/*/address".format(mac), - "awk -F '/' '{print $5}'" - ]) - - ssh = SSH() - ssh.connect(node) - ret_code, stdout, _ = ssh.exec_command(cmd) - - if ret_code == 0: - return stdout.strip() - else: - raise RuntimeError("No interface found using the specified MAC " - "address.") - - @staticmethod - def clear_interface_configuration(node, interface): - """Remove all configured IP addresses from the specified interface - and set it into down state. - - :param node: Node in topology. - :param interface: Name of an interface on the node. - :type node: dict - :type interface: str - :raises RuntimeError: If the configuration could not be cleared. - """ - - cmd = " && ".join([ - "sudo ip addr flush dev {interface}".format(interface=interface), - "sudo ip link set dev {interface} down".format(interface=interface) - ]) - - ssh = SSH() - ssh.connect(node) - ret_code, _, _ = ssh.exec_command(cmd) - if ret_code != 0: - raise RuntimeError("Could not clear interface configuration.") - - @staticmethod - def set_management_interface_address(node, interface, address, prefix): - """Configure an IP address on the specified interface. - - :param node: Node in topology. - :param interface: Name of an interface on the node. - :param address: IP address to configure. - :param prefix: IP network prefix. - :type node: dict - :type interface: str - :type address: str - :type prefix: int - :raises RuntimeError: If the configuration fails. - """ - - ssh = SSH() - ssh.connect(node) - - # Enable IPv6 for only the specified interface - cmd = "sudo sysctl net.ipv6.conf.{0}.disable_ipv6=0".format(interface) - - ret_code, _, _ = ssh.exec_command(cmd) - if ret_code != 0: - raise RuntimeError("Could not enable IPv6 on interface.") - - # Configure IPv6 address on the interface - cmd = "sudo ip address add {address}/{prefix} dev {interface}".format( - interface=interface, - address=address, - prefix=prefix) - - ret_code, _, _ = ssh.exec_command(cmd) - if ret_code != 0: - raise RuntimeError("Could not configure IP address on interface.") - - # Set the interface up - cmd = "sudo ip link set {interface} up".format(interface=interface) - - ret_code, _, _ = ssh.exec_command(cmd) - if ret_code != 0: - raise RuntimeError("Could not change the interface to 'up' state.") - - @staticmethod - def configure_control_interface_tunnel(node, src_port, dst_ip, dst_port): - """Configure a tunnel on the specified node, tunelling any IPv4 traffic - from one port to the specified address. - - :param node: Node in topology. - :param src_port: Port to tunnel traffic from. - :param dst_ip: IP address to tunnel traffic to. - :param dst_port: Port to tunnel traffic to. - :type node: dict - :type src_port: int - :type dst_ip: str - :type dst_port: int - :raises RuntimeError: If tunnel creation is not successful. - """ - - cmd = "nohup socat TCP4-LISTEN:{src_port},fork,su=nobody " \ - "TCP6:[{dst_ip}]:{dst_port} $@ > " \ - "/tmp/socat.log 2>&1 &".format( - src_port=src_port, - dst_ip=dst_ip, - dst_port=dst_port) - - ssh = SSH() - ssh.connect(node) - ret_code, _, _ = ssh.exec_command_sudo(cmd) - if ret_code != 0: - raise RuntimeError("Could not configure tunnel.") diff --git a/resources/libraries/python/honeycomb/Lisp.py b/resources/libraries/python/honeycomb/Lisp.py deleted file mode 100644 index 6ff6f834cc..0000000000 --- a/resources/libraries/python/honeycomb/Lisp.py +++ /dev/null @@ -1,671 +0,0 @@ -# Copyright (c) 2018 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""This module implements keywords to manipulate LISP data structures using -Honeycomb REST API.""" - -from resources.libraries.python.HTTPRequest import HTTPCodes -from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError -from resources.libraries.python.honeycomb.HoneycombUtil \ - import HoneycombUtil as HcUtil -from resources.libraries.python.honeycomb.HoneycombUtil \ - import DataRepresentation -from resources.libraries.python.topology import Topology - - -class LispKeywords(object): - """Implementation of keywords which make it possible to: - - enable/disable LISP feature - - configure LISP mappings - - configure locator sets - - configure map resolver - - configure LISP PITR feature - - read operational data for all of the above - """ - - def __init__(self): - """Initializer.""" - pass - - @staticmethod - def _set_lisp_properties(node, path, data=None): - """Set LISP 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 or 201 = ACCEPTED. - """ - - if data: - status_code, resp = HcUtil.\ - put_honeycomb_data(node, "config_lisp", data, path, - data_representation=DataRepresentation.JSON) - else: - status_code, resp = HcUtil.\ - delete_honeycomb_data(node, "config_lisp", path) - - if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): - raise HoneycombError( - "Lisp configuration unsuccessful. " - "Status code: {0}.".format(status_code)) - else: - return resp - - @staticmethod - def get_lisp_operational_data(node): - """Retrieve Lisp properties from Honeycomb operational data. - - :param node: Honeycomb node. - :type node: dict - :returns: List operational data. - :rtype: bytearray - """ - - status_code, resp = HcUtil.get_honeycomb_data(node, "oper_lisp") - - if status_code != HTTPCodes.OK: - raise HoneycombError("Could not retrieve LISP operational data." - "Status code: {0}.".format(status_code)) - else: - # get rid of empty vni-table entry - resp["lisp-state"]["lisp-feature-data"]["eid-table"][ - "vni-table"].remove( - { - "virtual-network-identifier": 0, - "vrf-subtable": {"table-id": 0} - } - ) - return resp - - @staticmethod - def verify_map_server_data_from_honeycomb(data, ip_addresses): - """Verify whether MAP server data from Honeycomb is correct. - - :param data: LISP operational data containing map server IP addresses. - :param ip_addresses: IP addresses to verify map server data against. - :type data: dict - :type ip_addresses: list - :returns: Boolean Value indicating equality of IP Lists. - :rtype: bool - """ - - data =\ - data['lisp-state']['lisp-feature-data']['map-servers']['map-server'] - - data = sorted([entry['ip-address'] for entry in data]) - ip_addresses.sort() - - return data == ip_addresses - - @staticmethod - def verify_map_server_data_from_vat(data, ip_addresses): - """Verify whether MAP server data from VAT is correct. - - :param data: LISP operational data containing map server IP addresses. - :param ip_addresses: IP addresses to verify map server data against. - :type data: dict - :type ip_addresses: list - :returns: Boolean Value indicating equality of IP Lists. - :rtype: bool - """ - - data = sorted([entry['map-server'] for entry in data]) - ip_addresses.sort() - - return data == ip_addresses - - @staticmethod - def set_lisp_state(node, state=True): - """Enable or disable the LISP feature. - - :param node: Honeycomb node. - :param state: Enable or disable LISP. - :type node: dict - :type state: bool - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the return code is not 200:OK - or 404:NOT FOUND. - """ - - ret_code, data = HcUtil.get_honeycomb_data(node, "config_lisp") - if ret_code == HTTPCodes.OK: - data["lisp"]["enable"] = bool(state) - elif ret_code == HTTPCodes.NOT_FOUND: - data = {"lisp": {"enable": bool(state)}} - else: - raise HoneycombError("Unexpected return code when getting existing" - " LISP configuration.") - - return LispKeywords._set_lisp_properties(node, '', data) - - @staticmethod - def set_rloc_probe_state(node, state=False): - """Enable or disable the Routing Locator probe. - - :param node: Honeycomb node. - :param state: Enable or Disable the Rloc probe. - :type node: dict - :type state: bool - :returns: Content of response. - :rtype: bytearray - """ - - path = "/lisp-feature-data/rloc-probe" - - data = { - "rloc-probe": { - "enabled": bool(state) - } - } - - return LispKeywords._set_lisp_properties(node, path, data) - - @staticmethod - def add_locator(node, interface, locator_set, priority=1, weight=1): - """Configure a new LISP locator set. - - :param node: Honeycomb node. - :param interface: An interface on the node. - :param locator_set: Name for the new locator set. - :param priority: Priority parameter for the locator. - :param weight: Weight parameter for the locator. - :type node: dict - :type interface: str - :type locator_set: str - :type priority: int - :type weight: int - :returns: Content of response. - :rtype: bytearray - """ - - interface = Topology.convert_interface_reference( - node, interface, "name") - - path = "/lisp-feature-data/locator-sets/locator-set" \ - "/{0}".format(locator_set) - - data = { - "locator-set": { - "name": locator_set, - "interface": { - "interface-ref": interface, - "priority": priority, - "weight": weight - } - } - } - - return LispKeywords._set_lisp_properties(node, path, data) - - @staticmethod - def configure_lisp_mapping(node, data): - """Modify eid-table configuration to the data provided. - - :param node: Honeycomb node. - :param data: Settings for the LISP mappings. - :type node: dict - :type data: dict - :returns: Content of response. - :rtype: bytearray - """ - - path = "/lisp-feature-data/eid-table" - return LispKeywords._set_lisp_properties(node, path, data) - - @staticmethod - def configure_lisp_map_request_mode(node, option): - """Modify LISP Map Request Mode configuration to the data provided. - - :param node: Honeycomb node. - :param option: Settings for the LISP map request mode. - :type node: dict - :type option: str - :returns: Content of response. - :rtype: bytearray - """ - - data = { - "map-request-mode": { - "mode": option - } - } - - path = "/lisp-feature-data/map-request-mode" - return LispKeywords._set_lisp_properties(node, path, data) - - @staticmethod - def add_lisp_adjacency(node, vni_id, map_name, adjacency_name, data): - """Add an adjacency to an existing LISP mapping. - - :param node: Honeycomb node. - :param vni_id: vni_id of the mapping. - :param map_name: Name of the mapping. - :param adjacency_name: Name for the new adjacency. - :param data: Adjacency settings. - :type node: dict - :type vni_id: int - :type map_name: str - :type adjacency_name: str - :type data: dict - :returns: Content of response. - :rtype: bytearray - """ - - path = ( - "/lisp-feature-data/eid-table/vni-table/{vni_id}/" - "vrf-subtable/remote-mappings/remote-mapping/{map_name}/" - "adjacencies/adjacency/{adjacency_name}" - ) - path = path.format( - vni_id=vni_id, - map_name=map_name, - adjacency_name=adjacency_name - ) - - return LispKeywords._set_lisp_properties(node, path, data) - - @staticmethod - def add_map_resolver(node, ip_address): - """Configure map resolver with the specified IP address. - - :param node: Honeycomb node. - :param ip_address: IP address to configure map resolver with. - :type node: dict - :type ip_address: str - :returns: Content of response. - :rtype: bytearray - """ - - path = "/lisp-feature-data/map-resolvers/map-resolver/{0}".format( - ip_address) - - data = { - "map-resolver": { - "ip-address": ip_address - } - } - - return LispKeywords._set_lisp_properties(node, path, data) - - @staticmethod - def set_map_register(node, map_register=False): - """Configure Map Register. - - :param node: Honeycomb node. - :param map_register: Enable or disable Map Register. - :type node: dict - :type map_register: bool - :returns: Content of response. - :rtype: bytearray - """ - - path = "/lisp-feature-data/map-register" - - data = { - "map-register": { - "enabled": bool(map_register) - } - } - - return LispKeywords._set_lisp_properties(node, path, data) - - @staticmethod - def set_map_request_mode(node, src_dst=False): - """Configure Map Request Mode. - - :param node: Honeycomb node. - :param src_dst: Configure Map Request Mode with source destination. - :type node: dict - :type src_dst: bool - :returns: Content of response. - :rtype: bytearray - """ - - path = "/lisp-feature-data/map-request-mode" - - data = { - "map-request-mode": { - "mode": "source-destination" if src_dst - else "target-destination" - } - } - - return LispKeywords._set_lisp_properties(node, path, data) - - @staticmethod - def delete_map_resolver(node): - """Delete an existing map resolver. - - :param node: Honeycomb node - :type node: dict - :returns: Content of response - :rtype: bytearray - """ - - path = "/lisp-feature-data/map-resolvers" - - return LispKeywords._set_lisp_properties(node, path) - - @staticmethod - def add_map_server(node, *ip_addresses): - """Configure map server with the specified IP addresses. - - :param node: Honeycomb node. - :param ip_addresses: IP addresses to configure map server with. - :type node: dict - :type ip_addresses: list - :returns: Content of response. - :rtype: bytearray - """ - - path = "/lisp-feature-data/map-servers" - - data = { - "map-servers": { - "map-server": [ - {"ip-address": ip_address} for ip_address in ip_addresses - ] - } - } - - return LispKeywords._set_lisp_properties(node, path, data) - - @staticmethod - def delete_map_server(node): - """Delete all map servers. - - :param node: Honeycomb node - :type node: dict - :returns: Content of response - :rtype: bytearray - """ - - path = "/lisp-feature-data/map-servers" - - return LispKeywords._set_lisp_properties(node, path) - - @staticmethod - def configure_pitr(node, locator_set=None): - """Configure PITR feature with the specified locator set. If not locator - set is specified, disable PITR instead. - - :param node: Honeycomb node. - :param locator_set: Name of a locator set. Optional. - :type node: dict - :type locator_set: str - :returns: Content of response. - :rtype: bytearray - """ - - path = "/lisp-feature-data/pitr-cfg" - - if locator_set: - data = { - "pitr-cfg": { - "locator-set": locator_set - } - } - else: - data = None - - return LispKeywords._set_lisp_properties(node, path, data) - - @staticmethod - def configure_petr(node, ip_address): - """Configure PETR feature with the specified IP. If no IP - specified, disable PETR instead. - - :param node: Honeycomb node. - :param ip_address: IPv6 address. - :type node: dict - :type ip_address: str - :returns: Content of response. - :rtype: bytearray - """ - - path = "/lisp-feature-data/petr-cfg" - - if ip_address: - data = { - "petr-cfg": { - "petr-address": ip_address - } - } - else: - data = None - - return LispKeywords._set_lisp_properties(node, path, data) - - @staticmethod - def disable_lisp(node): - """Remove all LISP settings on the node. - - :param node: Honeycomb node. - :type node: dict - :returns: Content of response. - :rtype: bytearray - """ - - return LispKeywords._set_lisp_properties(node, "") - - -class LispGPEKeywords(object): - """Implementation of keywords which make it possible to: - - enable/disable LISP GPE feature - - configure LISP GPE forwarding entries - - read operational data for all of the above - """ - - def __init__(self): - """Initializer.""" - pass - - @staticmethod - def _set_lispgpe_properties(node, path, data=None): - """Set LISP GPE 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 or 201 = ACCEPTED. - """ - - if data: - status_code, resp = HcUtil.\ - put_honeycomb_data(node, "config_lisp_gpe", data, path, - data_representation=DataRepresentation.JSON) - else: - status_code, resp = HcUtil.\ - delete_honeycomb_data(node, "config_lisp_gpe", path) - - if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): - raise HoneycombError( - "Lisp GPE configuration unsuccessful. " - "Status code: {0}.".format(status_code)) - else: - return resp - - @staticmethod - def get_lispgpe_operational_data(node): - """Retrieve LISP GPE properties from Honeycomb operational data. - - :param node: Honeycomb node. - :type node: dict - :returns: LISP GPE operational 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, "oper_lisp_gpe") - - if status_code != HTTPCodes.OK: - raise HoneycombError("Could not retrieve Lisp GPE operational data." - "Status code: {0}.".format(status_code)) - else: - return resp - - @staticmethod - 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 - - @staticmethod - 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 - - @staticmethod - def set_lispgpe_state(node, state=True): - """Enable or disable the LISP GPE feature. - - :param node: Honeycomb node. - :param state: Enable or disable LISP. - :type node: dict - :type state: bool - :returns: Content of response. - :rtype: bytearray - :raises HoneycombError: If the return code is not 200:OK - or 404:NOT FOUND. - """ - - ret_code, data = HcUtil.get_honeycomb_data(node, "config_lisp_gpe") - if ret_code == HTTPCodes.OK: - data["gpe"]["gpe-feature-data"]["enable"] = bool(state) - elif ret_code == HTTPCodes.NOT_FOUND: - data = {"gpe": {"gpe-feature-data": {"enable": bool(state)}}} - else: - raise HoneycombError("Unexpected return code when getting existing" - " Lisp GPE configuration.") - - return LispGPEKeywords._set_lispgpe_properties(node, '', data) - - @staticmethod - def configure_lispgpe_mapping(node, data=None): - """Modify LISP GPE mapping configuration to the data provided. - - :param node: Honeycomb node. - :param data: Settings for the LISP GPE mappings. - :type node: dict - :type data: dict - :returns: Content of response. - :rtype: bytearray - """ - - path = "/gpe-feature-data/gpe-entry-table" - if data: - data = {"gpe-entry-table": {"gpe-entry": data}} - return LispGPEKeywords._set_lispgpe_properties(node, path, data) - else: - return LispGPEKeywords._set_lispgpe_properties(node, path) - - @staticmethod - def add_lispgpe_mapping(node, name, data): - """Add the specified LISP GPE mapping. - - :param node: Honeycomb node. - :param name: Name for the mapping. - :param data: Mapping details. - :type node: dict - :type name: str - :type data: dict - :returns: Content of response. - :rtype: bytearray - """ - - path = "/gpe-feature-data/gpe-entry-table/gpe-entry/{name}".format( - name=name) - - data = {"gpe-entry": data} - return LispGPEKeywords._set_lispgpe_properties(node, path, data) - - @staticmethod - def delete_lispgpe_mapping(node, mapping): - """Delete the specified LISP GPE mapping from configuration. - - :param node: Honeycomb node. - :param mapping: Name of the mapping to remove. - :type node: dict - :type mapping: str - :returns: Content of response. - :rtype: bytearray - """ - - path = "/gpe-feature-data/gpe-entry-table/gpe-entry/{0}".format(mapping) - return LispGPEKeywords._set_lispgpe_properties(node, path) - - @staticmethod - def disable_lispgpe(node): - """Remove all LISP GPE settings on the node. - - :param node: Honeycomb node. - :type node: dict - :returns: Content of response. - :rtype: bytearray - """ - - return LispGPEKeywords._set_lispgpe_properties(node, "") diff --git a/resources/libraries/python/honeycomb/NAT.py b/resources/libraries/python/honeycomb/NAT.py deleted file mode 100644 index 759b801026..0000000000 --- a/resources/libraries/python/honeycomb/NAT.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright (c) 2018 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Keywords to manipulate NAT configuration using Honeycomb REST API.""" - -from resources.libraries.python.topology import Topology -from resources.libraries.python.HTTPRequest import HTTPCodes -from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError -from resources.libraries.python.honeycomb.HoneycombUtil \ - import DataRepresentation -from resources.libraries.python.honeycomb.HoneycombUtil \ - import HoneycombUtil as HcUtil - - -class NATKeywords(object): - """Keywords for NAT configuration.""" - - def __init__(self): - pass - - @staticmethod - def _set_nat_properties(node, path, data=None): - """Set NAT 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 - OK or ACCEPTED. - """ - - if data: - status_code, resp = HcUtil. \ - put_honeycomb_data(node, "config_nat", data, path, - data_representation=DataRepresentation.JSON) - else: - status_code, resp = HcUtil. \ - delete_honeycomb_data(node, "config_nat", path) - - if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): - raise HoneycombError( - "The configuration of NAT was not successful. " - "Status code: {0}.".format(status_code)) - return resp - - @staticmethod - 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" not in resp.keys(): - raise HoneycombError( - "Unexpected format, response does not contain nat container.") - return resp['nat'] - - @staticmethod - def configure_nat_entries(node, data, instance=0, entry=1): - """Configure NAT entries on node. - - :param node: Honeycomb node. - :param data: Data to be configured on node. - :param instance: NAT instance ID. - :param entry: NAT entry index. - :type node: dict - :type data: dict - :type instance: int - :type entry: int - :returns: Content of response. - :rtype: bytearray - """ - - return NATKeywords._set_nat_properties( - node, - '/instances/instance/{0}/' - 'mapping-table/mapping-entry/{1}/'.format(instance, entry), - data) - - @staticmethod - def configure_nat_on_interface(node, interface, direction, delete=False): - """Configure NAT on the specified interface. - - :param node: Honeycomb node. - :param interface: Name of an interface on the node. - :param direction: NAT direction, outbound or inbound. - :param delete: Delete an existing interface NAT configuration. - :type node: dict - :type interface: str - :type direction: str - :type delete: bool - :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}/interface-nat:nat/{1}".format( - interface, direction) - - data = {direction: {}} - - if delete: - status_code, resp = HcUtil.delete_honeycomb_data( - node, "config_vpp_interfaces", path) - else: - status_code, resp = HcUtil.put_honeycomb_data( - node, "config_vpp_interfaces", data, path) - - if status_code not in (HTTPCodes.OK, HTTPCodes.ACCEPTED): - raise HoneycombError( - "Could not configure NAT on interface. " - "Status code: {0}.".format(status_code)) - - return resp diff --git a/resources/libraries/python/honeycomb/Netconf.py b/resources/libraries/python/honeycomb/Netconf.py deleted file mode 100644 index caca14ed1a..0000000000 --- a/resources/libraries/python/honeycomb/Netconf.py +++ /dev/null @@ -1,166 +0,0 @@ -# Copyright (c) 2019 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Keywords used to connect to Honeycomb through Netconf, send messages - and receive replies.""" - -import socket -from time import time - -import paramiko -from robot.api import logger - -from resources.libraries.python.honeycomb.HoneycombUtil import HoneycombError - - -class Netconf(object): - """Implements methods for creating and managing Netconf sessions.""" - - def __init__(self, delimiter=']]>]]>'): - """Initializer. - - Note: Passing the channel object as a robotframework argument closes - the channel. Class variables are used instead, - to persist the connection channel throughout test cases. - """ - - self.client = None - self.channel = None - self.delimiter = delimiter - - def create_session(self, node, hello, time_out=10): - """Create an SSH session, connect to Honeycomb on the specified node, - open a communication channel to the Netconf subsystem and exchange hello - messages. - - :param node: Honeycomb node. - :param hello: Hello message and capability list to be sent to Honeycomb. - :param time_out: Timeout value for the connection in seconds. - :type node: dict - :type hello: str - :type time_out: int - """ - - start = time() - client = paramiko.SSHClient() - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - - client.connect(node['host'], - username=node['honeycomb']['user'], - password=node['honeycomb']['passwd'], - pkey=None, - port=node['honeycomb']['netconf_port'], - timeout=time_out) - - logger.trace('Connect took {0} seconds'.format(time() - start)) - logger.debug('New ssh: {0}'.format(client)) - logger.debug('Connect peer: {0}'. - format(client.get_transport().getpeername())) - logger.debug(client) - - channel = client.get_transport().open_session() - channel.settimeout(time_out) - channel.set_combine_stderr(True) - channel.get_pty() - channel.invoke_subsystem("netconf") - logger.debug(channel) - - self.client = client - self.channel = channel - - # read OpenDaylight's hello message and capability list - self.get_response( - size=131072, - err="Timeout on getting hello message." - ) - - self.channel.send(hello) - if not self.channel.active: - raise HoneycombError("Channel closed on capabilities exchange.") - - def get_response(self, size=4096, err="Unspecified Error."): - """Iteratively read data from the receive buffer and catenate together - until message ends with the message delimiter, or - until timeout is reached. - - :param size: Maximum number of bytes to read in one iteration. - :param err: Error message to provide when timeout is reached. - :type size: int - :type err: str - :returns: Content of response. - :rtype: str - :raises HoneycombError: If the read process times out. - """ - - reply = '' - - try: - while not reply.endswith(self.delimiter) or \ - self.channel.recv_ready(): - try: - chunk = self.channel.recv(size) - if not chunk: - break - reply += chunk - if self.channel.exit_status_ready(): - logger.debug('Channel exit status ready.') - break - except socket.timeout: - raise HoneycombError("Socket timeout.", - enable_logging=False) - - except RuntimeError: - raise HoneycombError(err + " Content of buffer: {0}".format(reply), - enable_logging=False) - - logger.trace(reply) - return reply.replace(self.delimiter, "") - - def get_all_responses(self, size=4096): - """Read responses from the receive buffer and catenate together - until a read operation times out. - - :param size: Maximum number of bytes to read in one iteration. - :type size: int - :returns: Content of response. - :rtype: str - """ - - response = "" - err = "Expected timeout occurred." - - while True: - try: - response += self.get_response(size, err) - except HoneycombError: - break - - return response - - def send(self, message, **params): - """Sends provided message through the channel. - - :param message: Message to be sent to Honeycomb. - :param params: Format the message string with these parameters. - :type message: str - :type params: dict - """ - - message = message.format(**params) - - if not message.endswith(self.delimiter): - message += self.delimiter - - logger.debug(message) - - self.channel.send(message) diff --git a/resources/libraries/python/honeycomb/Notifications.py b/resources/libraries/python/honeycomb/Notifications.py deleted file mode 100644 index 38f1fd3093..0000000000 --- a/resources/libraries/python/honeycomb/Notifications.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright (c) 2019 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Implementation of keywords for managing Honeycomb notifications.""" - -from robot.api import logger - -from resources.libraries.python.honeycomb.HoneycombUtil import HoneycombError -from resources.libraries.python.honeycomb.Netconf import Netconf - - -class Notifications(Netconf): - """Implements keywords for receiving Honeycomb notifications. - - The keywords implemented in this class make it possible to: - - receive notifications from Honeycomb - - read received notifications - """ - - def add_notification_listener(self, subscription): - """Open a new channel on the SSH session, connect to Netconf subsystem - and subscribe to receive Honeycomb notifications. - - :param subscription: RPC for subscription to notifications. - :type subscription: str - :raises HoneycombError: If subscription to notifications fails. - """ - - logger.debug(subscription) - self.send(subscription) - - reply = self.get_response( - err="Timeout on notifications subscription." - ) - - if "<ok/>" not in reply: - raise HoneycombError("Notifications subscription failed with" - " message: {0}".format(reply)) - - logger.debug("Notifications subscription successful.") - - def get_notification(self, time_out=10): - """Read and return the next notification message. - - :param time_out: Timeout value for the read operation in seconds. - :type time_out: int - :returns: Data received from buffer. - :rtype: str - """ - - logger.debug("Getting notification. Timeout set to {0} seconds." - .format(time_out)) - - reply = self.get_response( - err="Timeout on getting notification." - ) - - return reply diff --git a/resources/libraries/python/honeycomb/Performance.py b/resources/libraries/python/honeycomb/Performance.py deleted file mode 100644 index b81b9fd3db..0000000000 --- a/resources/libraries/python/honeycomb/Performance.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright (c) 2018 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Implementation of keywords for testing Honeycomb performance.""" - -from resources.libraries.python.ssh import SSH -from resources.libraries.python.Constants import Constants as Const -from resources.libraries.python.honeycomb.HoneycombUtil import HoneycombError - - -class Performance(object): - """Keywords used in Honeycomb performance testing.""" - - def __init__(self): - """Initializer.""" - pass - - @staticmethod - def configure_netconf_threads(node, threads): - """Set Honeycomb's Netconf thread count in configuration. - - :param node: Honeycomb node. - :param threads: Number of threads. - :type node: dict - :type threads: int - :raises HoneycombError: If the operation fails. - """ - - find = "netconf-netty-threads" - replace = '\\"netconf-netty-threads\\": {0},'.format(threads) - - argument = '"/{0}/c\\ {1}"'.format(find, replace) - path = "{0}/config/netconf.json".format(Const.REMOTE_HC_DIR) - command = "sed -i {0} {1}".format(argument, path) - - ssh = SSH() - ssh.connect(node) - (ret_code, _, stderr) = ssh.exec_command_sudo(command) - if ret_code != 0: - raise HoneycombError("Failed to modify configuration on " - "node {0}, {1}".format(node, stderr)) - - @staticmethod - def run_traffic_script_on_dut(node, script, cores, reserved=2, - *args, **kwargs): - """Copy traffic script over to the specified node and execute with - the provided arguments. - - :param node: Node in topology. - :param script: Name of the script to execute. - :param cores: Number of processor cores to use. - :param reserved: Number of cores reserved for other tasks. Default is 2, - one for system tasks and one for VPP main thread. - :param args: Sequential arguments for the script. - :param kwargs: Named arguments for the script. - :type node: dict - :type script: str - :type cores: int - :type reserved: int - :type args: list - :type kwargs: dict - """ - - path = "resources/traffic_scripts/honeycomb/{0}".format(script) - - # Assemble arguments for traffic script - arguments = "" - for arg in args: - arguments += "{0} ".format(arg) - - for key, value in kwargs.items(): - arguments += "--{0} {1} ".format(key, value) - - ssh = SSH() - ssh.connect(node) - ssh.scp(path, "/tmp") - - # Use alternate scheduler, Ubuntu's default can't load-balance - # over isolcpus - scheduler = "chrt -f 99" - core_afi = "taskset -c {first}-{last}".format( - first=reserved, last=cores-1) - - cmd = "{scheduler} {affinity} python /tmp/{script} {args}".format( - scheduler=scheduler, - affinity=core_afi, - script=script, - args=arguments) - - ret_code, stdout, _ = ssh.exec_command_sudo(cmd, timeout=600) - - ssh.exec_command("sudo pkill python ; rm /tmp/{0}".format(script)) - if ret_code != 0: - raise HoneycombError("Traffic script failed to execute.") - for line in stdout.splitlines(): - if "Avg. requests" in line: - return line - - @staticmethod - def log_core_schedule(node, process): - """Determine which cores the process' threads are running on. - - :param node: Honeycomb node. - :param process: Name of the process. - :type node: dict - :type process: str - """ - - # Get info on process and all of its children - cmd1 = """cat /proc/`pidof {0}`/task/*/stat""".format(process) - - # Parse process ID, name and core index - cmd2 = """awk '{print $1" "$2" "$39}'""" - - cmd = "{0} | {1}".format(cmd1, cmd2) - - ssh = SSH() - ssh.connect(node) - ssh.exec_command(cmd) diff --git a/resources/libraries/python/honeycomb/ProxyARP.py b/resources/libraries/python/honeycomb/ProxyARP.py deleted file mode 100644 index adc525d279..0000000000 --- a/resources/libraries/python/honeycomb/ProxyARP.py +++ /dev/null @@ -1,232 +0,0 @@ -# Copyright (c) 2018 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""This module implements keywords to configure proxyARP using Honeycomb -REST API.""" - -from resources.libraries.python.HTTPRequest import HTTPCodes -from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError -from resources.libraries.python.honeycomb.HoneycombUtil \ - import HoneycombUtil as HcUtil -from resources.libraries.python.honeycomb.HoneycombUtil \ - import DataRepresentation -from resources.libraries.python.topology import Topology - - -class ProxyARPKeywords(object): - """Implementation of keywords which make it possible to: - - configure proxyARP behaviour - - enable/disable proxyARP on individual interfaces - """ - - def __init__(self): - """Initializer.""" - pass - - @staticmethod - 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 - - @staticmethod - 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 - - @staticmethod - def get_proxyarp_operational_data(node): - """Retrieve proxyARP properties from Honeycomb operational data. - Note: The proxyARP feature has no operational data available. - - :param node: Honeycomb node. - :type node: dict - :returns: proxyARP operational data. - :rtype: bytearray - """ - - raise NotImplementedError("Not supported in VPP.") - - @staticmethod - 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"])) - - @staticmethod - def get_proxyarp_interface_assignment(node, interface): - """Read the status of proxyARP feature on the specified interface. - Note: The proxyARP feature has no operational data available. - - :param node: Honeycomb node. - :param interface: Name or sw_if_index of an interface on the node. - :type node: dict - :type interface: str - :returns: Content of response. - :rtype: bytearray - """ - - raise NotImplementedError("Not supported in VPP.") - - -class IPv6NDProxyKeywords(object): - """Keywords for IPv6 Neighbor Discovery proxy configuration.""" - - def __init__(self): - pass - - @staticmethod - 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 - - @staticmethod - 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 diff --git a/resources/libraries/python/honeycomb/Routing.py b/resources/libraries/python/honeycomb/Routing.py deleted file mode 100644 index 314c3fe64d..0000000000 --- a/resources/libraries/python/honeycomb/Routing.py +++ /dev/null @@ -1,328 +0,0 @@ -# Copyright (c) 2018 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""This module implements keywords to manipulate routing tables using -Honeycomb REST API.""" - -from robot.api import logger - -from resources.libraries.python.topology import Topology -from resources.libraries.python.HTTPRequest import HTTPCodes -from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError -from resources.libraries.python.honeycomb.HoneycombUtil \ - import HoneycombUtil as HcUtil -from resources.libraries.python.honeycomb.HoneycombUtil \ - import DataRepresentation -from resources.libraries.python.VatExecutor import VatTerminal - - -class RoutingKeywords(object): - """Implementation of keywords which make it possible to: - - add/remove routing tables, - - add/remove routing table entries - - get operational data about routing tables, - """ - - def __init__(self): - pass - - @staticmethod - def _set_routing_table_properties(node, path, data=None): - """Set routing 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 is not - 200 = OK. - """ - - if data: - status_code, resp = HcUtil.\ - put_honeycomb_data(node, "config_routing_table", data, path, - data_representation=DataRepresentation.JSON) - else: - status_code, resp = HcUtil.\ - delete_honeycomb_data(node, "config_routing_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 routing table was not successful. " - "Status code: {0}.".format(status_code)) - return resp - - @staticmethod - def configure_routing_table(node, name, ip_version, data, vrf=1, - special=False): - """Configure a routing table according to the data provided. - - :param node: Honeycomb node. - :param name: Name for the table. - :param ip_version: IP protocol version, ipv4 or ipv6. - :param data: Route configuration that should be set. - :param vrf: vrf-id to attach configuration to. - :param special: Must be True if the configuration is a special route. - :type node: dict - :type name: str - :type ip_version: str - :type data: dict - :type vrf: int - :type special: bool - :returns: Content of response. - :rtype: bytearray - """ - if special: - ip_version = "hc2vpp-ietf-{0}-unicast-routing:{0}".format( - ip_version) - protocol = "vpp-routing:vpp-protocol-attributes" - else: - ip_version = ip_version - protocol = "vpp-protocol-attributes" - - full_data = { - "control-plane-protocol": [ - { - "name": name, - "description": "hc2vpp-csit test route", - "type": "static", - protocol: { - "primary-vrf": vrf - }, - "static-routes": { - ip_version: { - "route": data - } - } - } - ] - } - - path = "/control-plane-protocol/hc2vpp-ietf-routing:static/{0}".format( - name) - return RoutingKeywords._set_routing_table_properties( - node, path, full_data) - - @staticmethod - def delete_routing_table(node, name): - """Delete the specified routing table from configuration data. - - :param node: Honeycomb node. - :param name: Name of the table. - :type node: dict - :type name: str - :returns: Content of response. - :rtype: bytearray - """ - - path = "/control-plane-protocol/hc2vpp-ietf-routing:static/{0}".format( - name) - return RoutingKeywords._set_routing_table_properties(node, path) - - @staticmethod - 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 = "/control-plane-protocol/hc2vpp-ietf-routing:static/{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 " - "routing tables. Status code: {0}.".format(status_code)) - - data = RoutingKeywords.clean_routing_oper_data( - resp['control-plane-protocol'][0]['static-routes'] - ['hc2vpp-ietf-{0}-unicast-routing:{0}'.format(ip_version)]['route']) - - return data - - @staticmethod - def clean_routing_oper_data(data): - """Prepare received routing operational data to be verified against - expected data. - - :param data: Routing operational data. - :type data: list - :returns: Routing operational data without entry ID numbers. - :rtype: list - """ - - for item in data: - # ID values are auto-incremented based on existing routes in VPP - item.pop("id", None) - if "next-hop-list" in item.keys(): - for item2 in item["next-hop-list"]["next-hop"]: - item2.pop("id", None) - - if "next-hop-list" in item.keys(): - # List items come in random order - item["next-hop-list"]["next-hop"].sort() - - return data - - @staticmethod - def log_routing_configuration(node): - """Retrieve route configuration using VAT and print the response - to robot log. - - :param node: VPP node. - :type node: dict - """ - - with VatTerminal(node) as vat: - vat.vat_terminal_exec_cmd("ip_fib_dump") - - @staticmethod - 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)) - - @staticmethod - 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 + '/ipv6/ipv6-router-advertisements' - - 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[ - 'hc2vpp-ietf-ipv6-unicast-routing:ipv6-router-advertisements'] - return {k: str(v) for k, v in dict_of_str.items()} - except (KeyError, TypeError): - return {} - - @staticmethod - 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)) - - @staticmethod - def get_policer_oper_data(node, policy_name): - """Get operational data about Policer on the node. - - :param node: Honeycomb node. - :type node: dict - :returns: dict of Policer operational data. - :rtype: dict - :raises HoneycombError: If status code differs from successful. - """ - - path = '/' + policy_name - - status_code, resp = HcUtil.\ - get_honeycomb_data(node, "oper_policer", path) - - if status_code != HTTPCodes.OK: - raise HoneycombError( - "Not possible to get operational information about Policer. " - "Status code: {0}.".format(status_code)) - try: - return resp['policer'] - except (KeyError, TypeError): - return {} diff --git a/resources/libraries/python/honeycomb/__init__.py b/resources/libraries/python/honeycomb/__init__.py deleted file mode 100644 index c35326d604..0000000000 --- a/resources/libraries/python/honeycomb/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2016 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: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -__init__ file for directory resources/libraries/python/honeycomb -""" |