diff options
author | selias <samelias@cisco.com> | 2017-10-09 16:36:16 +0200 |
---|---|---|
committer | Tibor Frank <tifrank@cisco.com> | 2017-11-08 13:26:45 +0000 |
commit | 56dd61dee872da788e578129eed48a3158a5b566 (patch) | |
tree | 4f56e96f06f78a8180c800eceabc56ce7046b4f5 /resources/libraries | |
parent | 2b8547bc50fd06ea936f096794b8c2a5e09c5f8b (diff) |
CSIT-811 HC Test: BGP functional tests
Added traffic tests for Honeycomb's BGP feature.
Change-Id: I5fa99908ab61d8bc9d2975e451917b98571b6aca
Signed-off-by: selias <samelias@cisco.com>
Diffstat (limited to 'resources/libraries')
-rw-r--r-- | resources/libraries/python/honeycomb/BGP.py | 107 | ||||
-rw-r--r-- | resources/libraries/python/honeycomb/HoneycombSetup.py | 32 | ||||
-rw-r--r-- | resources/libraries/robot/honeycomb/bgp.robot | 86 |
3 files changed, 213 insertions, 12 deletions
diff --git a/resources/libraries/python/honeycomb/BGP.py b/resources/libraries/python/honeycomb/BGP.py index ca50cc3120..75dce762ff 100644 --- a/resources/libraries/python/honeycomb/BGP.py +++ b/resources/libraries/python/honeycomb/BGP.py @@ -13,6 +13,7 @@ """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 \ @@ -27,6 +28,7 @@ class BGPKeywords(object): """ def __init__(self): + """Initializer.""" pass @staticmethod @@ -41,7 +43,7 @@ class BGPKeywords(object): :type data: dict :returns: Content of response. :rtype: bytearray - :raises HoneycombError: If the status code in response on PUT is not + :raises HoneycombError: If the status code in response to PUT is not 200 = OK or 201 = ACCEPTED. """ @@ -69,7 +71,7 @@ class BGPKeywords(object): :type data: dict :returns: Content of response. :rtype: bytearray - :raises HoneycombError: If the status code in response on PUT is not + :raises HoneycombError: If the status code in response to PUT is not 200 = OK or 201 = ACCEPTED. """ @@ -93,6 +95,7 @@ class BGPKeywords(object): :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. \ @@ -104,21 +107,29 @@ class BGPKeywords(object): return resp @staticmethod - def get_bgp_peer(node, address): + 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, "config_bgp_peer", path) + get_honeycomb_data(node, url, path) if status_code != HTTPCodes.OK: raise HoneycombError( "Not possible to get configuration information about the BGP" @@ -211,7 +222,7 @@ class BGPKeywords(object): :type ip_version: str :returns: Content of response. :rtype: bytearray - :raises HoneycombError: If the operation fails. + :raises HoneycombError: If the status code in response is not 200 = OK. """ route_address = route_address.replace("/", "%2F") @@ -239,7 +250,7 @@ class BGPKeywords(object): def get_all_peer_routes(node, peer_address, ip_version): """Get all configured routes for the given BGP peer. - :param node: HOneycomb node. + :param node: Honeycomb node. :param peer_address: IP address of the peer. :param ip_version: IP protocol version. ipv4 or ipv6 :type node: dict @@ -247,7 +258,7 @@ class BGPKeywords(object): :type ip_version: str :returns: Content of response. :rtype: bytearray - :raises HoneycombError: If the operation fails. + :raises HoneycombError: If the status code in response is not 200 = OK. """ if ip_version.lower() == "ipv4": @@ -299,3 +310,85 @@ class BGPKeywords(object): .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.") diff --git a/resources/libraries/python/honeycomb/HoneycombSetup.py b/resources/libraries/python/honeycomb/HoneycombSetup.py index 7c3831ca04..d4175b13e4 100644 --- a/resources/libraries/python/honeycomb/HoneycombSetup.py +++ b/resources/libraries/python/honeycomb/HoneycombSetup.py @@ -61,12 +61,13 @@ class HoneycombSetup(object): HoneycombSetup.print_environment(nodes) - logger.console("\n(re)Starting Honeycomb service ...") - 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) @@ -89,13 +90,15 @@ class HoneycombSetup(object): :type nodes: list :raises HoneycombError: If Honeycomb failed to stop. """ - logger.console("\nShutting down Honeycomb service ...") 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) @@ -121,7 +124,8 @@ class HoneycombSetup(object): :raises HoneycombError: If Honeycomb fails to start. """ - logger.console("\n(re)Starting Honeycomb service ...") + logger.console( + "\n(re)Starting Honeycomb service on node {0}".format(node["host"])) cmd = "sudo service honeycomb restart" @@ -650,6 +654,26 @@ class HoneycombSetup(object): 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): diff --git a/resources/libraries/robot/honeycomb/bgp.robot b/resources/libraries/robot/honeycomb/bgp.robot index d4c2d6b0a2..aa96cc6538 100644 --- a/resources/libraries/robot/honeycomb/bgp.robot +++ b/resources/libraries/robot/honeycomb/bgp.robot @@ -16,6 +16,24 @@ | Library | resources.libraries.python.honeycomb.HcAPIKwInterfaces.InterfaceKeywords *** Keywords *** +| Configure BGP module +| | [Documentation] | Edit Honeycomb's configuration file for the BGP feature.\ +| | ... | Honeycomb needs to be restarted for the changes to take effect. +| | ... +| | ... | *Arguments:* +| | ... | - node - information about a DUT node. Type: dictionary +| | ... | - ip_address - IP address to bind BGP listener to. Type: string +| | ... | - port - Port number to bind BGP listener to. Type: integer +| | ... | - as_number - Autonomous System (AS) ID number. Type: integer +| | ... +| | ... | *Example:* +| | ... +| | ... | \| Configure BGP module \| ${nodes['DUT1']} \| 192.168.0.1 \| ${179} \ +| | ... | \| ${65000} \| +| | ... +| | [Arguments] | ${node} | ${ip_address} | ${port} | ${as_number} +| | Configure BGP base | ${node} | ${ip_address} | ${port} | ${as_number} + | No BGP peers should be configured | | [Documentation] | Uses Honeycomb API to read BGP configuration and checks | | ... | if there ary BGP peers conffigured. @@ -50,7 +68,7 @@ | | Add BGP Peer | ${node} | ${address} | ${data} | BGP Peer From Honeycomb Should be -| | [Documentation] | Uses Honeycomb API to verify BGP peer operational data. +| | [Documentation] | Uses Honeycomb API to verify BGP peer config data. | | ... | | ... | *Arguments:* | | ... | - node - Information about a DUT node. Type: dictionary @@ -67,6 +85,24 @@ | | ${oper_data}= | Get BGP Peer | ${node} | ${address} | | Compare Data Structures | ${oper_data} | ${data} +| Peer Operational Data From Honeycomb Should be +| | [Documentation] | Uses Honeycomb API to verify BGP peer operational data. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - address - IP address of the peer. Type: string +| | ... | - data - Peer configuration data. Type: dictionary +| | ... +| | ... | *Example:* +| | ... +| | ... | \| BGP Peer From Honeycomb Should be \ +| | ... | \| ${nodes['DUT1']} \| 192.168.0.1 \| ${data} \| +| | ... +| | [Arguments] | ${node} | ${address} +| | ... +| | ${oper_data}= | Get BGP Peer | ${node} | ${address} | operational +| | Should be Equal | ${oper_data['peer'][0]['peer-id']} | bgp://${address} + | Honeycomb removes BGP peer | | [Documentation] | Uses Honeycomb API to add a BGP peer. | | ... @@ -171,3 +207,51 @@ | | ${oper_data}= | Get All Peer Routes | | ... | ${node} | ${peer_address} | ${ip_version} | | Should be Empty | ${oper_data['bgp-inet:${ip_version}-routes']} + +| BGP Loc-RIB table should include +| | [Documentation] | Uses Honeycomb API to retrieve local BGP RIB table\ +| | ... | And verifies that it contains the specified entry. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - data - RIB that should be present in operational data.\ +| | ... | Type: dictionary +| | ... +| | ... | *Example:* +| | ... +| | ... | \| BGP Loc-RIB table should include \| ${nodes['DUT1']} \| ${data} \| +| | ... +| | [Arguments] | ${node} | ${data} +| | ... +| | ${oper_data}= | Get BGP Local RIB | ${node} +| | ${oper_data}= | Set Variable | ${oper_data['loc-rib']['tables']} +| | ${data}= | Set Variable | ${data['loc-rib']['tables']} +| | Compare RIB Tables | ${oper_data} | ${data} + +| Receive BGP OPEN message +| | [Documentation] | Open a TCP listener on BGP port(179) and listen\ +| | ... | for BGP OPEN message. Verify ID and holdtime fields. +| | ... +| | ... | *Arguments:* +| | ... | - tg_node - Information about the TG node. Type: dictionary +| | ... | - rx_ip - IP address to listen on. Type: string +| | ... | - src_ip - IP address of the BGP speaker. Also acts as BGP peer ID.\ +| | ... | Type: string +| | ... | - holdtime - Expected value of HOLD_TIME field in received message.\ +| | ... | Type: integer +| | ... +| | ... | *Example:* +| | ... +| | ... | \| Receive BGP OPEN message \| ${node['TG']} \ +| | ... | \| 192.168.0.1 \| 192.168.0.2 \| ${0} +| | ... +| | [Arguments] | ${tg_node} | ${rx_ip} | ${src_ip} | ${port} | ${as_number} +| | ... | ${holdtime} +| | ... +| | ${args}= | Catenate | --rx_ip | ${rx_ip} +| | ... | --src_ip | ${src_ip} +| | ... | --rx_port | ${port} +| | ... | --as_number | ${as_number} +| | ... | --holdtime | ${holdtime} +| | Run Traffic Script On Node | honeycomb/bgp_open.py +| | ... | ${tg_node} | ${args} |