Page MenuHomeClusterLabs Projects

serverenv.py
No OneTemporary

serverenv.py

import os
import re
import time
from boothrunner import BoothRunner
from boothtestenv import BoothTestEnvironment
from utils import get_IP, use_single_instance
class ServerTestEnvironment(BoothTestEnvironment):
'''
boothd site/arbitrator will hang in setup phase while attempting to connect
to an unreachable peer during ticket_catchup(). In a test environment we don't
have any reachable peers. Fortunately, we can still successfully launch a
daemon by only listing our own IP in the config file.
'''
typical_config = """\
# This is like the config in the manual
transport="UDP"
port="9929"
# Here's another comment
#arbitrator="147.2.207.14"
site="147.4.215.19"
#site="147.18.2.1"
ticket="ticketA"
ticket="ticketB"
"""
site_re = re.compile('^site=".+"', re.MULTILINE)
working_config = re.sub(site_re, 'site="%s"' % get_IP(), typical_config, 1)
if not use_single_instance():
# use port based on pid
port_re = re.compile('^port=".+"', re.MULTILINE)
working_config = re.sub(port_re, 'port="%s"' % (9929 + (os.getpid() % 1009)), working_config, 1)
def run_booth(self, expected_exitcode, expected_daemon,
config_text=None, config_file=None, lock_file=True,
args=(), debug=False, foreground=False):
'''
Runs boothd. Defaults to using a temporary lock file and the
standard config file path. There are four possible types of
outcome:
- boothd exits non-zero without launching a daemon (setup phase failed,
e.g. due to invalid configuration file)
- boothd exits zero after launching a daemon (successful operation)
- boothd does not exit (running in foreground mode)
- boothd does not exit (setup phase hangs, e.g. while attempting
to connect to peer during ticket_catchup())
Arguments:
config_text
a string containing the contents of a configuration file to use
config_file
path to a configuration file to use
lock_file
False: don't pass a lockfile parameter to booth via -l
True: pass a temporary lockfile parameter to booth via -l
string: pass the given lockfile path to booth via -l
args
iterable of extra args to pass to booth
expected_exitcode
an integer, or False if booth is not expected to terminate
within the timeout
expected_daemon
True iff a daemon is expected to be launched (this means
running the server in foreground mode via -S;
even though in this case the server's not technically not a daemon,
we still want to treat it like one by checking the lockfile
before and after we kill it)
debug
True means pass the -D parameter
foreground
True means pass the -S parameter
Returns a (pid, return_code, stdout, stderr, runner) tuple,
where return_code/stdout/stderr are None iff pid is still running.
'''
if expected_daemon and expected_exitcode is not None and expected_exitcode != 0:
raise RuntimeError("Shouldn't ever expect daemon to start and then failure")
if not expected_daemon and expected_exitcode == 0:
raise RuntimeError("Shouldn't ever expect success without starting daemon")
self.init_log()
runner = BoothRunner(self.boothd_path, self.mode, args)
if config_text:
config_file = self.write_config_file(config_text)
if config_file:
runner.set_config_file(config_file)
if lock_file is True:
lock_file = os.path.join(self.test_path, 'boothd-lock.pid')
if lock_file:
runner.set_lock_file(lock_file)
if debug:
runner.set_debug()
if foreground:
runner.set_foreground()
runner.show_args()
(pid, return_code, stdout, stderr) = runner.run(expected_exitcode)
self.check_return_code(pid, return_code, expected_exitcode)
if expected_daemon:
self.check_daemon_handling(runner, expected_daemon)
elif return_code is None:
# This isn't strictly necessary because we ensure no
# daemon is running from within test setUp(), but it's
# probably a good idea to tidy up after ourselves anyway.
self.kill_pid(pid)
return (pid, return_code, stdout, stderr, runner)
def write_config_file(self, config_text):
config_file = self.get_tempfile('config')
c = open(config_file, 'w')
c.write(config_text)
c.close()
return config_file
def kill_pid(self, pid):
print("killing %d ..." % pid)
os.kill(pid, 15)
print("killed")
# Wait for lock file to appear if must_exist is True, or disappear if
# must_exist is False for maximum of timeout seconds
def wait_for_lock_file(self, lock_file, must_exist = True, timeout = 30):
start = time.time()
wait = 0.1
while True:
if must_exist and os.path.exists(lock_file):
# Lock file must contain single line
l = open(lock_file)
lines = l.readlines()
l.close()
if len(lines) == 1:
return True
if not must_exist and not os.path.exists(lock_file):
return True
elapsed = time.time() - start
if elapsed + wait > timeout:
wait = timeout - elapsed
appear_str = "appear" if must_exist else "disappear"
print("Waiting for lock file %s to %s for %.1fs ..." % (lock_file, appear_str, wait))
time.sleep(wait)
elapsed = time.time() - start
if elapsed >= timeout:
return False
wait *= 2
def check_daemon_handling(self, runner, expected_daemon):
'''
Check that the lock file contains a pid referring to a running
daemon. Then kill the daemon, and ensure that the lock file
vanishes (bnc#749763).
'''
self.wait_for_lock_file(runner.lock_file, True, 30)
daemon_pid = self.get_daemon_pid_from_lock_file(runner.lock_file)
err = "lock file should contain pid"
if not expected_daemon:
err += ", even though we didn't expect a daemon"
self.assertTrue(daemon_pid is not None, err)
daemon_running = self.is_pid_running_daemon(daemon_pid)
err = "pid in lock file should refer to a running daemon"
self.assertTrue(daemon_running, err)
if daemon_running:
self.kill_pid(int(daemon_pid))
self.wait_for_lock_file(runner.lock_file, False, 30)
time.sleep(1)
daemon_pid = self.get_daemon_pid_from_lock_file(runner.lock_file)
self.assertTrue(daemon_pid is None,
'bnc#749763: lock file should vanish after daemon is killed')
def get_daemon_pid_from_lock_file(self, lock_file):
'''
Returns the pid contained in lock_file, or None if it doesn't exist.
'''
if not os.path.exists(lock_file):
print("%s does not exist" % lock_file)
return None
l = open(lock_file)
lines = l.readlines()
l.close()
self.assertEqual(len(lines), 1, "Lock file should contain one line")
pid = re.search('\\bbooth_pid="?(\\d+)"?', lines[0]).group(1)
print("lockfile contains: <%s>" % pid)
return pid
def is_pid_running_daemon(self, pid):
'''
Returns true iff the given pid refers to a running boothd process.
'''
path = "/proc/%s" % pid
pid_running = os.path.isdir(path)
# print "======"
# import subprocess
# print subprocess.check_output(['lsof', '-p', pid])
# print subprocess.check_output(['ls', path])
# print subprocess.check_output(['cat', "/proc/%s/cmdline" % pid])
# print "======"
if not pid_running:
return False
c = open("/proc/%s/cmdline" % pid)
cmdline = "".join(c.readlines())
print(cmdline)
c.close()
if cmdline.find('boothd') == -1:
print('no boothd in cmdline:', cmdline)
return False
# self.assertRegexpMatches(
# cmdline,
# 'boothd',
# "lock file should refer to pid of running boothd"
# )
return True
def _test_buffer_overflow(self, expected_error, **args):
(pid, ret, stdout, stderr, runner) = \
self.run_booth(expected_exitcode=1, expected_daemon=False, **args)
self.assertRegexpMatches(stderr, expected_error)

File Metadata

Mime Type
text/x-script.python
Expires
Sat, Jan 25, 7:10 AM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1196152
Default Alt Text
serverenv.py (8 KB)

Event Timeline