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 as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 import os, os.path, re, signal, shutil, socket, subprocess, tempfile
26 __all__ = ["python", "ssh_path"]
27 __all__ += ["rsh", "tcpdump_path", "sshd_path"]
28 __all__ += ["execute", "backticks"]
31 # Unittest from Python 2.6 doesn't have these decorators
32 def _bannerwrap(f, text):
34 def banner(*args, **kwargs):
35 sys.stderr.write("*** WARNING: Skipping test %s: `%s'\n" %
41 return lambda f: _bannerwrap(f, text)
43 def skipUnless(cond, text):
44 return (lambda f: _bannerwrap(f, text)) if not cond else lambda f: f
46 def skipIf(cond, text):
47 return (lambda f: _bannerwrap(f, text)) if cond else lambda f: f
49 def find_bin(name, extra_path = None):
51 if "PATH" in os.environ:
52 search += os.environ["PATH"].split(":")
53 for pref in ("/", "/usr/", "/usr/local/"):
54 for d in ("bin", "sbin"):
55 search.append(pref + d)
61 os.stat(d + "/" + name)
64 if e.errno != os.errno.ENOENT:
68 def find_bin_or_die(name, extra_path = None):
71 raise RuntimeError(("Cannot find `%s' command, impossible to " +
75 def find_bin(name, extra_path = None):
77 if "PATH" in os.environ:
78 search += os.environ["PATH"].split(":")
79 for pref in ("/", "/usr/", "/usr/local/"):
80 for d in ("bin", "sbin"):
81 search.append(pref + d)
87 os.stat(d + "/" + name)
90 if e.errno != os.errno.ENOENT:
94 ssh_path = find_bin_or_die("ssh")
95 python_path = find_bin_or_die("python")
98 rsh_path = find_bin("rsh")
99 tcpdump_path = find_bin("tcpdump")
100 sshd_path = find_bin("sshd")
103 # FIXME: create a global debug variable
104 #print "[pid %d]" % os.getpid(), " ".join(cmd)
105 null = open("/dev/null", "r+")
106 p = subprocess.Popen(cmd, stdout = null, stderr = subprocess.PIPE)
107 out, err = p.communicate()
108 if p.returncode != 0:
109 raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err))
112 p = subprocess.Popen(cmd, stdout = subprocess.PIPE,
113 stderr = subprocess.PIPE)
114 out, err = p.communicate()
115 if p.returncode != 0:
116 raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err))
122 def gen_ssh_keypair(filename):
123 ssh_keygen = nepi.util.environ.find_bin_or_die("ssh-keygen")
124 args = [ssh_keygen, '-q', '-N', '', '-f', filename]
125 assert subprocess.Popen(args).wait() == 0
126 return filename, "%s.pub" % filename
128 def add_key_to_agent(filename):
129 ssh_add = nepi.util.environ.find_bin_or_die("ssh-add")
130 args = [ssh_add, filename]
131 null = file("/dev/null", "w")
132 assert subprocess.Popen(args, stderr = null).wait() == 0
137 s.bind(("127.0.0.1", 0))
138 port = s.getsockname()[1]
141 _SSH_CONF = """ListenAddress 127.0.0.1:%d
144 UsePrivilegeSeparation no
145 PubkeyAuthentication yes
146 PasswordAuthentication no
147 AuthorizedKeysFile %s
149 AllowAgentForwarding yes
152 PermitUserEnvironment yes
155 def gen_sshd_config(filename, port, server_key, auth_keys):
156 conf = open(filename, "w")
157 text = _SSH_CONF % (port, server_key, auth_keys)
162 def gen_auth_keys(pubkey, output, environ):
163 #opts = ['from="127.0.0.1/32"'] # fails in stupid yans setup
165 for k, v in environ.items():
166 opts.append('environment="%s=%s"' % (k, v))
168 lines = file(pubkey).readlines()
169 pubkey = lines[0].split()[0:2]
170 out = file(output, "w")
171 out.write("%s %s %s\n" % (",".join(opts), pubkey[0], pubkey[1]))
175 def start_ssh_agent():
176 ssh_agent = nepi.util.environ.find_bin_or_die("ssh-agent")
177 proc = subprocess.Popen([ssh_agent], stdout = subprocess.PIPE)
178 (out, foo) = proc.communicate()
179 assert proc.returncode == 0
181 for l in out.split("\n"):
182 match = re.search("^(\w+)=([^ ;]+);.*", l)
185 k, v = match.groups()
190 def stop_ssh_agent(data):
191 # No need to gather the pid, ssh-agent knows how to kill itself; after we
192 # had set up the environment
193 ssh_agent = nepi.util.environ.find_bin_or_die("ssh-agent")
194 null = file("/dev/null", "w")
195 proc = subprocess.Popen([ssh_agent, "-k"], stdout = null)
197 assert proc.wait() == 0