From a4b4bb5077c3c11cc13f43ef15dd3a3e7251a54c Mon Sep 17 00:00:00 2001 From: Jafar Al-Gharaibeh Date: Sat, 26 Feb 2022 19:59:48 -0600 Subject: [PATCH] topotests: add support for frr.conf as a unified config This PR adds support for configuring topotest routers using a single file. instead of: ``` router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) router.load_config( TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) ) router.load_config( TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) ) ``` you can now do: ``` router.load_frr_config( os.path.join(CWD, "{}/frr.conf".format(rname)), [TopoRouter.RD_ZEBRA, TopoRouter.RD_OSPF, TopoRouter.RD_BGP] ) ``` or just: ``` router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) ``` In this latter case, the daemons list will be inferred from frr.conf file. Signed-off-by: Jafar Al-Gharaibeh --- tests/topotests/lib/topogen.py | 24 +++++++++++++++++++ tests/topotests/lib/topotest.py | 42 +++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py index 33e1388639..a83ae7071f 100644 --- a/tests/topotests/lib/topogen.py +++ b/tests/topotests/lib/topogen.py @@ -706,6 +706,7 @@ class TopoRouter(TopoGear): ] # Router Daemon enumeration definition. + RD_FRR = 0 # not a daemon, but use to setup unified configs RD_ZEBRA = 1 RD_RIP = 2 RD_RIPNG = 3 @@ -725,6 +726,7 @@ class TopoRouter(TopoGear): RD_PATH = 17 RD_SNMP = 18 RD = { + RD_FRR: "frr", RD_ZEBRA: "zebra", RD_RIP: "ripd", RD_RIPNG: "ripngd", @@ -789,6 +791,28 @@ class TopoRouter(TopoGear): self.logger.info('check capability {} for "{}"'.format(param, daemonstr)) return self.net.checkCapability(daemonstr, param) + def load_frr_config(self, source, daemons=None): + """ + Loads the unified configuration file source + Start the daemons in the list + If daemons is None, try to infer daemons from the config file + """ + self.load_config(self.RD_FRR, source) + if not daemons: + # Always add zebra + self.load_config(self.RD_ZEBRA) + for daemon in self.RD: + # This will not work for all daemons + daemonstr = self.RD.get(daemon).rstrip("d") + result = self.run( + "grep 'router {}' {}".format(daemonstr, source) + ).strip() + if result: + self.load_config(daemon) + else: + for daemon in daemons: + self.load_config(daemon) + def load_config(self, daemon, source=None, param=None): """Loads daemon configuration from the specified source Possible daemon values are: TopoRouter.RD_ZEBRA, TopoRouter.RD_RIP, diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index d3438f67e5..4e5fe4c90b 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -1319,6 +1319,7 @@ class Router(Node): self.daemondir = None self.hasmpls = False self.routertype = "frr" + self.unified_config = None self.daemons = { "zebra": 0, "ripd": 0, @@ -1521,21 +1522,28 @@ class Router(Node): ) # print "Daemons before:", self.daemons - if daemon in self.daemons.keys(): - self.daemons[daemon] = 1 + if daemon in self.daemons.keys() or daemon == "frr": + if daemon == "frr": + self.unified_config = 1 + else: + self.daemons[daemon] = 1 if param is not None: 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) + if daemon == "frr" or not self.unified_config: + self.cmd_raises("rm -f " + conf_file) + self.cmd_raises("touch " + conf_file) else: self.cmd_raises("cp {} {}".format(source, conf_file)) - self.cmd_raises("chown {0}:{0} {1}".format(self.routertype, conf_file)) - self.cmd_raises("chmod 664 {}".format(conf_file)) + + if not self.unified_config or daemon == "frr": + self.cmd_raises("chown {0}:{0} {1}".format(self.routertype, conf_file)) + self.cmd_raises("chmod 664 {}".format(conf_file)) + if (daemon == "snmpd") and (self.routertype == "frr"): # /etc/snmp is private mount now - self.cmd('echo "agentXSocket /etc/frr/agentx" > /etc/snmp/frr.conf') + 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): @@ -1557,11 +1565,18 @@ class Router(Node): return self.run_in_window(cmd, title) def startRouter(self, tgen=None): - # Disable integrated-vtysh-config - self.cmd( - 'echo "no service integrated-vtysh-config" >> /etc/%s/vtysh.conf' - % self.routertype - ) + if self.unified_config: + self.cmd( + 'echo "service integrated-vtysh-config" >> /etc/%s/vtysh.conf' + % self.routertype + ) + else: + # Disable integrated-vtysh-config + self.cmd( + 'echo "no service integrated-vtysh-config" >> /etc/%s/vtysh.conf' + % self.routertype + ) + self.cmd( "chown %s:%svty /etc/%s/vtysh.conf" % (self.routertype, self.routertype, self.routertype) @@ -1633,6 +1648,9 @@ class Router(Node): if "all" in vtysh_routers or self.name in vtysh_routers: self.run_in_window("vtysh", title="vt-%s" % self.name) + if self.unified_config: + self.cmd("vtysh -f /etc/frr/frr.conf") + return status def getStdErr(self, daemon): -- 2.39.5