]> git.proxmox.com Git - mirror_frr.git/commitdiff
tests: refactor parallel reset/load config for non-json
authorChristian Hopps <chopps@labn.net>
Sun, 5 Sep 2021 22:59:26 +0000 (18:59 -0400)
committerChristian Hopps <chopps@labn.net>
Mon, 6 Sep 2021 15:18:48 +0000 (11:18 -0400)
Refactor the bgp_auth test to create common_config code to allow
non-json based tests to reset routers and load configs in parallel.

Signed-off-by: Christian Hopps <chopps@labn.net>
tests/topotests/bgp_auth/test_bgp_auth.py
tests/topotests/conftest.py
tests/topotests/lib/common_config.py
tests/topotests/lib/topogen.py
tests/topotests/lib/topojson.py
tests/topotests/lib/topotest.py

index f32bc49f5834788173c20a8743a6ad9516864c4a..f01c7f206adaab6a54d84e4cb5eecca11e2d18e1 100644 (file)
@@ -40,85 +40,43 @@ test_bgp_auth.py: Test BGP Md5 Authentication
 setup is 3 routers with 3 links between each each link in a different vrf
 Default, blue and red respectively
 Tests check various fiddling with passwords and checking that the peer
-establishment is as expected and passwords are not leaked across sockets 
+establishment is as expected and passwords are not leaked across sockets
 for bgp instances
 """
+# pylint: disable=C0413
 
-import os
-import sys
 import json
+import os
 import platform
-import pytest
+import sys
 from time import sleep
 
-# Save the Current Working Directory to find configuration files.
-CWD = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.join(CWD, "../"))
-
-# pylint: disable=C0413
-# Import topogen and topotest helpers
-from lib import common_config
-from lib import topotest
-from lib.topogen import Topogen, TopoRouter, get_topogen
+import pytest
+from lib import common_config, topotest
 from lib.common_config import (
-    FRRCFG_FILE,
-    FRRCFG_BKUP_FILE,
-    load_config_to_routers,
-    reset_config_on_routers,
+    save_initial_config_on_routers,
+    reset_with_new_configs,
 )
-
-ERROR_LIST = ["Malformed", "Failure", "Unknown", "Incomplete"]
+from lib.topogen import Topogen, TopoRouter, get_topogen
 
 pytestmark = [pytest.mark.bgpd, pytest.mark.ospfd]
 
-
-def reload_new_configs(tgen, *cflist):
-    reset_config_on_routers(tgen)
-
-    routers = tgen.routers()
-    for rname, router in routers.items():
-        destname = "{}/{}/{}".format(tgen.logdir, rname, FRRCFG_FILE)
-        wmode="w"
-        for cfbase in cflist:
-            confname = os.path.join(CWD, "{}/{}".format(rname, cfbase))
-            with open(confname, "r") as cf:
-                with open(destname, wmode) as df:
-                    df.write(cf.read())
-            wmode="a"
-
-    # import pdb
-    # pdb.set_trace()
-    common_config.ROUTER_LIST = routers
-    load_config_to_routers(tgen, routers, save_bkup=False)
-
-
-class InvalidCLIError(Exception):
-    """Raise when the CLI command is wrong"""
+CWD = os.path.dirname(os.path.realpath(__file__))
 
 
 def build_topo(tgen):
-    # Create routers
     tgen.add_router("R1")
     tgen.add_router("R2")
     tgen.add_router("R3")
 
-    # R1-R2 1
     tgen.add_link(tgen.gears["R1"], tgen.gears["R2"])
-    # R1-R3 1
     tgen.add_link(tgen.gears["R1"], tgen.gears["R3"])
-    # R2-R3 1
     tgen.add_link(tgen.gears["R2"], tgen.gears["R3"])
-    # R1-R2 2
     tgen.add_link(tgen.gears["R1"], tgen.gears["R2"])
-    # R1-R3 2
     tgen.add_link(tgen.gears["R1"], tgen.gears["R3"])
-    # R2-R3 2
     tgen.add_link(tgen.gears["R2"], tgen.gears["R3"])
-    # R1-R2 3
     tgen.add_link(tgen.gears["R1"], tgen.gears["R2"])
-    # R1-R3 2
     tgen.add_link(tgen.gears["R1"], tgen.gears["R3"])
-    # R2-R3 2
     tgen.add_link(tgen.gears["R2"], tgen.gears["R3"])
 
 
@@ -202,26 +160,15 @@ def setup_module(mod):
 
     # For all registred routers, load the zebra configuration file
     for rname, router in router_list.items():
-        router.load_config(
-            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
-        )
-        router.load_config(
-            TopoRouter.RD_OSPF, os.path.join(CWD, "{}/empty.conf".format(rname))
-        )
-        router.load_config(
-            TopoRouter.RD_BGP, os.path.join(CWD, "{}/empty.conf".format(rname))
-        )
+        router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf")
+        router.load_config(TopoRouter.RD_OSPF)
+        router.load_config(TopoRouter.RD_BGP)
 
-    # After loading the configurations, this function loads configured daemons.
+    # After copying the configurations, this function loads configured daemons.
     tgen.start_router()
 
-    # Set the initial (saved) config to the zebra config. reset_config_on_routers
-    # will use this config to reset to.
-    routers = tgen.routers()
-    for rname, router in routers.items():
-        confname = os.path.join(CWD, "{}/zebra.conf".format(rname))
-        destname = "{}/{}/{}".format(tgen.logdir, rname, FRRCFG_BKUP_FILE)
-        router.cmd_raises("cp {} {}".format(confname, destname))
+    # Save the initial router config. reset_config_on_routers will return to this config.
+    save_initial_config_on_routers(tgen)
 
 
 def teardown_module(mod):
@@ -272,94 +219,30 @@ def print_diag(vrf):
         print(router.vtysh_cmd("show bgp {} neighbor".format(vrf_str(vrf))))
 
 
-def configure(conf_file):
-    "configure from a file"
-
-    tgen = get_topogen()
-    router_list = tgen.routers()
-    for rname, router in router_list.items():
-        with open(
-            os.path.join(CWD, "{}/{}").format(router.name, conf_file), "r+"
-        ) as cfg:
-            new_config = cfg.read()
-
-            output = router.vtysh_multicmd(new_config, pretty_output=False)
-            for out_err in ERROR_LIST:
-                if out_err.lower() in output.lower():
-                    raise InvalidCLIError("%s" % output)
-
-
-def clear_bgp():
-    "clear bgp configuration for a vrf"
-
-    tgen = get_topogen()
-    r1 = tgen.gears["R1"]
-    r2 = tgen.gears["R2"]
-    r3 = tgen.gears["R3"]
-
-    r1.vtysh_cmd("conf t\nno router bgp 65001")
-    r2.vtysh_cmd("conf t\nno router bgp 65002")
-    r3.vtysh_cmd("conf t\nno router bgp 65003")
-    r1.vtysh_cmd("conf t\nno router bgp 65001 vrf blue")
-    r2.vtysh_cmd("conf t\nno router bgp 65002 vrf blue")
-    r3.vtysh_cmd("conf t\nno router bgp 65003 vrf blue")
-    r1.vtysh_cmd("conf t\nno router bgp 65001 vrf red")
-    r2.vtysh_cmd("conf t\nno router bgp 65002 vrf red")
-    r3.vtysh_cmd("conf t\nno router bgp 65003 vrf red")
-
-
-def configure_bgp(conf_file):
-    "configure bgp from file"
-
-    clear_bgp()
-    configure(conf_file)
-
-
-def clear_ospf():
-    "clear ospf configuration for a vrf"
-
-    tgen = get_topogen()
-    router_list = tgen.routers()
-    for rname, router in router_list.items():
-        router.vtysh_cmd("conf t\nno router ospf")
-        router.vtysh_cmd("conf t\nno router ospf vrf blue")
-        router.vtysh_cmd("conf t\nno router ospf vrf red")
-
+@common_config.retry(retry_timeout=190)
+def _check_neigh_state(router, peer, state, vrf=""):
+    "check BGP neighbor state on a router"
 
-def configure_ospf(conf_file):
-    "configure bgp from file"
+    neigh_output = router.vtysh_cmd(
+        "show bgp {} neighbors {} json".format(vrf_str(vrf), peer)
+    )
 
-    clear_ospf()
-    configure(conf_file)
+    peer_state = "Unknown"
+    neigh_output_json = json.loads(neigh_output)
+    if peer in neigh_output_json:
+        peer_state = neigh_output_json[peer]["bgpState"]
+        if peer_state == state:
+            return True
+    return "{} peer with {} expected state {} got {} ".format(
+        router.name, peer, state, peer_state
+    )
 
 
 def check_neigh_state(router, peer, state, vrf=""):
     "check BGP neighbor state on a router"
 
-    count = 0
-    matched = False
-    neigh_output = ""
-    while count < 125:
-        if vrf == "":
-            neigh_output = router.vtysh_cmd("show bgp neighbors {} json".format(peer))
-        else:
-            neigh_output = router.vtysh_cmd(
-                "show bgp vrf {} neighbors {} json".format(vrf, peer)
-            )
-        neigh_output_json = json.loads(neigh_output)
-        if peer in neigh_output_json.keys():
-            if neigh_output_json[peer]["bgpState"] == state:
-                matched = True
-                break
-        count += 1
-        sleep(1)
-
-    assertmsg = "{} could not peer {} state expected {} got {} ".format(
-        router.name, peer, state, neigh_output_json[peer]["bgpState"]
-    )
-    if matched != True:
-        print_diag(vrf)
-    assert matched == True, assertmsg
+    assertmsg = _check_neigh_state(router, peer, state, vrf)
+    assert assertmsg is True, assertmsg
 
 
 def check_all_peers_established(vrf=""):
@@ -517,28 +400,21 @@ def check_vrf_peer_change_passwords(vrf="", prefix="no"):
 def test_default_peer_established(tgen):
     "default vrf 3 peers same password"
 
-    # configure_bgp("bgpd.conf")
-    # configure_ospf("ospfd.conf")
-    reload_new_configs(tgen, "bgpd.conf", "ospfd.conf")
+    reset_with_new_configs(tgen, "bgpd.conf", "ospfd.conf")
     check_all_peers_established()
-    # tgen.mininet_cli()
 
 
 def test_default_peer_remove_passwords(tgen):
     "selectively remove passwords checking state"
 
-    # configure_bgp("bgpd.conf")
-    # configure_ospf("ospfd.conf")
-    reload_new_configs(tgen, "bgpd.conf", "ospfd.conf")
+    reset_with_new_configs(tgen, "bgpd.conf", "ospfd.conf")
     check_vrf_peer_remove_passwords()
 
 
 def test_default_peer_change_passwords(tgen):
     "selectively change passwords checking state"
 
-    # configure_bgp("bgpd.conf")
-    # configure_ospf("ospfd.conf")
-    reload_new_configs(tgen, "bgpd.conf", "ospfd.conf")
+    reset_with_new_configs(tgen, "bgpd.conf", "ospfd.conf")
     check_vrf_peer_change_passwords()
 
 
@@ -549,11 +425,8 @@ def test_default_prefix_peer_established(tgen):
     if topotest.version_cmp(platform.release(), "5.3") < 0:
         return
 
-    # configure_bgp("bgpd_prefix.conf")
-    # configure_ospf("ospfd.conf")
-    reload_new_configs(tgen, "bgpd_prefix.conf", "ospfd.conf")
+    reset_with_new_configs(tgen, "bgpd_prefix.conf", "ospfd.conf")
     check_all_peers_established()
-    # tgen.mininet_cli()
 
 
 def test_prefix_peer_remove_passwords(tgen):
@@ -563,9 +436,7 @@ def test_prefix_peer_remove_passwords(tgen):
     if topotest.version_cmp(platform.release(), "5.3") < 0:
         return
 
-    # configure_bgp("bgpd_prefix.conf")
-    # configure_ospf("ospfd.conf")
-    reload_new_configs(tgen, "bgpd_prefix.conf", "ospfd.conf")
+    reset_with_new_configs(tgen, "bgpd_prefix.conf", "ospfd.conf")
     check_vrf_peer_remove_passwords(prefix="yes")
 
 
@@ -576,9 +447,7 @@ def test_prefix_peer_change_passwords(tgen):
     if topotest.version_cmp(platform.release(), "5.3") < 0:
         return
 
-    # configure_bgp("bgpd_prefix.conf")
-    # configure_ospf("ospfd.conf")
-    reload_new_configs(tgen, "bgpd_prefix.conf", "ospfd.conf")
+    reset_with_new_configs(tgen, "bgpd_prefix.conf", "ospfd.conf")
     check_vrf_peer_change_passwords(prefix="yes")
 
 
@@ -586,28 +455,21 @@ def test_vrf_peer_established(tgen):
     "default vrf 3 peers same password with VRF config"
 
     # clean routers and load vrf config
-    # configure_bgp("bgpd_vrf.conf")
-    # configure_ospf("ospfd_vrf.conf")
-    reload_new_configs(tgen, "bgpd_vrf.conf", "ospfd_vrf.conf")
+    reset_with_new_configs(tgen, "bgpd_vrf.conf", "ospfd_vrf.conf")
     check_all_peers_established("blue")
-    # tgen.mininet_cli()
 
 
 def test_vrf_peer_remove_passwords(tgen):
     "selectively remove passwords checking state with VRF config"
 
-    # configure_bgp("bgpd_vrf.conf")
-    # configure_ospf("ospfd_vrf.conf")
-    reload_new_configs(tgen, "bgpd_vrf.conf", "ospfd_vrf.conf")
+    reset_with_new_configs(tgen, "bgpd_vrf.conf", "ospfd_vrf.conf")
     check_vrf_peer_remove_passwords(vrf="blue")
 
 
 def test_vrf_peer_change_passwords(tgen):
     "selectively change passwords checking state with VRF config"
 
-    # configure_bgp("bgpd_vrf.conf")
-    # configure_ospf("ospfd_vrf.conf")
-    reload_new_configs(tgen, "bgpd_vrf.conf", "ospfd_vrf.conf")
+    reset_with_new_configs(tgen, "bgpd_vrf.conf", "ospfd_vrf.conf")
     check_vrf_peer_change_passwords(vrf="blue")
 
 
@@ -618,9 +480,7 @@ def test_vrf_prefix_peer_established(tgen):
     if topotest.version_cmp(platform.release(), "5.3") < 0:
         return
 
-    # configure_bgp("bgpd_vrf_prefix.conf")
-    # configure_ospf("ospfd_vrf.conf")
-    reload_new_configs(tgen, "bgpd_vrf_prefix.conf", "ospfd_vrf.conf")
+    reset_with_new_configs(tgen, "bgpd_vrf_prefix.conf", "ospfd_vrf.conf")
     check_all_peers_established("blue")
 
 
@@ -631,9 +491,7 @@ def test_vrf_prefix_peer_remove_passwords(tgen):
     if topotest.version_cmp(platform.release(), "5.3") < 0:
         return
 
-    # configure_bgp("bgpd_vrf_prefix.conf")
-    # configure_ospf("ospfd_vrf.conf")
-    reload_new_configs(tgen, "bgpd_vrf_prefix.conf", "ospfd_vrf.conf")
+    reset_with_new_configs(tgen, "bgpd_vrf_prefix.conf", "ospfd_vrf.conf")
     check_vrf_peer_remove_passwords(vrf="blue", prefix="yes")
 
 
@@ -644,47 +502,36 @@ def test_vrf_prefix_peer_change_passwords(tgen):
     if topotest.version_cmp(platform.release(), "5.3") < 0:
         return
 
-    # configure_bgp("bgpd_vrf_prefix.conf")
-    # configure_ospf("ospfd_vrf.conf")
-    reload_new_configs(tgen, "bgpd_vrf_prefix.conf", "ospfd_vrf.conf")
+    reset_with_new_configs(tgen, "bgpd_vrf_prefix.conf", "ospfd_vrf.conf")
     check_vrf_peer_change_passwords(vrf="blue", prefix="yes")
 
 
 def test_multiple_vrf_peer_established(tgen):
     "default vrf 3 peers same password with multiple VRFs"
 
-    # configure_bgp("bgpd_multi_vrf.conf")
-    # configure_ospf("ospfd_multi_vrf.conf")
-    reload_new_configs(tgen, "bgpd_multi_vrf.conf", "ospfd_multi_vrf.conf")
+    reset_with_new_configs(tgen, "bgpd_multi_vrf.conf", "ospfd_multi_vrf.conf")
     check_all_peers_established("blue")
     check_all_peers_established("red")
-    # tgen.mininet_cli()
 
 
 def test_multiple_vrf_peer_remove_passwords(tgen):
     "selectively remove passwords checking state with multiple VRFs"
 
-    # configure_bgp("bgpd_multi_vrf.conf")
-    # configure_ospf("ospfd_multi_vrf.conf")
-    reload_new_configs(tgen, "bgpd_multi_vrf.conf", "ospfd_multi_vrf.conf")
+    reset_with_new_configs(tgen, "bgpd_multi_vrf.conf", "ospfd_multi_vrf.conf")
     check_vrf_peer_remove_passwords("blue")
     check_all_peers_established("red")
     check_vrf_peer_remove_passwords("red")
     check_all_peers_established("blue")
-    # tgen.mininet_cli()
 
 
 def test_multiple_vrf_peer_change_passwords(tgen):
     "selectively change passwords checking state with multiple VRFs"
 
-    # configure_bgp("bgpd_multi_vrf.conf")
-    # configure_ospf("ospfd_multi_vrf.conf")
-    reload_new_configs(tgen, "bgpd_multi_vrf.conf", "ospfd_multi_vrf.conf")
+    reset_with_new_configs(tgen, "bgpd_multi_vrf.conf", "ospfd_multi_vrf.conf")
     check_vrf_peer_change_passwords("blue")
     check_all_peers_established("red")
     check_vrf_peer_change_passwords("red")
     check_all_peers_established("blue")
-    # tgen.mininet_cli()
 
 
 def test_multiple_vrf_prefix_peer_established(tgen):
@@ -694,12 +541,9 @@ def test_multiple_vrf_prefix_peer_established(tgen):
     if topotest.version_cmp(platform.release(), "5.3") < 0:
         return
 
-    # configure_bgp("bgpd_multi_vrf_prefix.conf")
-    # configure_ospf("ospfd_multi_vrf.conf")
-    reload_new_configs(tgen, "bgpd_multi_vrf_prefix.conf", "ospfd_multi_vrf.conf")
+    reset_with_new_configs(tgen, "bgpd_multi_vrf_prefix.conf", "ospfd_multi_vrf.conf")
     check_all_peers_established("blue")
     check_all_peers_established("red")
-    # tgen.mininet_cli()
 
 
 def test_multiple_vrf_prefix_peer_remove_passwords(tgen):
@@ -709,14 +553,11 @@ def test_multiple_vrf_prefix_peer_remove_passwords(tgen):
     if topotest.version_cmp(platform.release(), "5.3") < 0:
         return
 
-    # configure_bgp("bgpd_multi_vrf_prefix.conf")
-    # configure_ospf("ospfd_multi_vrf.conf")
-    reload_new_configs(tgen, "bgpd_multi_vrf_prefix.conf", "ospfd_multi_vrf.conf")
+    reset_with_new_configs(tgen, "bgpd_multi_vrf_prefix.conf", "ospfd_multi_vrf.conf")
     check_vrf_peer_remove_passwords(vrf="blue", prefix="yes")
     check_all_peers_established("red")
     check_vrf_peer_remove_passwords(vrf="red", prefix="yes")
     check_all_peers_established("blue")
-    # tgen.mininet_cli()
 
 
 def test_multiple_vrf_prefix_peer_change_passwords(tgen):
@@ -726,14 +567,11 @@ def test_multiple_vrf_prefix_peer_change_passwords(tgen):
     if topotest.version_cmp(platform.release(), "5.3") < 0:
         return
 
-    # configure_bgp("bgpd_multi_vrf_prefix.conf")
-    # configure_ospf("ospfd_multi_vrf.conf")
-    reload_new_configs(tgen, "bgpd_multi_vrf_prefix.conf", "ospfd_multi_vrf.conf")
+    reset_with_new_configs(tgen, "bgpd_multi_vrf_prefix.conf", "ospfd_multi_vrf.conf")
     check_vrf_peer_change_passwords(vrf="blue", prefix="yes")
     check_all_peers_established("red")
     check_vrf_peer_change_passwords(vrf="red", prefix="yes")
     check_all_peers_established("blue")
-    # tgen.mininet_cli()
 
 
 def test_memory_leak(tgen):
index 2dfeff70f55a2ad494671f2cfa26a3b2e82dac8c..ed55490c096508bf3ddc7fe7d7ef617c25b31495 100755 (executable)
@@ -255,6 +255,7 @@ def pytest_configure(config):
             cli_level = config.getini("log_cli_level")
             if cli_level is not None:
                 config.option.log_cli_level = cli_level
+
     # ---------------------------------------
     # Record our options in global dictionary
     # ---------------------------------------
@@ -329,6 +330,12 @@ def setup_session_auto():
     logger.debug("After the run (is_worker: %s)", is_worker)
 
 
+def pytest_runtest_setup(item):
+    module = item.parent.module
+    script_dir = os.path.abspath(os.path.dirname(module.__file__))
+    os.environ["PYTEST_TOPOTEST_SCRIPTDIR"] = script_dir
+
+
 def pytest_runtest_makereport(item, call):
     "Log all assert messages to default logger with error level"
 
index cbc73915a77686dfbbe7b7a57ae09e954fd08361..bfb6cd1ef2df6a5e2b82e22f25e65d42ada60bae 100644 (file)
@@ -49,7 +49,6 @@ FRRCFG_FILE = "frr_json.conf"
 FRRCFG_BKUP_FILE = "frr_json_initial.conf"
 
 ERROR_LIST = ["Malformed", "Failure", "Unknown", "Incomplete"]
-ROUTER_LIST = []
 
 ####
 CD = os.path.dirname(os.path.realpath(__file__))
@@ -471,6 +470,40 @@ def check_router_status(tgen):
     return True
 
 
+def save_initial_config_on_routers(tgen):
+    """Save current configuration on routers to FRRCFG_BKUP_FILE.
+
+    FRRCFG_BKUP_FILE is the file that will be restored when `reset_config_on_routers()`
+    is called.
+
+    Parameters
+    ----------
+    * `tgen` : Topogen object
+    """
+    router_list = tgen.routers()
+    target_cfg_fmt = tgen.logdir + "/{}/frr_json_initial.conf"
+
+    # Get all running configs in parallel
+    procs = {}
+    for rname in router_list:
+        logger.info("Fetching running config for router %s", rname)
+        procs[rname] = router_list[rname].popen(
+            ["/usr/bin/env", "vtysh", "-c", "show running-config no-header"],
+            stdin=None,
+            stdout=open(target_cfg_fmt.format(rname), "w"),
+            stderr=subprocess.PIPE,
+        )
+    for rname, p in procs.items():
+        _, error = p.communicate()
+        if p.returncode:
+            logger.error(
+                "Get running config for %s failed %d: %s", rname, p.returncode, error
+            )
+            raise InvalidCLIError(
+                "vtysh show running error on {}: {}".format(rname, error)
+            )
+
+
 def reset_config_on_routers(tgen, routerName=None):
     """
     Resets configuration on routers to the snapshot created using input JSON
