2 # NEPI, a framework to manage network experiments
3 # Copyright (C) 2013 INRIA
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License version 2 as
7 # published by the Free Software Foundation;
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
18 # Martin Ferrari <martin.ferrari@inria.fr>
26 import os, os.path, re, signal, shutil, socket, subprocess, tempfile
28 __all__ = ["python", "ssh_path"]
29 __all__ += ["rsh", "tcpdump_path", "sshd_path"]
30 __all__ += ["execute", "backticks"]
33 # Unittest from Python 2.6 doesn't have these decorators
34 def _bannerwrap(f, text):
36 def banner(*args, **kwargs):
37 sys.stderr.write("*** WARNING: Skipping test %s: `%s'\n" %
43 return lambda f: _bannerwrap(f, text)
45 def skipUnless(cond, text):
46 return (lambda f: _bannerwrap(f, text)) if not cond else lambda f: f
48 def skipIf(cond, text):
49 return (lambda f: _bannerwrap(f, text)) if cond else lambda f: f
51 def find_bin(name, extra_path = None):
53 if "PATH" in os.environ:
54 search += os.environ["PATH"].split(":")
55 for pref in ("/", "/usr/", "/usr/local/"):
56 for d in ("bin", "sbin"):
57 search.append(pref + d)
63 os.stat(d + "/" + name)
66 if e.errno != os.errno.ENOENT:
70 def find_bin_or_die(name, extra_path = None):
73 raise RuntimeError(("Cannot find `%s' command, impossible to " +
77 def find_bin(name, extra_path = None):
79 if "PATH" in os.environ:
80 search += os.environ["PATH"].split(":")
81 for pref in ("/", "/usr/", "/usr/local/"):
82 for d in ("bin", "sbin"):
83 search.append(pref + d)
89 os.stat(d + "/" + name)
92 if e.errno != os.errno.ENOENT:
96 ssh_path = find_bin_or_die("ssh")
97 python_path = find_bin_or_die("python")
100 rsh_path = find_bin("rsh")
101 tcpdump_path = find_bin("tcpdump")
102 sshd_path = find_bin("sshd")
105 # FIXME: create a global debug variable
106 #print "[pid %d]" % os.getpid(), " ".join(cmd)
107 null = open("/dev/null", "r+")
108 p = subprocess.Popen(cmd, stdout = null, stderr = subprocess.PIPE)
109 out, err = p.communicate()
110 if p.returncode != 0:
111 raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err))
114 p = subprocess.Popen(cmd, stdout = subprocess.PIPE,
115 stderr = subprocess.PIPE)
116 out, err = p.communicate()
117 if p.returncode != 0:
118 raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err))
124 def gen_ssh_keypair(filename):
125 ssh_keygen = nepi.util.environ.find_bin_or_die("ssh-keygen")
126 args = [ssh_keygen, '-q', '-N', '', '-f', filename]
127 assert subprocess.Popen(args).wait() == 0
128 return filename, "%s.pub" % filename
130 def add_key_to_agent(filename):
131 ssh_add = nepi.util.environ.find_bin_or_die("ssh-add")
132 args = [ssh_add, filename]
133 null = file("/dev/null", "w")
134 assert subprocess.Popen(args, stderr = null).wait() == 0
139 s.bind(("127.0.0.1", 0))
140 port = s.getsockname()[1]
143 _SSH_CONF = """ListenAddress 127.0.0.1:%d
146 UsePrivilegeSeparation no
147 PubkeyAuthentication yes
148 PasswordAuthentication no
149 AuthorizedKeysFile %s
151 AllowAgentForwarding yes
154 PermitUserEnvironment yes
157 def gen_sshd_config(filename, port, server_key, auth_keys):
158 conf = open(filename, "w")
159 text = _SSH_CONF % (port, server_key, auth_keys)
164 def gen_auth_keys(pubkey, output, environ):
165 #opts = ['from="127.0.0.1/32"'] # fails in stupid yans setup
167 for k, v in environ.items():
168 opts.append('environment="%s=%s"' % (k, v))
170 lines = file(pubkey).readlines()
171 pubkey = lines[0].split()[0:2]
172 out = file(output, "w")
173 out.write("%s %s %s\n" % (",".join(opts), pubkey[0], pubkey[1]))
177 def start_ssh_agent():
178 ssh_agent = nepi.util.environ.find_bin_or_die("ssh-agent")
179 proc = subprocess.Popen([ssh_agent], stdout = subprocess.PIPE)
180 (out, foo) = proc.communicate()
181 assert proc.returncode == 0
183 for l in out.split("\n"):
184 match = re.search("^(\w+)=([^ ;]+);.*", l)
187 k, v = match.groups()
192 def stop_ssh_agent(data):
193 # No need to gather the pid, ssh-agent knows how to kill itself; after we
194 # had set up the environment
195 ssh_agent = nepi.util.environ.find_bin_or_die("ssh-agent")
196 null = file("/dev/null", "w")
197 proc = subprocess.Popen([ssh_agent, "-k"], stdout = null)
199 assert proc.wait() == 0