From d9fb94d6c327b53bb7303b43f863fb2262327ae5 Mon Sep 17 00:00:00 2001 From: nguggarigoud Date: Fri, 29 Oct 2021 04:14:33 -0700 Subject: [PATCH] tests: Add topotests for MGMT daemon 1. MGMT daemon support in topotests. 2. Sanity tests for MGMTd. Signed-off-by: nguggarigoud --- .../test_all_protocol_startup.py | 1 + .../test_bfd_profiles_topo1.py | 4 + tests/topotests/bfd_topo2/test_bfd_topo2.py | 4 + tests/topotests/bfd_topo3/test_bfd_topo3.py | 4 + .../bgp_suppress_fib/test_bgp_suppress_fib.py | 3 + tests/topotests/lib/common_config.py | 10 +- tests/topotests/lib/topogen.py | 9 +- tests/topotests/lib/topotest.py | 23 +- tests/topotests/mgmt_tests/test_yang_mgmt.py | 592 ++++++++++++++++++ tests/topotests/mgmt_tests/yang_mgmt.json | 157 +++++ .../msdp_mesh_topo1/test_msdp_mesh_topo1.py | 5 + tests/topotests/msdp_topo1/test_msdp_topo1.py | 4 + .../topotests/ospf6_topo2/test_ospf6_topo2.py | 4 + .../pim_basic_topo2/test_pim_basic_topo2.py | 4 + tests/topotests/zebra_rib/test_zebra_rib.py | 3 + 15 files changed, 821 insertions(+), 6 deletions(-) create mode 100644 tests/topotests/mgmt_tests/test_yang_mgmt.py create mode 100644 tests/topotests/mgmt_tests/yang_mgmt.json diff --git a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py index ca8c005f9e..ead394f132 100644 --- a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py +++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py @@ -92,6 +92,7 @@ def setup_module(module): # # Main router for i in range(1, 2): + net["r%s" % i].loadConf("mgmtd", "%s/r%s/mgmtd.conf" % (thisDir, i)) net["r%s" % i].loadConf("zebra", "%s/r%s/zebra.conf" % (thisDir, i)) net["r%s" % i].loadConf("ripd", "%s/r%s/ripd.conf" % (thisDir, i)) net["r%s" % i].loadConf("ripngd", "%s/r%s/ripngd.conf" % (thisDir, i)) diff --git a/tests/topotests/bfd_profiles_topo1/test_bfd_profiles_topo1.py b/tests/topotests/bfd_profiles_topo1/test_bfd_profiles_topo1.py index 169f90abf0..e67bb91090 100644 --- a/tests/topotests/bfd_profiles_topo1/test_bfd_profiles_topo1.py +++ b/tests/topotests/bfd_profiles_topo1/test_bfd_profiles_topo1.py @@ -60,6 +60,10 @@ def setup_module(mod): router_list = tgen.routers() for rname, router in router_list.items(): + daemon_file = "{}/{}/mgmtd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_MGMTD, daemon_file) + daemon_file = "{}/{}/bfdd.conf".format(CWD, rname) if os.path.isfile(daemon_file): router.load_config(TopoRouter.RD_BFD, daemon_file) diff --git a/tests/topotests/bfd_topo2/test_bfd_topo2.py b/tests/topotests/bfd_topo2/test_bfd_topo2.py index 57ce0cdf09..97b5d84a58 100644 --- a/tests/topotests/bfd_topo2/test_bfd_topo2.py +++ b/tests/topotests/bfd_topo2/test_bfd_topo2.py @@ -58,6 +58,10 @@ def setup_module(mod): router_list = tgen.routers() for rname, router in router_list.items(): + daemon_file = "{}/{}/mgmtd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_MGMTD, daemon_file) + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) router.load_config(TopoRouter.RD_ZEBRA, daemon_file) diff --git a/tests/topotests/bfd_topo3/test_bfd_topo3.py b/tests/topotests/bfd_topo3/test_bfd_topo3.py index 978593e41a..c35d3f4dd4 100644 --- a/tests/topotests/bfd_topo3/test_bfd_topo3.py +++ b/tests/topotests/bfd_topo3/test_bfd_topo3.py @@ -61,6 +61,10 @@ def setup_module(mod): if os.path.isfile(daemon_file): router.load_config(TopoRouter.RD_BFD, daemon_file) + daemon_file = "{}/{}/mgmtd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_MGMTD, daemon_file) + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) if os.path.isfile(daemon_file): router.load_config(TopoRouter.RD_ZEBRA, daemon_file) diff --git a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py index 2c87d9d7b0..58f9b4007f 100644 --- a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py +++ b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py @@ -61,6 +61,9 @@ def setup_module(mod): router_list = tgen.routers() for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_MGMTD, os.path.join(CWD, "{}/mgmtd.conf".format(rname)) + ) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 564571c929..c936392bf4 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -103,6 +103,7 @@ DEBUG_LOGS = { "debug zebra vxlan", "debug zebra nht", ], + "mgmt": [], "ospf": [ "debug ospf event", "debug ospf ism", @@ -451,6 +452,8 @@ def check_router_status(tgen): result = rnode.check_router_running() if result != "": daemons = [] + if "mgmtd" in result: + daemons.append("mgmtd") if "bgpd" in result: daemons.append("bgpd") if "zebra" in result: @@ -1015,6 +1018,11 @@ def start_topology(tgen, daemon=None): except IOError as err: logger.error("I/O error({0}): {1}".format(err.errno, err.strerror)) + # Loading empty mgmtd.conf file to router, to start the mgmtd daemon + router.load_config( + TopoRouter.RD_MGMTD, "{}/{}/mgmtd.conf".format(tgen.logdir, rname) + ) + # Loading empty zebra.conf file to router, to start the zebra daemon router.load_config( TopoRouter.RD_ZEBRA, "{}/{}/zebra.conf".format(tgen.logdir, rname) @@ -2546,7 +2554,7 @@ def create_route_maps(tgen, input_dict, build=False): nexthop = set_data.setdefault("nexthop", None) origin = set_data.setdefault("origin", None) ext_comm_list = set_data.setdefault("extcommunity", {}) - metrictype = set_data.setdefault("metric-type", {}) + metrictype = set_data.setdefault("metric-type", None) # Local Preference if local_preference: diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py index 4ed5b2f825..3bb63a017b 100644 --- a/tests/topotests/lib/topogen.py +++ b/tests/topotests/lib/topogen.py @@ -725,6 +725,7 @@ class TopoRouter(TopoGear): RD_PBRD = 16 RD_PATH = 17 RD_SNMP = 18 + RD_MGMTD = 19 RD = { RD_FRR: "frr", RD_ZEBRA: "zebra", @@ -745,6 +746,7 @@ class TopoRouter(TopoGear): RD_PBRD: "pbrd", RD_PATH: "pathd", RD_SNMP: "snmpd", + RD_MGMTD: "mgmtd", } def __init__(self, tgen, cls, name, **params): @@ -820,7 +822,8 @@ class TopoRouter(TopoGear): 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. + TopoRouter.RD_PIM, TopoRouter.RD_PBR, TopoRouter.RD_SNMP, + TopoRouter.RD_MGMTD. 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 @@ -1278,6 +1281,7 @@ def diagnose_env_linux(rundir): "pimd", "ldpd", "pbrd", + "mgmtd", ]: path = os.path.join(frrdir, fname) if not os.path.isfile(path): @@ -1292,9 +1296,10 @@ def diagnose_env_linux(rundir): logger.warning("could not find {} in {}".format(fname, frrdir)) ret = False else: - if fname != "zebra": + if fname != "zebra" or fname != "mgmtd": continue + os.system("{} -v 2>&1 >{}/frr_mgmtd.txt".format(path, rundir)) os.system("{} -v 2>&1 >{}/frr_zebra.txt".format(path, rundir)) # Test MPLS availability diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index e786ae02cd..dc50d6b0c5 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -1340,8 +1340,9 @@ class Router(Node): "pbrd": 0, "pathd": 0, "snmpd": 0, + "mgmtd": 0, } - self.daemons_options = {"zebra": ""} + self.daemons_options = {"zebra": "", "mgmtd": ""} self.reportCores = True self.version = None @@ -1367,6 +1368,10 @@ class Router(Node): if not os.path.isfile(zebra_path): raise Exception("FRR zebra binary doesn't exist at {}".format(zebra_path)) + mgmtd_path = os.path.join(self.daemondir, "mgmtd") + if not os.path.isfile(mgmtd_path): + raise Exception("FRR MGMTD binary doesn't exist at {}".format(mgmtd_path)) + # pylint: disable=W0221 # Some params are only meaningful for the parent class. def config(self, **params): @@ -1384,6 +1389,10 @@ class Router(Node): zpath = os.path.join(self.daemondir, "zebra") if not os.path.isfile(zpath): raise Exception("No zebra binary found in {}".format(zpath)) + + cpath = os.path.join(self.daemondir, "mgmtd") + if not os.path.isfile(zpath): + raise Exception("No MGMTD binary found in {}".format(cpath)) # Allow user to specify routertype when the path was specified. if params.get("routertype") is not None: self.routertype = params.get("routertype") @@ -1547,7 +1556,9 @@ class Router(Node): self.cmd('echo "agentXSocket /etc/frr/agentx" >> /etc/snmp/frr.conf') self.cmd('echo "mibs +ALL" > /etc/snmp/snmp.conf') - if (daemon == "zebra") and (self.daemons["staticd"] == 0): + if (daemon == "zebra" or daemon == "mgmtd") and ( + self.daemons["staticd"] == 0 + ): # Add staticd with zebra - if it exists try: staticd_path = os.path.join(self.daemondir, "staticd") @@ -1803,7 +1814,13 @@ class Router(Node): else: logger.info("%s: %s %s started", self, self.routertype, daemon) - # Start Zebra first + # Start mgmtd first + if "mgmtd" in daemons_list: + start_daemon("mgmtd") + while "mgmtd" in daemons_list: + daemons_list.remove("mgmtd") + + # Start Zebra after mgmtd if "zebra" in daemons_list: start_daemon("zebra", "-s 90000000") while "zebra" in daemons_list: diff --git a/tests/topotests/mgmt_tests/test_yang_mgmt.py b/tests/topotests/mgmt_tests/test_yang_mgmt.py new file mode 100644 index 0000000000..d1610c06e4 --- /dev/null +++ b/tests/topotests/mgmt_tests/test_yang_mgmt.py @@ -0,0 +1,592 @@ +#!/usr/bin/python + +# +# Copyright (c) 2021 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# +""" + +1. Verify mgmt commit check. +2. Verify mgmt commit apply. +3. Verify mgmt commit abort. +4. Verify mgmt delete config. +5. Kill mgmtd - verify that static routes are intact. +6. Kill mgmtd - verify that watch frr restarts. +7. Show and CLI - Execute all the newly introduced commands of mgmtd. +8. Verify mgmt rollback functionality. + +""" +import sys +import time +import os +import pytest +import platform + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from lib.topotest import version_cmp + +# Import topoJson from lib, to create topology and initial configuration +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + verify_rib, + create_static_routes, + check_address_types, + step, + shutdown_bringup_interface, + stop_router, + start_router, + apply_raw_config, + kill_router_daemons, + start_router_daemons, +) +from lib.topolog import logger +from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib +from lib.topojson import build_config_from_json + +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + +# Global variables +ADDR_TYPES = check_address_types() +NETWORK = {"ipv4": ["11.0.20.1/32", "11.0.20.2/32"], "ipv6": ["2::1/128", "2::2/128"]} +NETWORK2 = {"ipv4": "11.0.20.1/32", "ipv6": "2::1/128"} +PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"} + + +def setup_module(mod): + """ + Sets up the pytest environment. + + * `mod`: module name + """ + + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/yang_mgmt.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + if version_cmp(platform.release(), "4.19") < 0: + error_msg = ( + 'These tests will not run. (have kernel "{}", ' + "requires kernel >= 4.19)".format(platform.release()) + ) + pytest.skip(error_msg) + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment. + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology: %s", mod) + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +def populate_nh(): + """ + Populate nexthops. + """ + + next_hop_ip = { + "nh1": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0], + }, + "nh2": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0], + }, + } + return next_hop_ip + + +##################################################### +# +# Testcases +# +##################################################### + + +def test_mgmt_commit_check(request): + """ + Verify mgmt commit check. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + + step("Mgmt Commit check") + raw_config = { + "r1": { + "raw_config": [ + "mgmt set-config xpath /frr-routing:routing/control-plane-protocols/control-plane-protocol[type='frr-staticd:staticd'][name='staticd'][vrf='default']/frr-staticd:staticd/route-list[prefix='192.1.1.2/32'][afi-safi='frr-routing:ipv4-unicast']/path-list[table-id='0'][distance='1']/frr-nexthops/nexthop[nh-type='blackhole'][vrf='default'][gateway=''][interface='(null)']/bh-type value unspec", + "mgmt commit-check", + ] + } + } + + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Mgmt Commit check") + raw_config = { + "r1": { + "raw_config": [ + "mgmt set-config xpath /frr-routing:routing/control-plane-protocols/control-plane-protocol[type='frr-staticd:staticd'][name='staticd'][vrf='default']/frr-staticd:staticd/route-list[prefix='192.1.1.2/32'][afi-safi='frr-routing:ipv4-unicast']/path-list[table-id='0'][distance='1']/frr-nexthops/nexthop[nh-type='blackhole'][vrf='default'][gateway=''][interface='(null)']/bh-type value unspec", + "mgmt commit-check", + ] + } + } + + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify that the route is not configured, as commit apply not done.") + + dut = "r1" + protocol = "static" + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": "192.168.1.1/32", + "next_hop": "Null0", + } + ] + } + } + result = verify_rib(tgen, "ipv4", dut, input_dict_4, protocol=protocol) + assert ( + result is not True + ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_mgmt_commit_apply(request): + """ + Verify mgmt commit apply. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + + step("Mgmt Commit apply") + raw_config = { + "r1": { + "raw_config": [ + "mgmt set-config xpath /frr-routing:routing/control-plane-protocols/control-plane-protocol[type='frr-staticd:staticd'][name='staticd'][vrf='default']/frr-staticd:staticd/route-list[prefix='192.1.1.20/32'][afi-safi='frr-routing:ipv4-unicast']/path-list[table-id='0'][distance='1']/frr-nexthops/nexthop[nh-type='blackhole'][vrf='default'][gateway=''][interface='(null)']/vrf value default", + "mgmt commit-apply", + ] + } + } + + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Mgmt Commit apply") + raw_config = { + "r1": { + "raw_config": [ + "mgmt set-config xpath /frr-routing:routing/control-plane-protocols/control-plane-protocol[type='frr-staticd:staticd'][name='staticd'][vrf='default']/frr-staticd:staticd/route-list[prefix='192.1.1.20/32'][afi-safi='frr-routing:ipv4-unicast']/path-list[table-id='0'][distance='1']/frr-nexthops/nexthop[nh-type='blackhole'][vrf='default'][gateway=''][interface='(null)']/vrf value default", + "mgmt commit-apply", + ] + } + } + + result = apply_raw_config(tgen, raw_config) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify that the route is configured") + + dut = "r1" + protocol = "static" + input_dict_4 = {"r2": {"static_routes": [{"network": "192.1.1.20/32"}]}} + result = verify_rib(tgen, "ipv4", dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_mgmt_commit_abort(request): + """ + Verify mgmt commit abort. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + + step("Mgmt Commit abort") + raw_config = { + "r1": { + "raw_config": [ + "mgmt set-config xpath /frr-routing:routing/control-plane-protocols/control-plane-protocol[type='frr-staticd:staticd'][name='staticd'][vrf='default']/frr-staticd:staticd/route-list[prefix='192.1.1.3/32'][afi-safi='frr-routing:ipv4-unicast']/path-list[table-id='0'][distance='1']/frr-nexthops/nexthop[nh-type='blackhole'][vrf='default'][gateway=''][interface='(null)']/vrf value default", + "mgmt commit-abort", + ] + } + } + + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify that the route is not configured") + + dut = "r1" + protocol = "static" + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": "192.168.1.3/32", + "next_hop": "Null0", + } + ] + } + } + result = verify_rib(tgen, "ipv4", dut, input_dict_4, protocol=protocol) + assert ( + result is not True + ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_mgmt_delete_config(request): + """ + Verify mgmt delete config. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + + step("Mgmt - Configure a static route using commit-apply") + + raw_config = { + "r1": { + "raw_config": [ + "mgmt set-config xpath /frr-routing:routing/control-plane-protocols/control-plane-protocol[type='frr-staticd:staticd'][name='staticd'][vrf='default']/frr-staticd:staticd/route-list[prefix='192.168.1.3/32'][afi-safi='frr-routing:ipv4-unicast']/path-list[table-id='0'][distance='1']/frr-nexthops/nexthop[nh-type='blackhole'][vrf='default'][gateway=''][interface='(null)']/vrf value default", + "mgmt commit-apply", + ] + } + } + + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Mgmt delete config") + raw_config = { + "r1": { + "raw_config": [ + "mgmt delete-config xpath /frr-routing:routing/control-plane-protocols/control-plane-protocol[type='frr-staticd:staticd'][name='staticd'][vrf='default']/frr-staticd:staticd/route-list[prefix='192.168.1.3/32'][afi-safi='frr-routing:ipv4-unicast']", + "mgmt commit-apply", + ] + } + } + + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify that the route is deleted configured") + + dut = "r1" + protocol = "static" + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": "192.168.1.3/32", + "next_hop": "Null0", + } + ] + } + } + result = verify_rib(tgen, "ipv4", dut, input_dict_4, protocol=protocol) + assert ( + result is not True + ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_mgmt_chaos_stop_start_frr(request): + """ + Kill mgmtd - verify that watch frr restarts. + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + next_hop_ip = populate_nh() + + step("Configure Static route with next hop null 0") + + raw_config = { + "r1": { + "raw_config": [ + "mgmt set-config xpath /frr-routing:routing/control-plane-protocols/control-plane-protocol[type='frr-staticd:staticd'][name='staticd'][vrf='default']/frr-staticd:staticd/route-list[prefix='192.1.11.200/32'][afi-safi='frr-routing:ipv4-unicast']/path-list[table-id='0'][distance='1']/frr-nexthops/nexthop[nh-type='blackhole'][vrf='default'][gateway=''][interface='(null)']/bh-type value unspec", + "mgmt commit-apply", + ] + } + } + + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify that the route is configured and present in the zebra") + + dut = "r1" + protocol = "static" + input_dict_4 = {"r2": {"static_routes": [{"network": "192.1.11.200/32"}]}} + result = verify_rib(tgen, "ipv4", dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name) + + step("Restart frr") + stop_router(tgen, "r1") + start_router(tgen, "r1") + step("Verify routes are intact in zebra.") + result = verify_rib(tgen, "ipv4", dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name) + + step("delete the configured route and ") + raw_config = { + "r1": { + "raw_config": [ + "mgmt delete-config xpath /frr-routing:routing/control-plane-protocols/control-plane-protocol[type='frr-staticd:staticd'][name='staticd'][vrf='default']/frr-staticd:staticd/route-list[prefix='192.1.11.200/32'][afi-safi='frr-routing:ipv4-unicast']/path-list[table-id='0'][distance='1']/frr-nexthops/nexthop[nh-type='blackhole'][vrf='default'][gateway=''][interface='(null)']" + ] + } + } + + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify that the route is deleted and deleted from zebra") + + dut = "r1" + protocol = "static" + input_dict_4 = {"r1": {"static_routes": [{"network": "192.1.11.200/32"}]}} + result = verify_rib(tgen, "ipv4", dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_show_cli(request): + """ + This is to test all the clis for mgmt. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + + step("Mgmt cli check") + raw_config = { + "r1": { + "raw_config": [ + "debug mgmt all", + "debug mgmt backend", + "debug mgmt database", + "debug mgmt frontend", + "debug mgmt transaction", + "do show mgmt backend-adapter all", + "do show mgmt backend-yang-xpath-registry", + "do show mgmt commit-history", + "do show mgmt database all", + "do show mgmt database candidate", + "do show mgmt database operational", + "do show mgmt database running", + "do show mgmt database-contents db-name running", + "do show mgmt frontend-adapter all detail", + "do show mgmt frontend-adapter all", + "do show mgmt get-config running", + "do show mgmt get-data running xpath /", + "do show mgmt transaction all", + "do show mgmt yang-xpath-subscription /", + "mgmt commit-abort", + "mgmt commit-apply", + "mgmt commit-check", + "mgmt delete-config xpath /", + "mgmt load-config file WORD merge", + "mgmt load-config file WORD replace", + "mgmt lock-database candidate", + "mgmt rollback last 2", + "mgmt rollback last", + "mgmt save-config db-name WORD file WORD", + "mgmt set-config xpath WORD value WORD", + "mgmt unlock-database candidate", + ] + } + } + + result = apply_raw_config(tgen, raw_config) + assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_mgmt_chaos_kill_daemon(request): + """ + Kill mgmtd - verify that static routes are intact + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + next_hop_ip = populate_nh() + + step("Configure Static route with next hop null 0") + + raw_config = { + "r1": { + "raw_config": [ + "mgmt set-config xpath /frr-routing:routing/control-plane-protocols/control-plane-protocol[type='frr-staticd:staticd'][name='staticd'][vrf='default']/frr-staticd:staticd/route-list[prefix='192.1.11.200/32'][afi-safi='frr-routing:ipv4-unicast']/path-list[table-id='0'][distance='1']/frr-nexthops/nexthop[nh-type='blackhole'][vrf='default'][gateway=''][interface='(null)']/bh-type value unspec", + "mgmt commit-apply", + ] + } + } + + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify that the route is configured and present in the zebra") + + dut = "r1" + protocol = "static" + input_dict_4 = {"r2": {"static_routes": [{"network": "192.1.11.200/32"}]}} + result = verify_rib(tgen, "ipv4", dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name) + + step("Kill static daemon on R2.") + kill_router_daemons(tgen, "r1", ["staticd"]) + + step("Bring up staticd daemon on R2.") + start_router_daemons(tgen, "r1", ["staticd"]) + + step("Verify routes are intact in zebra.") + result = verify_rib(tgen, "ipv4", dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name) + + step("Kill mgmt daemon on R2.") + kill_router_daemons(tgen, "r1", ["mgmtd"]) + + step("Bring up zebra daemon on R2.") + start_router_daemons(tgen, "r1", ["mgmtd"]) + + step("Verify routes are intact in zebra.") + result = verify_rib(tgen, "ipv4", dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/mgmt_tests/yang_mgmt.json b/tests/topotests/mgmt_tests/yang_mgmt.json new file mode 100644 index 0000000000..0fe3bb1dbe --- /dev/null +++ b/tests/topotests/mgmt_tests/yang_mgmt.json @@ -0,0 +1,157 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3": { + "keepalivetimer": 1, + "holddowntimer": 4 + } + } + } + } + } + } + } + } + } + } +} diff --git a/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py index 138e190986..6dbe241928 100644 --- a/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py +++ b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py @@ -84,6 +84,11 @@ def setup_module(mod): router_list = tgen.routers() for rname, router in router_list.items(): + + daemon_file = "{}/{}/mgmtd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_MGMTD, daemon_file) + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) if os.path.isfile(daemon_file): router.load_config(TopoRouter.RD_ZEBRA, daemon_file) diff --git a/tests/topotests/msdp_topo1/test_msdp_topo1.py b/tests/topotests/msdp_topo1/test_msdp_topo1.py index 46ccd5e599..b7d7ccc26f 100755 --- a/tests/topotests/msdp_topo1/test_msdp_topo1.py +++ b/tests/topotests/msdp_topo1/test_msdp_topo1.py @@ -95,6 +95,10 @@ def setup_module(mod): router_list = tgen.routers() for rname, router in router_list.items(): + daemon_file = "{}/{}/mgmtd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_MGMTD, daemon_file) + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) if os.path.isfile(daemon_file): router.load_config(TopoRouter.RD_ZEBRA, daemon_file) diff --git a/tests/topotests/ospf6_topo2/test_ospf6_topo2.py b/tests/topotests/ospf6_topo2/test_ospf6_topo2.py index d17aeda3ea..6185596161 100644 --- a/tests/topotests/ospf6_topo2/test_ospf6_topo2.py +++ b/tests/topotests/ospf6_topo2/test_ospf6_topo2.py @@ -142,6 +142,10 @@ def setup_module(mod): router_list = tgen.routers() for rname, router in router_list.items(): + daemon_file = "{}/{}/mgmtd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_MGMTD, daemon_file) + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) if os.path.isfile(daemon_file): router.load_config(TopoRouter.RD_ZEBRA, daemon_file) diff --git a/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py b/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py index 9506c3c6d1..46fe899f49 100644 --- a/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py +++ b/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py @@ -81,6 +81,10 @@ def setup_module(mod): if os.path.isfile(daemon_file): router.load_config(TopoRouter.RD_PIM, daemon_file) + daemon_file = "{}/{}/mgmtd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_MGMTD, daemon_file) + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) if os.path.isfile(daemon_file): router.load_config(TopoRouter.RD_ZEBRA, daemon_file) diff --git a/tests/topotests/zebra_rib/test_zebra_rib.py b/tests/topotests/zebra_rib/test_zebra_rib.py index b72691b71e..9566570444 100644 --- a/tests/topotests/zebra_rib/test_zebra_rib.py +++ b/tests/topotests/zebra_rib/test_zebra_rib.py @@ -70,6 +70,9 @@ def setup_module(mod): router_list = tgen.routers() for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_MGMTD, os.path.join(CWD, "{}/mgmtd.conf".format(rname)) + ) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) -- 2.39.5