From 5356d0adcef703dc965b03028e6c9a4afd23fb79 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Mon, 10 Apr 2017 03:45:30 +0200 Subject: trying to get sysmobts to work and various details I know that these commit messages aren't very good, but the code is not stable yet, so I'm not bothering with details. Change-Id: I2d5e5f4a5407725d71093cbd71ef97b271eb8197 --- src/osmo_gsm_tester/bts_osmotrx.py | 7 ---- src/osmo_gsm_tester/bts_sysmo.py | 75 ++++++++++++++++++++++++++++++++++++-- src/osmo_gsm_tester/log.py | 7 ++-- src/osmo_gsm_tester/osmo_ctrl.py | 2 + src/osmo_gsm_tester/process.py | 37 ++++++++++++------- src/osmo_gsm_tester/suite.py | 16 +++++--- 6 files changed, 111 insertions(+), 33 deletions(-) (limited to 'src/osmo_gsm_tester') diff --git a/src/osmo_gsm_tester/bts_osmotrx.py b/src/osmo_gsm_tester/bts_osmotrx.py index cff63ab..2bdacec 100644 --- a/src/osmo_gsm_tester/bts_osmotrx.py +++ b/src/osmo_gsm_tester/bts_osmotrx.py @@ -24,7 +24,6 @@ class OsmoBtsTrx(log.Origin): suite_run = None nitb = None run_dir = None - processes = None inst = None env = None @@ -37,8 +36,6 @@ class OsmoBtsTrx(log.Origin): self.conf = conf self.set_name('osmo-bts-trx') self.set_log_category(log.C_RUN) - self.processes = {} - self.inst = None self.env = {} def start(self): @@ -62,9 +59,6 @@ class OsmoBtsTrx(log.Origin): self.suite_run.poll() def launch_process(self, binary_name, *args): - if self.processes.get(binary_name) is not None: - raise RuntimeError('Attempt to launch twice: %r' % binary_name) - binary = os.path.abspath(self.inst.child('bin', binary_name)) run_dir = self.run_dir.new_dir(binary_name) if not os.path.isfile(binary): @@ -72,7 +66,6 @@ class OsmoBtsTrx(log.Origin): proc = process.Process(binary_name, run_dir, (binary,) + args, env=self.env) - self.processes[binary_name] = proc self.suite_run.remember_to_stop(proc) proc.launch() diff --git a/src/osmo_gsm_tester/bts_sysmo.py b/src/osmo_gsm_tester/bts_sysmo.py index de79f65..190297f 100644 --- a/src/osmo_gsm_tester/bts_sysmo.py +++ b/src/osmo_gsm_tester/bts_sysmo.py @@ -17,18 +17,29 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from . import log, config, util, template +import os +from . import log, config, util, template, process class SysmoBts(log.Origin): suite_run = None nitb = None run_dir = None + inst = None + remote_addr = None + remote_inst = None + remote_env = None + remote_dir = None + + REMOTE_DIR = '/osmo-gsm-tester' + BTS_SYSMO_BIN = 'osmo-bts-sysmo' + BTS_SYSMO_CFG = 'osmo-bts-sysmo.cfg' def __init__(self, suite_run, conf): self.suite_run = suite_run self.conf = conf self.set_name('osmo-bts-sysmo') self.set_log_category(log.C_RUN) + self.remote_env = {} def start(self): if self.nitb is None: @@ -36,12 +47,68 @@ class SysmoBts(log.Origin): self.log('Starting sysmoBTS to connect to', self.nitb) self.run_dir = util.Dir(self.suite_run.trial.get_run_dir().new_dir(self.name())) self.configure() - self.err('SysmoBts is not yet implemented') + + self.inst = util.Dir(os.path.abspath(self.suite_run.trial.get_inst(SysmoBts.BTS_SYSMO_BIN))) + lib = self.inst.child('lib') + if not os.path.isdir(lib): + self.raise_exn('No lib/ in', self.inst) + if not self.inst.isfile('bin', SysmoBts.BTS_SYSMO_BIN): + self.raise_exn('No osmo-bts-sysmo binary in', self.inst) + + self.remote_dir = util.Dir(SysmoBts.REMOTE_DIR) + self.remote_inst = util.Dir(self.remote_dir.child(os.path.basename(str(self.inst)))) + + self.run_remote('rm-remote-dir', ('test', '!', '-d', SysmoBts.REMOTE_DIR, '||', 'rm', '-rf', SysmoBts.REMOTE_DIR)) + self.run_remote('mk-remote-dir', ('mkdir', '-p', SysmoBts.REMOTE_DIR)) + self.run_local('scp-inst-to-sysmobts', + ('scp', '-r', str(self.inst), '%s:%s' % (self.remote_addr, str(self.remote_inst)))) + + remote_run_dir = self.remote_dir.child(SysmoBts.BTS_SYSMO_BIN) + self.run_remote('mk-remote-run-dir', ('mkdir', '-p', remote_run_dir)) + + remote_config_file = self.remote_dir.child(SysmoBts.BTS_SYSMO_CFG) + self.run_local('scp-cfg-to-sysmobts', + ('scp', '-r', self.config_file, '%s:%s' % (self.remote_addr, remote_config_file))) + + remote_lib = self.remote_inst.child('lib') + remote_binary = self.remote_inst.child('bin', 'osmo-bts-sysmo') + self.launch_remote('osmo-bts-sysmo', + ('LD_LIBRARY_PATH=%s' % remote_lib, + remote_binary, '-c', remote_config_file, '-r', '1'), + remote_cwd=remote_run_dir) + + def _process_remote(self, name, popen_args, remote_cwd=None): + run_dir = self.run_dir.new_dir(name) + return process.RemoteProcess(name, run_dir, self.remote_addr, remote_cwd, + popen_args) + + def run_remote(self, name, popen_args, remote_cwd=None): + proc = self._process_remote(name, popen_args, remote_cwd) + proc.launch() + proc.wait() + if proc.result != 0: + proc.raise_exn('Exited in error') + + def launch_remote(self, name, popen_args, remote_cwd=None): + proc = self._process_remote(name, popen_args, remote_cwd) + self.suite_run.remember_to_stop(proc) + proc.launch() + + def run_local(self, name, popen_args): + run_dir = self.run_dir.new_dir(name) + proc = process.Process(name, run_dir, popen_args) + proc.launch() + proc.wait() + if proc.result != 0: + proc.raise_exn('Exited in error') def configure(self): if self.nitb is None: raise RuntimeError('BTS needs to be added to a NITB before it can be configured') - self.config_file = self.run_dir.new_file('osmo-bts-sysmo.cfg') + + self.remote_addr = self.conf.get('addr') + + self.config_file = self.run_dir.new_file(SysmoBts.BTS_SYSMO_CFG) self.dbg(config_file=self.config_file) values = { 'osmo_bts_sysmo': config.get_defaults('osmo_bts_sysmo') } @@ -51,7 +118,7 @@ class SysmoBts(log.Origin): self.dbg(conf=values) with open(self.config_file, 'w') as f: - r = template.render('osmo-bts-sysmo.cfg', values) + r = template.render(SysmoBts.BTS_SYSMO_CFG, values) self.dbg(r) f.write(r) diff --git a/src/osmo_gsm_tester/log.py b/src/osmo_gsm_tester/log.py index a4f78df..f56d2c9 100644 --- a/src/osmo_gsm_tester/log.py +++ b/src/osmo_gsm_tester/log.py @@ -66,7 +66,7 @@ class LogTarget: get_time_str = lambda self: time.strftime(self.log_time_fmt) # sink that gets each complete logging line - log_sink = sys.stderr.write + log_sink = sys.__stdout__.write category_levels = None @@ -182,8 +182,9 @@ class LogTarget: loglevel, ' '.join(log_line)) - self.log_sink(log_str.strip() + '\n') - + if not log_str.endswith('\n'): + log_str = log_str + '\n' + self.log_sink(log_str) targets = [ LogTarget() ] diff --git a/src/osmo_gsm_tester/osmo_ctrl.py b/src/osmo_gsm_tester/osmo_ctrl.py index c3a09db..736c943 100644 --- a/src/osmo_gsm_tester/osmo_ctrl.py +++ b/src/osmo_gsm_tester/osmo_ctrl.py @@ -79,10 +79,12 @@ class OsmoCtrl(log.Origin): self._send(getmsg) def __enter__(self): + super().__enter__() self.connect() return self def __exit__(self, *exc_info): self.disconnect() + super().__exit__(*exc_info) # vim: expandtab tabstop=4 shiftwidth=4 diff --git a/src/osmo_gsm_tester/process.py b/src/osmo_gsm_tester/process.py index 8152ff0..78814c0 100644 --- a/src/osmo_gsm_tester/process.py +++ b/src/osmo_gsm_tester/process.py @@ -22,7 +22,7 @@ import time import subprocess import signal -from . import log +from . import log, test from .util import Dir class Process(log.Origin): @@ -166,7 +166,9 @@ class Process(log.Origin): if self.result is not None: self.cleanup() - def is_running(self): + def is_running(self, poll_first=True): + if poll_first: + self.poll() return self.process_obj is not None and self.result is None def get_output(self, which): @@ -178,9 +180,12 @@ class Process(log.Origin): return f2.read() def get_output_tail(self, which, tail=10, prefix=''): - out = self.get_output(which).splitlines() + out = self.get_output(which) + if not out: + return None + out = out.splitlines() tail = min(len(out), tail) - return ('\n' + prefix).join(out[-tail:]) + return prefix + ('\n' + prefix).join(out[-tail:]) def get_stdout(self): return self.get_output('stdout') @@ -194,28 +199,32 @@ class Process(log.Origin): def get_stderr_tail(self, tail=10, prefix=''): return self.get_output_tail('stderr', tail, prefix) - def terminated(self): - self.poll() + def terminated(self, poll_first=True): + if poll_first: + self.poll() return self.result is not None - def wait(self): - self.process_obj.wait() - self.poll() + def wait(self, timeout=300): + test.wait(self.terminated, timeout=timeout) class RemoteProcess(Process): - def __init__(self, remote_host, remote_cwd, *process_args, **process_kwargs): - super().__init__(*process_args, **process_kwargs) + def __init__(self, name, run_dir, remote_host, remote_cwd, popen_args, **popen_kwargs): + super().__init__(name, run_dir, popen_args, **popen_kwargs) self.remote_host = remote_host self.remote_cwd = remote_cwd # hacky: instead of just prepending ssh, i.e. piping stdout and stderr # over the ssh link, we should probably run on the remote side, # monitoring the process remotely. - self.popen_args = ['ssh', '-t', self.remote_host, - 'cd "%s"; %s' % (self.remote_cwd, - ' '.join(['"%s"' % arg for arg in self.popen_args]))] + if self.remote_cwd: + cd = 'cd "%s"; ' % self.remote_cwd + else: + cd = '' + self.popen_args = ['ssh', self.remote_host, + '%s%s' % (cd, + ' '.join(self.popen_args))] self.dbg(self.popen_args, dir=self.run_dir, conf=self.popen_kwargs) # vim: expandtab tabstop=4 shiftwidth=4 diff --git a/src/osmo_gsm_tester/suite.py b/src/osmo_gsm_tester/suite.py index 2d6c67b..08965b5 100644 --- a/src/osmo_gsm_tester/suite.py +++ b/src/osmo_gsm_tester/suite.py @@ -232,9 +232,11 @@ class SuiteRun(log.Origin): self.log('using MSISDN', msisdn) return msisdn - def wait(self, condition, *condition_args, timeout=300, **condition_kwargs): + def _wait(self, condition, condition_args, condition_kwargs, timeout, timestep): if not timeout or timeout < 0: raise RuntimeError('wait() *must* time out at some point. timeout=%r' % timeout) + if timestep < 0.1: + timestep = 0.1 started = time.time() while True: @@ -244,17 +246,21 @@ class SuiteRun(log.Origin): waited = time.time() - started if waited > timeout: return False - time.sleep(.1) + time.sleep(timestep) + + def wait(self, condition, *condition_args, timeout=300, timestep=1, **condition_kwargs): + if not self._wait(condition, condition_args, condition_kwargs, timeout, timestep): + raise RuntimeError('Timeout expired') def sleep(self, seconds): - self.wait(lambda: False, timeout=seconds) + assert seconds > 0. + self._wait(lambda: False, [], {}, timeout=seconds, timestep=min(seconds, 1)) def poll(self): ofono_client.poll() if self._processes: for process in self._processes: - process.poll() - if not process.is_running(): + if process.terminated(): process.log_stdout_tail() process.log_stderr_tail() process.raise_exn('Process ended prematurely') -- cgit v1.2.3