@@ -490,8 +523,12 @@ def reset_config_on_routers(tgen, routerName=None):
     # Trim the router list if needed
     router_list = tgen.routers()
     if routerName:
-        if (routerName not in ROUTER_LIST) or (routerName not in router_list):
-            logger.debug("Exiting API: reset_config_on_routers: no routers")
+        if routerName not in router_list:
+            logger.warning(
+                "Exiting API: reset_config_on_routers: no router %s",
+                routerName,
+                exc_info=True,
+            )
             return True
         router_list = {routerName: router_list[routerName]}
 
@@ -622,6 +659,44 @@ def reset_config_on_routers(tgen, routerName=None):
     return True
 
 
+def prep_load_config_to_routers(tgen, *config_name_list):
+    """Create common config for `load_config_to_routers`.
+
+    The common config file is constructed from the list of sub-config files passed as
+    position arguments to this function. Each entry in `config_name_list` is looked for
+    under the router sub-directory in the test directory and those files are
+    concatenated together to create the common config. e.g.,
+
+      # Routers are "r1" and "r2", test file is `example/test_example_foo.py`
+      prepare_load_config_to_routers(tgen, "bgpd.conf", "ospfd.conf")
+
+    When the above call is made the files in
+
+      example/r1/bgpd.conf
+      example/r1/ospfd.conf
+
+    Are concat'd together into a single config file that will be loaded on r1, and
+
+      example/r2/bgpd.conf
+      example/r2/ospfd.conf
+
+    Are concat'd together into a single config file that will be loaded on r2 when
+    the call to `load_config_to_routers` is made.
+    """
+
+    routers = tgen.routers()
+    for rname, router in routers.items():
+        destname = "{}/{}/{}".format(tgen.logdir, rname, FRRCFG_FILE)
+        wmode = "w"
+        for cfbase in config_name_list:
+            script_dir = os.environ["PYTEST_TOPOTEST_SCRIPTDIR"]
+            confname = os.path.join(script_dir, "{}/{}".format(rname, cfbase))
+            with open(confname, "r") as cf:
+                with open(destname, wmode) as df:
+                    df.write(cf.read())
+            wmode = "a"
+
+
 def load_config_to_routers(tgen, routers, save_bkup=False):
     """
     Loads configuration on routers from the file FRRCFG_FILE.
@@ -644,7 +719,7 @@ def load_config_to_routers(tgen, routers, save_bkup=False):
     base_router_list = tgen.routers()
     router_list = {}
     for router in routers:
-        if (router not in ROUTER_LIST) or (router not in base_router_list):
+        if router not in base_router_list:
             continue
         router_list[router] = base_router_list[router]
 
@@ -759,6 +834,21 @@ def load_config_to_router(tgen, routerName, save_bkup=False):
     return load_config_to_routers(tgen, [routerName], save_bkup)
 
 
+def reset_with_new_configs(tgen, *cflist):
+    """Reset the router to initial config, then load new configs.
+
+    Resets routers to the initial config state (see `save_initial_config_on_routers()
+    and `reset_config_on_routers()` `), then concat list of router sub-configs together
+    and load onto the routers (see `prep_load_config_to_routers()` and
+    `load_config_to_routers()`)
+    """
+    routers = tgen.routers()
+
+    reset_config_on_routers(tgen)
+    prep_load_config_to_routers(tgen, *cflist)
+    load_config_to_routers(tgen, tgen.routers(), save_bkup=False)
+
+
 def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None):
     """
     API to get the link local ipv6 address of a particular interface using
