tests: Enhance topotests scripts to kill/start specific Daemons

1. Added APIs to topogen.py and topotest.py to kill/start specific Daemons,
   ex - bgpd, staticd

Signed-off-by: Kuldeep Kashyap <kashyapk@vmware.com>
This commit is contained in:
Kuldeep Kashyap 2020-04-13 14:47:45 +00:00
parent 81ad029173
commit c65a7e26dc
2 changed files with 161 additions and 0 deletions

View File

@ -707,6 +707,38 @@ class TopoRouter(TopoGear):
self.logger.debug("stopping")
return self.tgen.net[self.name].stopRouter(wait, assertOnError)
def startDaemons(self, daemons):
"""
Start Daemons: to start specific daemon(user defined daemon only)
* Start daemons (e.g. FRR/Quagga)
* Configure daemon logging files
"""
self.logger.debug('starting')
nrouter = self.tgen.net[self.name]
result = nrouter.startRouterDaemons(daemons)
# Enable all daemon command logging, logging files
# and set them to the start dir.
for daemon, enabled in nrouter.daemons.iteritems():
for d in daemons:
if enabled == 0:
continue
self.vtysh_cmd('configure terminal\nlog commands\nlog file {}.log'.\
format(daemon), daemon=daemon)
if result != '':
self.tgen.set_error(result)
return result
def killDaemons(self, daemons, wait=True, assertOnError=True):
"""
Kill specific daemon(user defined daemon only)
forcefully using SIGKILL
"""
self.logger.debug('Killing daemons using SIGKILL..')
return self.tgen.net[self.name].killRouterDaemons(daemons, wait, assertOnError)
def vtysh_cmd(self, command, isjson=False, daemon=None):
"""
Runs the provided command string in the vty shell and returns a string

View File

@ -1088,6 +1088,135 @@ class Router(Node):
def getLog(self, log, daemon):
return self.cmd("cat {}/{}/{}.{}".format(self.logdir, self.name, daemon, log))
def startRouterDaemons(self, daemons):
# Starts actual daemons without init (ie restart)
# cd to per node directory
self.cmd('cd {}/{}'.format(self.logdir, self.name))
self.cmd('umask 000')
#Re-enable to allow for report per run
self.reportCores = True
rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype)
for daemon in daemons:
if daemon == 'zebra':
# Start Zebra first
if self.daemons['zebra'] == 1:
zebra_path = os.path.join(self.daemondir, 'zebra')
zebra_option = self.daemons_options['zebra']
self.cmd('{0} {1} > zebra.out 2> zebra.err &'.format(
zebra_path, zebra_option, self.logdir, self.name
))
self.waitOutput()
logger.debug('{}: {} zebra started'.format(self, self.routertype))
sleep(1, '{}: waiting for zebra to start'.format(self.name))
# Fix Link-Local Addresses
# Somehow (on Mininet only), Zebra removes the IPv6 Link-Local
# addresses on start. Fix this
self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done')
if daemon == 'staticd':
# Start staticd next if required
if self.daemons['staticd'] == 1:
staticd_path = os.path.join(self.daemondir, 'staticd')
staticd_option = self.daemons_options['staticd']
self.cmd('{0} {1} > staticd.out 2> staticd.err &'.format(
staticd_path, staticd_option, self.logdir, self.name
))
self.waitOutput()
logger.debug('{}: {} staticd started'.format(self, self.routertype))
sleep(1, '{}: waiting for staticd to start'.format(self.name))
# Now start all the daemons
# Skip disabled daemons and zebra
if self.daemons[daemon] == 0 or daemon == 'zebra' or daemon == 'staticd':
continue
daemon_path = os.path.join(self.daemondir, daemon)
self.cmd('{0} > {1}.out 2> {1}.err &'.format(
daemon_path, daemon
))
self.waitOutput()
logger.debug('{}: {} {} started'.format(self, self.routertype, daemon))
sleep(1, '{}: waiting for {} to start'.format(self.name, daemon))
rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype)
if re.search(r"No such file or directory", rundaemons):
return "Daemons are not running"
return ""
def killRouterDaemons(self, daemons, wait=True, assertOnError=True,
minErrorVersion='5.1'):
# Kill Running Quagga or FRR specific
# Daemons(user specified daemon only) using SIGKILL
rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype)
errors = ""
daemonsNotRunning = []
if re.search(r"No such file or directory", rundaemons):
return errors
for daemon in daemons:
if rundaemons is not None and daemon in rundaemons:
numRunning = 0
for d in StringIO.StringIO(rundaemons):
if re.search(r"%s" % daemon, d):
daemonpid = self.cmd('cat %s' % d.rstrip()).rstrip()
if (daemonpid.isdigit() and pid_exists(int(daemonpid))):
logger.info('{}: killing {}'.format(
self.name,
os.path.basename(d.rstrip().rsplit(".", 1)[0])
))
self.cmd('kill -9 %s' % daemonpid)
self.waitOutput()
if pid_exists(int(daemonpid)):
numRunning += 1
if wait and numRunning > 0:
sleep(2, '{}: waiting for {} daemon to be stopped'.\
format(self.name, daemon))
# 2nd round of kill if daemons didn't exit
for d in StringIO.StringIO(rundaemons):
if re.search(r"%s" % daemon, d):
daemonpid = \
self.cmd('cat %s' % d.rstrip()).rstrip()
if (daemonpid.isdigit() and pid_exists(
int(daemonpid))):
logger.info('{}: killing {}'.format(
self.name,
os.path.basename(d.rstrip().\
rsplit(".", 1)[0])
))
self.cmd('kill -9 %s' % daemonpid)
self.waitOutput()
self.cmd('rm -- {}'.format(d.rstrip()))
if wait:
errors = self.checkRouterCores(reportOnce=True)
if self.checkRouterVersion('<', minErrorVersion):
#ignore errors in old versions
errors = ""
if assertOnError and len(errors) > 0:
assert "Errors found - details follow:" == 0, errors
errors = ""
# Check Memory leaks
if pytest.config.getoption('--valgrind'):
mem_leak, mem_data = self.check_mem_leaks_valgrind(
daemon
)
if mem_leak:
for d_name, data in mem_data.items():
if data:
logger.error(
"Memory leaks in router [%s] for "
"daemon [%s]", self.name, daemon)
errors = "Router [%s] has memory leak, Check" \
" logs for details." % self.name
else:
daemonsNotRunning.append(daemon)
if len(daemonsNotRunning) > 0:
errors = errors+"Daemons are not running", daemonsNotRunning
return errors
def checkRouterCores(self, reportLeaks=True, reportOnce=False):
if reportOnce and not self.reportCores:
return