]> git.puffer.fish Git - matthieu/frr.git/commitdiff
tests: Add topotests for MGMT daemon
authornguggarigoud <nguggarigoud@vmware.com>
Fri, 29 Oct 2021 11:14:33 +0000 (04:14 -0700)
committerChristian Hopps <chopps@labn.net>
Wed, 6 Apr 2022 01:41:23 +0000 (21:41 -0400)
1. MGMT daemon support in topotests.
2. Sanity tests for MGMTd.

Signed-off-by: nguggarigoud <nguggarigoud@vmware.com>
15 files changed:
tests/topotests/all_protocol_startup/test_all_protocol_startup.py
tests/topotests/bfd_profiles_topo1/test_bfd_profiles_topo1.py
tests/topotests/bfd_topo2/test_bfd_topo2.py
tests/topotests/bfd_topo3/test_bfd_topo3.py
tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py
tests/topotests/lib/common_config.py
tests/topotests/lib/topogen.py
tests/topotests/lib/topotest.py
tests/topotests/mgmt_tests/test_yang_mgmt.py [new file with mode: 0644]
tests/topotests/mgmt_tests/yang_mgmt.json [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py
tests/topotests/msdp_topo1/test_msdp_topo1.py
tests/topotests/ospf6_topo2/test_ospf6_topo2.py
tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py
tests/topotests/zebra_rib/test_zebra_rib.py

index ca8c005f9ec705d6bca7c602082abc3cb57c0f1b..ead394f132684db057c196d976ff6cb4552f96ce 100644 (file)
@@ -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))
index 169f90abf063fa6625dddd9cf417596dadd5e956..e67bb9109048e285f42a7bcbfde334b3dbfa3270 100644 (file)
@@ -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)
index 57ce0cdf09b9a18ffeb85bbeaf037dd1febef422..97b5d84a5864adbeb29c9bf5d70bb6ce81e4bc67 100644 (file)
@@ -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)
 
index 978593e41ac130aaa604b17be467bc3ad2962537..c35d3f4dd4dbfabf2c19e2d13272d6b95953d1c1 100644 (file)
@@ -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)
index 2c87d9d7b0f80b543e5e7372c531336f5d967396..58f9b4007f265f6b1668ea4677a30e2823f47d5d 100644 (file)
@@ -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))
         )
index 564571c929b23189de5e53dd2bcc6b8e251f1cba..c936392bf492f866f61525ff95cc9ffd8cb4aeb8 100644 (file)
@@ -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:
index 4ed5b2f8258f50996a2f8b9c7f930d2179b95422..3bb63a017bc8432518439795c7a6b93eee61ff0f 100644 (file)
@@ -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
index e786ae02cdf732a9e2d8571e31f3e07464d45965..dc50d6b0c5a12131d1daa1f2f416fa9ec87f1831 100644 (file)
@@ -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 (file)
index 0000000..d1610c0
--- /dev/null
@@ -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 (file)
index 0000000..0fe3bb1
--- /dev/null
@@ -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
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
index 138e1909865740d8d0e6e22ebe95a0f41055905e..6dbe241928cef2568112d2c81e2d40e10b346b39 100644 (file)
@@ -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)
index 46ccd5e599c87cffbe54f4ed9e0717c4a87d705d..b7d7ccc26f6f0d113d82f4794e8a9a03a961d5ba 100755 (executable)
@@ -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)
index d17aeda3eae43ba2c29ba22f882a49f9e2fac5e7..61855961617ab96757bdc6023294170585b48b48 100644 (file)
@@ -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)
index 9506c3c6d11800c2b55021b497ce73e30ac7bde6..46fe899f49ebc42bafcb9c42505e6cb643954c64 100644 (file)
@@ -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)
index b72691b71e539812b22bfe4bb8510687da524d95..956657044411aff6b22f58889a475e6a04d974d5 100644 (file)
@@ -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))
         )