@@ -882,20 +972,19 @@ def start_topology(tgen, daemon=None):
     * `tgen`  : topogen object
     """
 
-    global ROUTER_LIST
     # Starting topology
     tgen.start_topology()
 
     # Starting daemons
 
     router_list = tgen.routers()
-    ROUTER_LIST = sorted(
+    routers_sorted = sorted(
         router_list.keys(), key=lambda x: int(re_search("[0-9]+", x).group(0))
     )
 
     linux_ver = ""
     router_list = tgen.routers()
-    for rname in ROUTER_LIST:
+    for rname in routers_sorted:
         router = router_list[rname]
 
         # It will help in debugging the failures, will give more details on which
@@ -1034,11 +1123,11 @@ def topo_daemons(tgen, topo=None):
         topo = tgen.json_topo
 
     router_list = tgen.routers()
-    ROUTER_LIST = sorted(
+    routers_sorted = sorted(
         router_list.keys(), key=lambda x: int(re_search("[0-9]+", x).group(0))
     )
 
-    for rtr in ROUTER_LIST:
+    for rtr in routers_sorted:
         if "ospf" in topo["routers"][rtr] and "ospfd" not in daemon_list:
             daemon_list.append("ospfd")
 
index fa943b299b37f808d9bc753059c01037894e4d56..325f65dd6fdfe075e2efc24119f90dd2ddfd91f1 100644 (file)
@@ -786,13 +786,16 @@ class TopoRouter(TopoGear):
         return self.net.checkCapability(daemonstr, param)
 
     def load_config(self, daemon, source=None, param=None):
-        """
-        Loads daemon configuration from the specified source
+        """Loads daemon configuration from the specified source
         Possible daemon values are: TopoRouter.RD_ZEBRA, TopoRouter.RD_RIP,
         TopoRouter.RD_RIPNG, TopoRouter.RD_OSPF, TopoRouter.RD_OSPF6,
         TopoRouter.RD_ISIS, TopoRouter.RD_BGP, TopoRouter.RD_LDP,
         TopoRouter.RD_PIM, TopoRouter.RD_PBR, TopoRouter.RD_SNMP.
 
+        Possible `source` values are `None` for an empty config file, a path name which is
+        used directly, or a file name with no path components which is first looked for
+        directly and then looked for under a sub-directory named after router.
+
         This API unfortunately allows for source to not exist for any and
         all routers.
         """
