]> git.puffer.fish Git - mirror/frr.git/commitdiff
topogen: support configuration file
authorRafael Zalamena <rzalamena@gmail.com>
Tue, 27 Jun 2017 21:11:02 +0000 (18:11 -0300)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 28 Nov 2018 01:22:11 +0000 (20:22 -0500)
Use a configuration file for casual settings like:

* Verbosity level (helps when debugging mininet issues)
* Custom daemon directory (in order to support running different daemon
  binaries without touching tests)
* Daemon type switch: allow running quagga without touching any test
  files

Also fix the add_router() documentation to include all options.

tests/topotests/GUIDELINES.md
tests/topotests/lib/topogen.py
tests/topotests/lib/topotest.py
tests/topotests/pytest.ini

index 1566705bc1b8e1610f6e29a1b0786dbbb856a7a3..8c26c837b97f98ed58c18dc3356f1542dcd52b6b 100644 (file)
@@ -552,3 +552,15 @@ r1
 *** Starting CLI:
 mininet>
 ```
+
+To enable more debug messages in other Topogen subsystems (like Mininet), more
+logging messages can be displayed by modifying the test configuration file
+`pytest.ini`:
+
+```ini
+[topogen]
+# Change the default verbosity line from 'info'...
+#verbosity = info
+# ...to 'debug'
+verbosity = debug
+```
index 97f006c59cda40d57878c19f9cbad7162a876134..ed0339d8f0956d4b14faaab10f9b52bb8527b010 100644 (file)
@@ -41,6 +41,7 @@ Basic usage instructions:
 import os
 import sys
 import json
+import ConfigParser
 
 from mininet.net import Mininet
 from mininet.log import setLogLevel
@@ -48,6 +49,8 @@ from mininet.cli import CLI
 
 from lib import topotest
 
+CWD = os.path.dirname(os.path.realpath(__file__))
+
 # pylint: disable=C0103
 # Global Topogen variable. This is being used to keep the Topogen available on
 # all test functions without declaring a test local variable.
@@ -75,7 +78,10 @@ def set_topogen(tgen):
 class Topogen(object):
     "A topology test builder helper."
 
+    CONFIG_SECTION = 'topogen'
+
     def __init__(self, cls):
+        self.config = None
         self.topo = None
         self.net = None
         self.gears = {}
@@ -97,6 +103,9 @@ class Topogen(object):
         # Set the global variable so the test cases can access it anywhere
         set_topogen(self)
 
+        # Load the default topology configurations
+        self._load_config()
+
         # Initialize the API
         self._mininet_reset()
         cls()
@@ -104,11 +113,28 @@ class Topogen(object):
         for gear in self.gears.values():
             gear.net = self.net
 
+    def _load_config(self):
+        """
+        Loads the configuration file `pytest.ini` located at the root dir of
+        topotests.
+        """
+        defaults = {
+            'verbosity': 'info',
+            'frrdir': '/usr/lib/frr',
+            'quaggadir': '/usr/lib/quagga',
+            'routertype': 'frr',
+        }
+        self.config = ConfigParser.ConfigParser(defaults)
+        pytestini_path = os.path.join(CWD, '../pytest.ini')
+        self.config.read(pytestini_path)
+
     def add_router(self, name=None, cls=topotest.Router, **params):
         """
         Adds a new router to the topology. This function has the following
         options:
-        name: (optional) select the router name
+        * `name`: (optional) select the router name
+        * `daemondir`: (optional) custom daemon binary directory
+        * `routertype`: (optional) `quagga` or `frr`
         Returns a TopoRouter.
         """
         if name is None:
@@ -116,6 +142,11 @@ class Topogen(object):
         if name in self.gears:
             raise KeyError('router already exists')
 
+        params['frrdir'] = self.config.get(self.CONFIG_SECTION, 'frrdir')
+        params['quaggadir'] = self.config.get(self.CONFIG_SECTION, 'quaggadir')
+        if not params.has_key('routertype'):
+            params['routertype'] = self.config.get(self.CONFIG_SECTION, 'routertype')
+
         self.gears[name] = TopoRouter(self, cls, name, **params)
         self.routern += 1
         return self.gears[name]
@@ -167,7 +198,7 @@ class Topogen(object):
         return dict((rname, gear) for rname, gear in self.gears.iteritems()
                     if isinstance(gear, TopoRouter))
 
-    def start_topology(self, log_level='info'):
+    def start_topology(self, log_level=None):
         """
         Starts the topology class. Possible `log_level`s are:
         'debug': all information possible
@@ -177,6 +208,10 @@ class Topogen(object):
         'error': only error and critical messages
         'critical': only critical messages
         """
+        # If log_level is not specified use the configuration.
+        if log_level is None:
+            log_level = self.config.get('topogen', 'verbosity')
+
         # Run mininet
         setLogLevel(log_level)
         self.net.start()
index 9f540fc86f3b9dc10117b4f7e0d15ae79c7309aa..da7dc06191c3ff0c0a97df7c88dd4ac7406f75be 100644 (file)
@@ -259,6 +259,26 @@ class Router(Node):
                         'ospf6d': 0, 'isisd': 0, 'bgpd': 0, 'pimd': 0,
                         'ldpd': 0}
 
+    def _config_frr(self, **params):
+        "Configure FRR binaries"
+        self.daemondir = params.get('frrdir')
+        if self.daemondir is None:
+            self.daemondir = '/usr/lib/frr'
+
+        zebra_path = os.path.join(self.daemondir, 'zebra')
+        if not os.path.isfile(zebra_path):
+            raise Exception("FRR zebra binary doesn't exist at {}".format(zebra_path))
+
+    def _config_quagga(self, **params):
+        "Configure Quagga binaries"
+        self.daemondir = params.get('quaggadir')
+        if self.daemondir is None:
+            self.daemondir = '/usr/lib/quagga'
+
+        zebra_path = os.path.join(self.daemondir, 'zebra')
+        if not os.path.isfile(zebra_path):
+            raise Exception("Quagga zebra binary doesn't exist at {}".format(zebra_path))
+
     # pylint: disable=W0221
     # Some params are only meaningful for the parent class.
     def config(self, **params):
@@ -267,12 +287,11 @@ class Router(Node):
         # User did not specify the daemons directory, try to autodetect it.
         self.daemondir = params.get('daemondir')
         if self.daemondir is None:
-            self.daemondir = '/usr/lib/frr'
-            if not os.path.isfile(os.path.join(self.daemondir, 'zebra')):
-                self.daemondir = '/usr/lib/quagga'
-                self.routertype = 'quagga'
-                if not os.path.isfile(os.path.join(self.daemondir, 'zebra')):
-                    raise Exception('No FRR or Quagga binaries found')
+            self.routertype = params.get('routertype', 'frr')
+            if self.routertype == 'quagga':
+                self._config_quagga(**params)
+            else:
+                self._config_frr(**params)
         else:
             # Test the provided path
             zpath = os.path.join(self.daemondir, 'zebra')
index a744b34aae74e5233b01d2c699e03a5f87e168d5..1866bae1cf10a5b1ee487d779b338a9654437779 100644 (file)
@@ -1,3 +1,19 @@
 # Skip pytests example directory
 [pytest]
 norecursedirs = .git example-test
+
+[topogen]
+# Default configuration values
+#
+# 'verbosity' controls how much data the underline systems will use to
+# provide output (e.g. mininet output, test debug output etc...). The
+# value is 'info', but can be changed to 'debug' to provide more details.
+#verbosity = info
+
+# Default daemons binaries path.
+#frrdir = /usr/lib/frr
+#quaggadir = /usr/lib/quagga
+
+# Default router type to use. Possible values are:
+# 'frr' and 'quagga'.
+#routertype = frr