blob: 771f2b8ebc5a3e7f633540b5f2adc56fa99785b4 [file] [log] [blame]
Pau Espin Pedrol2eafb032020-01-29 17:56:14 +01001# osmo_gsm_tester: specifics for remote nodes
2#
3# Copyright (C) 2020 by sysmocom - s.f.m.c. GmbH
4#
5# Author: Pau Espin Pedrol <pespin@sysmocom.de>
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20import stat
21import os
22import re
23import pprint
24
25from . import log, util, config, template, process, osmo_ctrl, pcap_recorder
26
27class RemoteHost(log.Origin):
28
29 WRAPPER_SCRIPT = 'ssh_sigkiller.sh'
30
31 def __init__(self, run_dir, remote_user = 'root', remote_host = 'localhost', remote_cwd=None):
32 super().__init__(log.C_RUN, 'host-' + remote_user + '@' + remote_host)
33 self.run_dir = util.Dir(run_dir.new_dir(self.name()))
34 self.remote_user = remote_user
35 self.remote_host = remote_host
36 self.remote_cwd = remote_cwd
Pau Espin Pedrolf6d45ad2020-02-11 14:39:15 +010037 self.remote_env = {}
Pau Espin Pedrol2eafb032020-01-29 17:56:14 +010038
39 def user(self):
40 return self.remote_user
41
42 def host(self):
43 return self.remote_host
44
45 def cwd(self):
46 return self.remote_cwd
47
Pau Espin Pedrolf6d45ad2020-02-11 14:39:15 +010048 def set_remote_env(self, remote_env_dict):
49 self.remote_env = remote_env_dict
50
51 def get_remote_env(self):
52 return self.remote_env
53
54 def RemoteProcess(self, name, popen_args, remote_env={}, **popen_kwargs):
Pau Espin Pedrol2eafb032020-01-29 17:56:14 +010055 run_dir = self.run_dir.new_dir(name)
Pau Espin Pedrolf6d45ad2020-02-11 14:39:15 +010056 return process.RemoteProcess(name, run_dir, self.user(), self.host(), self.cwd(), popen_args, remote_env=remote_env, **popen_kwargs)
Pau Espin Pedrol2eafb032020-01-29 17:56:14 +010057
58 def generate_wrapper_script(self):
59 wrapper_script = self.run_dir.new_file(RemoteHost.WRAPPER_SCRIPT)
60 with open(wrapper_script, 'w') as f:
61 r = """#!/bin/bash
62 mypid=0
63 sign_handler() {
64 sig=$1
65 echo "received signal handler $sig, killing $mypid"
66 kill $mypid
67 }
68 trap 'sign_handler SIGTERM' SIGTERM
69 trap 'sign_handler SIGINT' SIGINT
70 trap 'sign_handler SIGHUP' SIGHUP
71 $@ &
72 mypid=$!
73 echo "waiting for $mypid"
74 wait $mypid
75 echo "process $mypid finished"
76 """
77 f.write(r)
78 st = os.stat(wrapper_script)
79 os.chmod(wrapper_script, st.st_mode | stat.S_IEXEC)
80 return wrapper_script
81
Pau Espin Pedrolf6d45ad2020-02-11 14:39:15 +010082 def RemoteProcessFixIgnoreSIGHUP(self, name, remote_dir, popen_args, remote_env={}, **popen_kwargs):
Pau Espin Pedrol2eafb032020-01-29 17:56:14 +010083 # Run remotely through ssh. We need to run binary under a wrapper
84 # script since osmo-trx ignores SIGHUP and will keep running after
85 # we close local ssh session. The wrapper script catches SIGHUP and
86 # sends SIGINT to it.
87 self.create_remote_dir(remote_dir)
88
89 wrapper_script = self.generate_wrapper_script()
90 remote_wrapper_script = remote_dir.child(RemoteHost.WRAPPER_SCRIPT)
91 self.scp('scp-wrapper-to-remote', wrapper_script, remote_wrapper_script)
92
Pau Espin Pedrolf6d45ad2020-02-11 14:39:15 +010093 args = (remote_wrapper_script,) + popen_args
94 return self.RemoteProcess(name, args, remote_env, **popen_kwargs)
Pau Espin Pedrol2eafb032020-01-29 17:56:14 +010095
Pau Espin Pedrol14022d32020-02-11 14:20:00 +010096 def RemoteNetNSProcess(self, name, netns, popen_args, **popen_kwargs):
97 run_dir = self.run_dir.new_dir(name)
98 return self.RemoteNetNSProcess(name, run_dir, self.user(), self.host(), self.cwd(), netns, popen_args, **popen_kwargs)
99
Pau Espin Pedrol2eafb032020-01-29 17:56:14 +0100100 def run_remote_sync(self, name, popen_args):
Pau Espin Pedrolf6d45ad2020-02-11 14:39:15 +0100101 proc = self.RemoteProcess(name, popen_args, remote_env=self.remote_env)
Pau Espin Pedrol2eafb032020-01-29 17:56:14 +0100102 proc.launch_sync()
103 return proc
104
105 def rm_remote_dir(self, remote_dir):
106 remote_dir_str = str(remote_dir)
107 self.run_remote_sync('rm-remote-dir', ('test', '!', '-d', remote_dir_str, '||', 'rm', '-rf', remote_dir_str))
108
109 def create_remote_dir(self, remote_dir):
110 remote_dir_str = str(remote_dir)
111 self.run_remote_sync('mk-remote-dir', ('mkdir', '-p', remote_dir_str))
112
113 def recreate_remote_dir(self, remote_dir):
114 self.rm_remote_dir(remote_dir)
115 self.create_remote_dir(remote_dir)
116
117 def inst_compatible_for_remote(self):
118 proc = self.run_remote_sync('uname-m', ('uname', '-m'))
119 if "x86_64" in (proc.get_stdout() or ''):
120 return True
121 return False
122
123 def scp(self, name, local_path, remote_path):
124 process.run_local_sync(self.run_dir, name, ('scp', '-r', local_path, '%s@%s:%s' % (self.user(), self.host(), remote_path)))