index beb298eb3a066ac7118f8bc6205d238003e77714..4f23e1ace03042a9e4977a4332f6bbda3f817fa6 100644 (file)
@@ -44,8 +44,6 @@ from lib.ospf import create_router_ospf, create_router_ospf6
 from lib.pim import create_igmp_config, create_pim_config
 from lib.topolog import logger
 
-ROUTER_LIST = []
-
 
 def build_topo_from_json(tgen, topo=None):
     """
@@ -58,26 +56,26 @@ def build_topo_from_json(tgen, topo=None):
     if topo is None:
         topo = tgen.json_topo
 
-    ROUTER_LIST = sorted(
+    router_list = sorted(
         topo["routers"].keys(), key=lambda x: int(re_search(r"\d+", x).group(0))
     )
 
-    SWITCH_LIST = []
+    switch_list = []
     if "switches" in topo:
-        SWITCH_LIST = sorted(
+        switch_list = sorted(
             topo["switches"].keys(), key=lambda x: int(re_search(r"\d+", x).group(0))
         )
 
-    listRouters = sorted(ROUTER_LIST[:])
-    listSwitches = sorted(SWITCH_LIST[:])
+    listRouters = sorted(router_list[:])
+    listSwitches = sorted(switch_list[:])
     listAllRouters = deepcopy(listRouters)
     dictSwitches = {}
 
-    for routerN in ROUTER_LIST:
+    for routerN in router_list:
         logger.info("Topo: Add router {}".format(routerN))
         tgen.add_router(routerN)
 
-    for switchN in SWITCH_LIST:
+    for switchN in switch_list:
         logger.info("Topo: Add switch {}".format(switchN))
         dictSwitches[switchN] = tgen.add_switch(switchN)
 
index 39b01203e942f6a305432bdedae514f73c3d6d49..b6f55664a66550ef2dd498e05952ee364d3d4878 100644 (file)
@@ -1488,7 +1488,25 @@ class Router(Node):
         return True
 
     def loadConf(self, daemon, source=None, param=None):
+        """Enabled and set config for a daemon.
+
+        Arranges for loading of daemon configuration from the specified source. Possible
+        `source` values are `None` for an empty config file, a path name which is used
+        directly, or a file name with no path components which is first looked for
+        directly and then looked for under a sub-directory named after router.
+        """
+
         # Unfortunately this API allowsfor source to not exist for any and all routers.
+        if source:
+            head, tail = os.path.split(source)
+            if not head and not self.path_exists(tail):
+                script_dir = os.environ["PYTEST_TOPOTEST_SCRIPTDIR"]
+                router_relative = os.path.join(script_dir, self.name, tail)
+                if self.path_exists(router_relative):
+                    source = router_relative
+                    self.logger.info(
+                        "using router relative configuration: {}".format(source)
+                    )
 
         # print "Daemons before:", self.daemons
         if daemon in self.daemons.keys():
@@ -1497,6 +1515,7 @@ class Router(Node):
                 self.daemons_options[daemon] = param
             conf_file = "/etc/{}/{}.conf".format(self.routertype, daemon)
             if source is None or not os.path.exists(source):
+                self.cmd_raises("rm -f " + conf_file)
                 self.cmd_raises("touch " + conf_file)
             else:
                 self.cmd_raises("cp {} {}".format(source, conf_file))