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
This commit is contained in:
Neels Hofmeyr 2017-04-10 03:45:30 +02:00
parent 85eb324165
commit 5356d0adce
11 changed files with 126 additions and 45 deletions

View File

@ -1 +1 @@
- sms:trx
- sms:sysmo

View File

@ -17,12 +17,12 @@ nitb_bts:
timeslot_list:
- phys_chan_config: CCCH+SDCCH4
- phys_chan_config: SDCCH8
- phys_chan_config: TCH_F/TCH_H/PDCH
- phys_chan_config: TCH_F/TCH_H/PDCH
- phys_chan_config: TCH_F/TCH_H/PDCH
- phys_chan_config: TCH_F/TCH_H/PDCH
- phys_chan_config: TCH_F/TCH_H/PDCH
- phys_chan_config: TCH_F/TCH_H/PDCH
- phys_chan_config: TCH/F_TCH/H_PDCH
- phys_chan_config: TCH/F_TCH/H_PDCH
- phys_chan_config: TCH/F_TCH/H_PDCH
- phys_chan_config: TCH/F_TCH/H_PDCH
- phys_chan_config: TCH/F_TCH/H_PDCH
- phys_chan_config: TCH/F_TCH/H_PDCH
osmo_bts_sysmo:
ipa_unit_id: 1123

View File

@ -1,9 +1,9 @@
# all hardware and interfaces available to this osmo-gsm-tester
nitb_iface:
- addr: 127.0.0.10
- addr: 127.0.0.11
- addr: 127.0.0.12
- addr: 10.42.42.1
- addr: 10.42.42.2
- addr: 10.42.42.3
bts:
- label: sysmoBTS 1002

View File

@ -0,0 +1,3 @@
resources:
bts:
- type: sysmo

View File

@ -10,7 +10,7 @@ ms_mt = suite.modem()
print('start nitb and bts...')
nitb.bts_add(bts)
nitb.start()
sleep(.1)
sleep(1)
assert nitb.running()
bts.start()
@ -19,7 +19,7 @@ nitb.subscriber_add(ms_mt)
ms_mo.connect(nitb)
ms_mt.connect(nitb)
wait(nitb.subscriber_attached, ms_mo, ms_mt)
wait(nitb.subscriber_attached, ms_mo, ms_mt, timeout=20)
sms = ms_mo.sms_send(ms_mt.msisdn)
wait(ms_mt.sms_received, sms)

View File

@ -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()

View File

@ -17,18 +17,29 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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)

View File

@ -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() ]

View File

@ -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

View File

@ -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

View File

@ -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')