def vtysh_cmd(self, command, isjson=False, daemon=None): """ Runs the provided command string in the vty shell and returns a string with the response. This function also accepts multiple commands, but this mode does not return output for each command. See vtysh_multicmd() for more details. """ # Detect multi line commands if command.find('\n') != -1: return self.vtysh_multicmd(command, daemon=daemon) dparam = '' if daemon is not None: dparam += '-d {}'.format(daemon) vtysh_command = 'vtysh {} -c "{}" 2>/dev/null'.format(dparam, command) output = self.run(vtysh_command) self.logger.info('\nvtysh command => {}\nvtysh output <= {}'.format( command, output)) if isjson is False: return output try: return json.loads(output) except ValueError: logger.warning('vtysh_cmd: failed to convert json output') return {}
def test_pe2_converge_evpn(): "Wait for protocol convergence" tgen = get_topogen() # Don't run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) pe2 = tgen.gears["PE2"] json_file = "{}/{}/evpn.vni.json".format(CWD, pe2.name) expected = json.loads(open(json_file).read()) test_func = partial(show_vni_json_elide_ifindex, pe2, 101, expected) _, result = topotest.run_and_expect(test_func, None, count=45, wait=1) assertmsg = '"{}" JSON output mismatches'.format(pe2.name) assert result is None, assertmsg test_func = partial( check_vni_macs_present, tgen, pe2, 101, (("host1", "host1-eth0"), ("host2", "host2-eth0")), ) _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) if result: logger.warning("%s", result) assert None, '"{}" missing expected MACs'.format(pe2.name)
def setup_module(self, mod): "Sets up the pytest environment" # This function initiates the topology build with Topogen... tgen = Topogen(customize.build_topo, mod.__name__) # ... and here it calls Mininet initialization functions. tgen.start_topology() self.logdir = tgen.logdir logger.info("Topology started") try: self.prestarthooksuccess = customize.ltemplatePreRouterStartHook() except AttributeError: # not defined logger.debug("ltemplatePreRouterStartHook() not defined") if self.prestarthooksuccess != True: logger.info("ltemplatePreRouterStartHook() failed, skipping test") return # This is a sample of configuration loading. router_list = tgen.routers() # For all registered routers, load the zebra configuration file for rname, router in router_list.items(): logger.info("Setting up %s" % rname) for rd_val in TopoRouter.RD: config = os.path.join( self.testdir, "{}/{}.conf".format(rname, TopoRouter.RD[rd_val])) prog = os.path.join(tgen.net[rname].daemondir, TopoRouter.RD[rd_val]) if os.path.exists(config): if os.path.exists(prog): router.load_config(rd_val, config) else: logger.warning( "{} not found, but have {}.conf file".format( prog, TopoRouter.RD[rd_val])) # After loading the configurations, this function loads configured daemons. logger.info("Starting routers") tgen.start_router() try: self.poststarthooksuccess = customize.ltemplatePostRouterStartHook( ) except AttributeError: # not defined logger.debug("ltemplatePostRouterStartHook() not defined") luStart(baseScriptDir=self.scriptdir, baseLogDir=self.logdir, net=tgen.net)
def show_isis_interface_detail(router, rname): """ Get the show isis mpls ldp-sync info in a dictionary format. """ out = topotest.normalize_text( router.vtysh_cmd("show isis interface detail")).splitlines() logger.warning(out) parsed = parse_show_isis_interface_detail(out, rname) logger.warning(parsed) return parsed
def vtysh_cmd(self, command, isjson=False, daemon=None): """ Runs the provided command string in the vty shell and returns a string with the response. This function also accepts multiple commands, but this mode does not return output for each command. See vtysh_multicmd() for more details. """ # Detect multi line commands if command.find("\n") != -1: return self.vtysh_multicmd(command, daemon=daemon) dparam = "" if daemon is not None: dparam += "-d {}".format(daemon) vtysh_command = 'vtysh {} -c "{}" 2>/dev/null'.format(dparam, command) self.logger.info('vtysh command => "{}"'.format(command)) output = self.run(vtysh_command) dbgout = output.strip() if dbgout: if "\n" in dbgout: dbgout = dbgout.replace("\n", "\n\t") self.logger.info("vtysh result:\n\t{}".format(dbgout)) else: self.logger.info('vtysh result: "{}"'.format(dbgout)) if isjson is False: return output try: return json.loads(output) except ValueError as error: logger.warning( "vtysh_cmd: %s: failed to convert json output: %s: %s", self.name, str(output), str(error), ) return {}
def diagnose_env_linux(): """ Run diagnostics in the running environment. Returns `True` when everything is ok, otherwise `False`. """ ret = True # Test log path exists before installing handler. if not os.path.isdir("/tmp"): logger.warning("could not find /tmp for logs") else: os.system("mkdir /tmp/topotests") # Log diagnostics to file so it can be examined later. fhandler = logging.FileHandler( filename="/tmp/topotests/diagnostics.txt") fhandler.setLevel(logging.DEBUG) fhandler.setFormatter( logging.Formatter(fmt="%(asctime)s %(levelname)s: %(message)s")) logger.addHandler(fhandler) logger.info("Running environment diagnostics") # Load configuration config = configparser.ConfigParser(defaults=tgen_defaults) pytestini_path = os.path.join(CWD, "../pytest.ini") config.read(pytestini_path) # Assert that we are running as root if os.getuid() != 0: logger.error("you must run topotest as root") ret = False # Assert that we have mininet if os.system("which mn >/dev/null 2>/dev/null") != 0: logger.error( "could not find mininet binary (mininet is not installed)") ret = False # Assert that we have iproute installed if os.system("which ip >/dev/null 2>/dev/null") != 0: logger.error("could not find ip binary (iproute is not installed)") ret = False # Assert that we have gdb installed if os.system("which gdb >/dev/null 2>/dev/null") != 0: logger.error("could not find gdb binary (gdb is not installed)") ret = False # Assert that FRR utilities exist frrdir = config.get("topogen", "frrdir") if not os.path.isdir(frrdir): logger.error("could not find {} directory".format(frrdir)) ret = False else: try: pwd.getpwnam("frr")[2] except KeyError: logger.warning('could not find "frr" user') try: grp.getgrnam("frr")[2] except KeyError: logger.warning('could not find "frr" group') try: if "frr" not in grp.getgrnam("frrvty").gr_mem: logger.error( '"frr" user and group exist, but user is not under "frrvty"' ) except KeyError: logger.warning('could not find "frrvty" group') for fname in [ "zebra", "ospfd", "ospf6d", "bgpd", "ripd", "ripngd", "isisd", "pimd", "ldpd", "pbrd", ]: path = os.path.join(frrdir, fname) if not os.path.isfile(path): # LDPd is an exception if fname == "ldpd": logger.info( "could not find {} in {}".format(fname, frrdir) + "(LDPd tests will not run)") continue logger.warning("could not find {} in {}".format(fname, frrdir)) ret = False else: if fname != "zebra": continue os.system( "{} -v 2>&1 >/tmp/topotests/frr_zebra.txt".format(path)) # Test MPLS availability krel = platform.release() if topotest.version_cmp(krel, "4.5") < 0: logger.info( 'LDPd tests will not run (have kernel "{}", but it requires 4.5)'. format(krel)) # Test for MPLS Kernel modules available if not topotest.module_present("mpls-router", load=False) != 0: logger.info( "LDPd tests will not run (missing mpls-router kernel module)") if not topotest.module_present("mpls-iptunnel", load=False) != 0: logger.info( "LDPd tests will not run (missing mpls-iptunnel kernel module)") # TODO remove me when we start supporting exabgp >= 4 try: p = os.popen("exabgp -v") line = p.readlines() version = line[0].split() if topotest.version_cmp(version[2], "4") >= 0: logger.warning( "BGP topologies are still using exabgp version 3, expect failures" ) # We want to catch all exceptions # pylint: disable=W0702 except: logger.warning("failed to find exabgp or returned error") # After we logged the output to file, remove the handler. logger.removeHandler(fhandler) return ret
def diagnose_env_linux(): """ Run diagnostics in the running environment. Returns `True` when everything is ok, otherwise `False`. """ ret = True # Test log path exists before installing handler. if not os.path.isdir('/tmp'): logger.warning('could not find /tmp for logs') else: os.system('mkdir /tmp/topotests') # Log diagnostics to file so it can be examined later. fhandler = logging.FileHandler(filename='/tmp/topotests/diagnostics.txt') fhandler.setLevel(logging.DEBUG) fhandler.setFormatter( logging.Formatter(fmt='%(asctime)s %(levelname)s: %(message)s') ) logger.addHandler(fhandler) logger.info('Running environment diagnostics') # Load configuration config = ConfigParser.ConfigParser(tgen_defaults) pytestini_path = os.path.join(CWD, '../pytest.ini') config.read(pytestini_path) # Assert that we are running as root if os.getuid() != 0: logger.error('you must run topotest as root') ret = False # Assert that we have mininet if os.system('which mn >/dev/null 2>/dev/null') != 0: logger.error('could not find mininet binary (mininet is not installed)') ret = False # Assert that we have iproute installed if os.system('which ip >/dev/null 2>/dev/null') != 0: logger.error('could not find ip binary (iproute is not installed)') ret = False # Assert that we have gdb installed if os.system('which gdb >/dev/null 2>/dev/null') != 0: logger.error('could not find gdb binary (gdb is not installed)') ret = False # Assert that FRR utilities exist frrdir = config.get('topogen', 'frrdir') hasfrr = False if not os.path.isdir(frrdir): logger.error('could not find {} directory'.format(frrdir)) ret = False else: hasfrr = True try: pwd.getpwnam('frr')[2] except KeyError: logger.warning('could not find "frr" user') try: grp.getgrnam('frr')[2] except KeyError: logger.warning('could not find "frr" group') try: if 'frr' not in grp.getgrnam('frrvty').gr_mem: logger.error('"frr" user and group exist, but user is not under "frrvty"') except KeyError: logger.warning('could not find "frrvty" group') for fname in ['zebra', 'ospfd', 'ospf6d', 'bgpd', 'ripd', 'ripngd', 'isisd', 'pimd', 'ldpd']: path = os.path.join(frrdir, fname) if not os.path.isfile(path): # LDPd is an exception if fname == 'ldpd': logger.info('could not find {} in {}'.format(fname, frrdir) + '(LDPd tests will not run)') continue logger.warning('could not find {} in {}'.format(fname, frrdir)) ret = False else: if fname != 'zebra': continue os.system( '{} -v 2>&1 >/tmp/topotests/frr_zebra.txt'.format(path) ) # Assert that Quagga utilities exist quaggadir = config.get('topogen', 'quaggadir') if hasfrr: # if we have frr, don't check for quagga pass elif not os.path.isdir(quaggadir): logger.info('could not find {} directory (quagga tests will not run)'.format(quaggadir)) else: ret = True try: pwd.getpwnam('quagga')[2] except KeyError: logger.info('could not find "quagga" user') try: grp.getgrnam('quagga')[2] except KeyError: logger.info('could not find "quagga" group') try: if 'quagga' not in grp.getgrnam('quaggavty').gr_mem: logger.error('"quagga" user and group exist, but user is not under "quaggavty"') except KeyError: logger.warning('could not find "quaggavty" group') for fname in ['zebra', 'ospfd', 'ospf6d', 'bgpd', 'ripd', 'ripngd', 'isisd', 'pimd']: path = os.path.join(quaggadir, fname) if not os.path.isfile(path): logger.warning('could not find {} in {}'.format(fname, quaggadir)) ret = False else: if fname != 'zebra': continue os.system( '{} -v 2>&1 >/tmp/topotests/quagga_zebra.txt'.format(path) ) # Test MPLS availability krel = platform.release() if topotest.version_cmp(krel, '4.5') < 0: logger.info('LDPd tests will not run (have kernel "{}", but it requires 4.5)'.format(krel)) # Test for MPLS Kernel modules available if not topotest.module_present('mpls-router', load=False) != 0: logger.info('LDPd tests will not run (missing mpls-router kernel module)') if not topotest.module_present('mpls-iptunnel', load=False) != 0: logger.info('LDPd tests will not run (missing mpls-iptunnel kernel module)') # TODO remove me when we start supporting exabgp >= 4 try: output = subprocess.check_output(['exabgp', '-v']) line = output.split('\n')[0] version = line.split(' ')[2] if topotest.version_cmp(version, '4') >= 0: logger.warning('BGP topologies are still using exabgp version 3, expect failures') # We want to catch all exceptions # pylint: disable=W0702 except: logger.warning('failed to find exabgp or returned error') # After we logged the output to file, remove the handler. logger.removeHandler(fhandler) return ret
def diagnose_env_linux(rundir): """ Run diagnostics in the running environment. Returns `True` when everything is ok, otherwise `False`. """ ret = True # Load configuration config = configparser.ConfigParser(defaults=tgen_defaults) pytestini_path = os.path.join(CWD, "../pytest.ini") config.read(pytestini_path) # Test log path exists before installing handler. os.system("mkdir -p " + rundir) # Log diagnostics to file so it can be examined later. fhandler = logging.FileHandler( filename="{}/diagnostics.txt".format(rundir)) fhandler.setLevel(logging.DEBUG) fhandler.setFormatter(logging.Formatter(fmt=topolog.FORMAT)) logger.addHandler(fhandler) logger.info("Running environment diagnostics") # Assert that we are running as root if os.getuid() != 0: logger.error("you must run topotest as root") ret = False # Assert that we have mininet # if os.system("which mn >/dev/null 2>/dev/null") != 0: # logger.error("could not find mininet binary (mininet is not installed)") # ret = False # Assert that we have iproute installed if os.system("which ip >/dev/null 2>/dev/null") != 0: logger.error("could not find ip binary (iproute is not installed)") ret = False # Assert that we have gdb installed if os.system("which gdb >/dev/null 2>/dev/null") != 0: logger.error("could not find gdb binary (gdb is not installed)") ret = False # Assert that FRR utilities exist frrdir = config.get("topogen", "frrdir") if not os.path.isdir(frrdir): logger.error("could not find {} directory".format(frrdir)) ret = False else: try: pwd.getpwnam("frr")[2] except KeyError: logger.warning('could not find "frr" user') try: grp.getgrnam("frr")[2] except KeyError: logger.warning('could not find "frr" group') try: if "frr" not in grp.getgrnam("frrvty").gr_mem: logger.error( '"frr" user and group exist, but user is not under "frrvty"' ) except KeyError: logger.warning('could not find "frrvty" group') for fname in [ "zebra", "ospfd", "ospf6d", "bgpd", "ripd", "ripngd", "isisd", "pimd", "pim6d", "ldpd", "pbrd", ]: path = os.path.join(frrdir, fname) if not os.path.isfile(path): # LDPd is an exception if fname == "ldpd": logger.info( "could not find {} in {}".format(fname, frrdir) + "(LDPd tests will not run)") continue logger.warning("could not find {} in {}".format(fname, frrdir)) ret = False else: if fname != "zebra": continue os.system("{} -v 2>&1 >{}/frr_zebra.txt".format(path, rundir)) # Test MPLS availability krel = platform.release() if topotest.version_cmp(krel, "4.5") < 0: logger.info( 'LDPd tests will not run (have kernel "{}", but it requires 4.5)'. format(krel)) # Test for MPLS Kernel modules available if not topotest.module_present("mpls-router", load=False) != 0: logger.info( "LDPd tests will not run (missing mpls-router kernel module)") if not topotest.module_present("mpls-iptunnel", load=False) != 0: logger.info( "LDPd tests will not run (missing mpls-iptunnel kernel module)") if not get_exabgp_cmd(): logger.warning("Failed to find exabgp < 4") logger.removeHandler(fhandler) fhandler.close() return ret
def pytest_runtest_makereport(item, call): "Log all assert messages to default logger with error level" # Nothing happened if call.when == "call": pause = topotest_extra_config["pause"] else: pause = False title = "unset" if call.excinfo is None: error = False else: parent = item.parent modname = parent.module.__name__ # Treat skips as non errors, don't pause after if call.excinfo.typename == "Skipped": pause = False error = False logger.info('test skipped at "{}/{}": {}'.format( modname, item.name, call.excinfo.value)) else: error = True # Handle assert failures parent._previousfailed = item # pylint: disable=W0212 logger.error('test failed at "{}/{}": {}'.format( modname, item.name, call.excinfo.value)) title = "{}/{}".format(modname, item.name) # We want to pause, if requested, on any error not just test cases # (e.g., call.when == "setup") if not pause: pause = (topotest_extra_config["pause_on_error"] or topotest_extra_config["pause"]) # (topogen) Set topology error to avoid advancing in the test. tgen = get_topogen() if tgen is not None: # This will cause topogen to report error on `routers_have_failure`. tgen.set_error("{}/{}".format(modname, item.name)) commander = Commander("pytest") isatty = sys.stdout.isatty() error_cmd = None if error and topotest_extra_config["vtysh_on_error"]: error_cmd = commander.get_exec_path(["vtysh"]) elif error and topotest_extra_config["shell_on_error"]: error_cmd = os.getenv("SHELL", commander.get_exec_path(["bash"])) if error_cmd: is_tmux = bool(os.getenv("TMUX", "")) is_screen = not is_tmux and bool(os.getenv("STY", "")) is_xterm = not is_tmux and not is_screen and bool( os.getenv("DISPLAY", "")) channel = None win_info = None wait_for_channels = [] wait_for_procs = [] # Really would like something better than using this global here. # Not all tests use topogen though so get_topogen() won't work. for node in Mininet.g_mnet_inst.hosts.values(): pause = True if is_tmux: channel = ("{}-{}".format(os.getpid(), Commander.tmux_wait_gen) if not isatty else None) Commander.tmux_wait_gen += 1 wait_for_channels.append(channel) pane_info = node.run_in_window( error_cmd, new_window=win_info is None, background=True, title="{} ({})".format(title, node.name), name=title, tmux_target=win_info, wait_for=channel, ) if is_tmux: if win_info is None: win_info = pane_info elif is_xterm: assert isinstance(pane_info, subprocess.Popen) wait_for_procs.append(pane_info) # Now wait on any channels for channel in wait_for_channels: logger.debug("Waiting on TMUX channel %s", channel) commander.cmd_raises( [commander.get_exec_path("tmux"), "wait", channel]) for p in wait_for_procs: logger.debug("Waiting on TMUX xterm process %s", p) o, e = p.communicate() if p.wait(): logger.warning("xterm proc failed: %s:", proc_error(p, o, e)) if error and topotest_extra_config["cli_on_error"]: # Really would like something better than using this global here. # Not all tests use topogen though so get_topogen() won't work. if Mininet.g_mnet_inst: cli(Mininet.g_mnet_inst, title=title, background=False) else: logger.error("Could not launch CLI b/c no mininet exists yet") while pause and isatty: try: user = raw_input( 'PAUSED, "cli" for CLI, "pdb" to debug, "Enter" to continue: ') except NameError: user = input( 'PAUSED, "cli" for CLI, "pdb" to debug, "Enter" to continue: ') user = user.strip() if user == "cli": cli(Mininet.g_mnet_inst) elif user == "pdb": pdb.set_trace() elif user: print('Unrecognized input: "%s"' % user) else: break
def diagnose_env_linux(): """ Run diagnostics in the running environment. Returns `True` when everything is ok, otherwise `False`. """ ret = True # Test log path exists before installing handler. if not os.path.isdir('/tmp'): logger.warning('could not find /tmp for logs') else: os.system('mkdir /tmp/topotests') # Log diagnostics to file so it can be examined later. fhandler = logging.FileHandler(filename='/tmp/topotests/diagnostics.txt') fhandler.setLevel(logging.DEBUG) fhandler.setFormatter( logging.Formatter(fmt='%(asctime)s %(levelname)s: %(message)s') ) logger.addHandler(fhandler) logger.info('Running environment diagnostics') # Load configuration config = configparser.ConfigParser(tgen_defaults) pytestini_path = os.path.join(CWD, '../pytest.ini') config.read(pytestini_path) # Assert that we are running as root if os.getuid() != 0: logger.error('you must run topotest as root') ret = False # Assert that we have mininet if os.system('which mn >/dev/null 2>/dev/null') != 0: logger.error('could not find mininet binary (mininet is not installed)') ret = False # Assert that we have iproute installed if os.system('which ip >/dev/null 2>/dev/null') != 0: logger.error('could not find ip binary (iproute is not installed)') ret = False # Assert that we have gdb installed if os.system('which gdb >/dev/null 2>/dev/null') != 0: logger.error('could not find gdb binary (gdb is not installed)') ret = False # Assert that FRR utilities exist frrdir = config.get('topogen', 'frrdir') hasfrr = False if not os.path.isdir(frrdir): logger.error('could not find {} directory'.format(frrdir)) ret = False else: hasfrr = True try: pwd.getpwnam('frr')[2] except KeyError: logger.warning('could not find "frr" user') try: grp.getgrnam('frr')[2] except KeyError: logger.warning('could not find "frr" group') try: if 'frr' not in grp.getgrnam('frrvty').gr_mem: logger.error('"frr" user and group exist, but user is not under "frrvty"') except KeyError: logger.warning('could not find "frrvty" group') for fname in ['zebra', 'ospfd', 'ospf6d', 'bgpd', 'ripd', 'ripngd', 'isisd', 'pimd', 'ldpd']: path = os.path.join(frrdir, fname) if not os.path.isfile(path): # LDPd is an exception if fname == 'ldpd': logger.info('could not find {} in {}'.format(fname, frrdir) + '(LDPd tests will not run)') continue logger.warning('could not find {} in {}'.format(fname, frrdir)) ret = False else: if fname != 'zebra': continue os.system( '{} -v 2>&1 >/tmp/topotests/frr_zebra.txt'.format(path) ) # Assert that Quagga utilities exist quaggadir = config.get('topogen', 'quaggadir') if hasfrr: # if we have frr, don't check for quagga pass elif not os.path.isdir(quaggadir): logger.info('could not find {} directory (quagga tests will not run)'.format(quaggadir)) else: ret = True try: pwd.getpwnam('quagga')[2] except KeyError: logger.info('could not find "quagga" user') try: grp.getgrnam('quagga')[2] except KeyError: logger.info('could not find "quagga" group') try: if 'quagga' not in grp.getgrnam('quaggavty').gr_mem: logger.error('"quagga" user and group exist, but user is not under "quaggavty"') except KeyError: logger.warning('could not find "quaggavty" group') for fname in ['zebra', 'ospfd', 'ospf6d', 'bgpd', 'ripd', 'ripngd', 'isisd', 'pimd']: path = os.path.join(quaggadir, fname) if not os.path.isfile(path): logger.warning('could not find {} in {}'.format(fname, quaggadir)) ret = False else: if fname != 'zebra': continue os.system( '{} -v 2>&1 >/tmp/topotests/quagga_zebra.txt'.format(path) ) # Test MPLS availability krel = platform.release() if topotest.version_cmp(krel, '4.5') < 0: logger.info('LDPd tests will not run (have kernel "{}", but it requires 4.5)'.format(krel)) # Test for MPLS Kernel modules available if not topotest.module_present('mpls-router', load=False) != 0: logger.info('LDPd tests will not run (missing mpls-router kernel module)') if not topotest.module_present('mpls-iptunnel', load=False) != 0: logger.info('LDPd tests will not run (missing mpls-iptunnel kernel module)') # TODO remove me when we start supporting exabgp >= 4 try: output = subprocess.check_output(['exabgp', '-v']) line = output.split('\n')[0] version = line.split(' ')[2] if topotest.version_cmp(version, '4') >= 0: logger.warning('BGP topologies are still using exabgp version 3, expect failures') # We want to catch all exceptions # pylint: disable=W0702 except: logger.warning('failed to find exabgp or returned error') # After we logged the output to file, remove the handler. logger.removeHandler(fhandler) return ret