c5445e25ee87b954b9a1074c8db8b42e19d551d3
[cascardo/ovs.git] / utilities / ovs-dev.py
1 #!/usr/bin/python
2 # Copyright (c) 2013 Nicira, Inc.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 import optparse
17 import os
18 import shutil
19 import subprocess
20 import sys
21 import tempfile
22
23 ENV = os.environ
24 HOME = ENV["HOME"]
25 OVS_SRC = HOME + "/ovs"
26 ROOT = HOME + "/root"
27 BUILD_GCC = OVS_SRC + "/_build-gcc"
28 BUILD_CLANG = OVS_SRC + "/_build-clang"
29 PATH = "%(ovs)s/utilities:%(ovs)s/ovsdb:%(ovs)s/vswitchd" % {"ovs": BUILD_GCC}
30
31 ENV["CFLAGS"] = "-g -O0"
32 ENV["PATH"] = PATH + ":" + ENV["PATH"]
33
34 options = None
35 parser = None
36 commands = []
37
38
39 def _sh(*args, **kwargs):
40     print "------> " + " ".join(args)
41     shell = len(args) == 1
42     if kwargs.get("capture", False):
43         proc = subprocess.Popen(args, stdout=subprocess.PIPE, shell=shell)
44         return proc.stdout.readlines()
45     elif kwargs.get("check", True):
46         subprocess.check_call(args, shell=shell)
47     else:
48         subprocess.call(args, shell=shell)
49
50
51 def uname():
52     return _sh("uname", "-r", capture=True)[0].strip()
53
54
55 def conf():
56     tag()
57
58     try:
59         os.remove(OVS_SRC + "/Makefile")
60     except OSError:
61         pass
62
63     configure = ["../configure", "--prefix=" + ROOT, "--localstatedir=" + ROOT,
64                  "--with-logdir=%s/log" % ROOT, "--with-rundir=%s/run" % ROOT,
65                  "--with-linux=/lib/modules/%s/build" % uname(),
66                  "--with-dbdir=" + ROOT]
67
68     if options.werror:
69         configure.append("--enable-Werror")
70
71     if options.cache_time:
72         configure.append("--enable-cache-time")
73
74     if options.mandir:
75         configure.append("--mandir=" + options.mandir)
76
77     _sh("./boot.sh")
78
79     try:
80         os.mkdir(BUILD_GCC)
81     except OSError:
82         pass # Directory exists.
83
84     os.chdir(BUILD_GCC)
85     _sh(*configure)
86
87     try:
88         _sh("clang --version", check=True)
89         clang = True
90     except subprocess.CalledProcessError:
91         clang = False
92
93     try:
94         _sh("sparse --version", check=True)
95         sparse = True
96     except subprocess.CalledProcessError:
97         sparse = False
98
99     if clang:
100         try:
101             os.mkdir(BUILD_CLANG)
102         except OSError:
103             pass # Directory exists.
104
105         ENV["CC"] = "clang"
106         os.chdir(BUILD_CLANG)
107         _sh(*configure)
108
109     if sparse:
110         c1 = "C=1"
111     else:
112         c1 = ""
113
114     os.chdir(OVS_SRC)
115
116     make_str = "\t$(MAKE) -C %s $@\n"
117
118     mf = open(OVS_SRC + "/Makefile", "w")
119     mf.write("all:\n%:\n")
120     if clang:
121         mf.write(make_str % BUILD_CLANG)
122     mf.write("\t$(MAKE) -C %s %s $@\n" % (BUILD_GCC, c1))
123     mf.write("\ncheck:\n")
124     mf.write(make_str % BUILD_GCC)
125     mf.close()
126 commands.append(conf)
127
128
129 def make(args=""):
130     make = "make -s -j 8 " + args
131     _sh(make)
132 commands.append(make)
133
134
135 def check():
136     make("check")
137 commands.append(check)
138
139
140 def tag():
141     ctags = ['ctags', '-R', '-f', '.tags']
142
143     try:
144         _sh(*(ctags + ['--exclude="datapath/"']))
145     except:
146         try:
147             _sh(*ctags)  # Some versions of ctags don't have --exclude
148         except:
149             pass
150
151     try:
152         _sh('cscope', '-R', '-b')
153     except:
154         pass
155 commands.append(tag)
156
157
158 def kill():
159     for proc in ["ovs-vswitchd", "ovsdb-server"]:
160         if os.path.exists("%s/run/openvswitch/%s.pid" % (ROOT, proc)):
161             _sh("ovs-appctl", "-t", proc, "exit", check=False)
162             time.sleep(.1)
163         _sh("sudo", "killall", "-q", "-2", proc, check=False)
164 commands.append(kill)
165
166
167 def reset():
168     kill()
169     if os.path.exists(ROOT):
170         shutil.rmtree(ROOT)
171     for dp in _sh("ovs-dpctl dump-dps", capture=True):
172         _sh("ovs-dpctl", "del-dp", dp.strip())
173 commands.append(reset)
174
175
176 def run():
177     kill()
178     for d in ["log", "run"]:
179         d = "%s/%s" % (ROOT, d)
180         shutil.rmtree(d, ignore_errors=True)
181         os.makedirs(d)
182
183     pki_dir = ROOT + "/pki"
184     if not os.path.exists(pki_dir):
185         os.mkdir(pki_dir)
186         os.chdir(pki_dir)
187         _sh("ovs-pki init")
188         _sh("ovs-pki req+sign ovsclient")
189         os.chdir(OVS_SRC)
190
191     if not os.path.exists(ROOT + "/conf.db"):
192         _sh("ovsdb-tool", "create", ROOT + "/conf.db",
193             OVS_SRC + "/vswitchd/vswitch.ovsschema")
194
195     opts = ["--pidfile", "--log-file", "--enable-dummy"]
196
197     _sh(*(["ovsdb-server",
198            "--remote=punix:%s/run/db.sock" % ROOT,
199            "--remote=db:Open_vSwitch,Open_vSwitch,manager_options",
200            "--private-key=db:Open_vSwitch,SSL,private_key",
201            "--certificate=db:Open_vSwitch,SSL,certificate",
202            "--bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert",
203            "--detach", "-vconsole:off"] + opts))
204
205     _sh("ovs-vsctl --no-wait --bootstrap set-ssl %s/ovsclient-privkey.pem" \
206         " %s/ovsclient-cert.pem %s/vswitchd.cacert"
207         % (pki_dir, pki_dir, pki_dir))
208     version = _sh("ovs-vsctl --no-wait --version", capture=True)
209     version = version[0].strip().split()[3]
210     root_uuid = _sh("ovs-vsctl --no-wait --bare list Open_vSwitch",
211                     capture=True)[0].strip()
212     _sh("ovs-vsctl --no-wait set Open_vSwitch %s ovs_version=%s"
213         % (root_uuid, version))
214
215     cmd = [BUILD_GCC + "/vswitchd/ovs-vswitchd"]
216     if options.gdb:
217         cmd = ["gdb", "--args"] + cmd
218     elif options.valgrind:
219         cmd = ["valgrind", "--track-origins=yes",
220                "--suppressions=%s/tests/glibc.supp" % OVS_SRC,
221                "--suppressions=%s/tests/openssl.supp" % OVS_SRC] + cmd
222     else:
223         cmd = ["sudo"] + cmd
224         opts = opts + ["-vconsole:off", "--detach"]
225     _sh(*(cmd + opts))
226 commands.append(run)
227
228
229 def modinst():
230     if not os.path.exists("/lib/modules"):
231         print "Missing modules directory.  Is this a Linux system?"
232         sys.exit(1)
233
234     try:
235         _sh("rmmod", "openvswitch")
236     except subprocess.CalledProcessError, e:
237         pass  # Module isn't loaded
238
239     try:
240         _sh("rm /lib/modules/%s/extra/openvswitch.ko" % uname())
241     except subprocess.CalledProcessError, e:
242         pass  # Module isn't installed
243
244     conf()
245     make()
246     make("modules_install")
247
248     _sh("modprobe", "openvswitch")
249     _sh("dmesg | grep openvswitch | tail -1")
250 commands.append(modinst)
251
252
253 def env():
254     print "export PATH=" + ENV["PATH"]
255 commands.append(env)
256
257
258 def doc():
259     parser.print_help()
260     print \
261 """
262 This program is designed to help developers build and run Open vSwitch without
263 necessarily needing to know the gory details. Given some basic requirements
264 (described below), it can be used to build and run Open vSwitch, keeping
265 runtime files in the user's home directory.
266
267 Basic Configuration:
268     # This section can be run as a script on ubuntu systems.
269
270     # First install the basic requirements needed to build Open vSwitch.
271     sudo apt-get install git build-essential libtool autoconf pkg-config \\
272             libssl-dev gdb linux-headers-`uname -r`
273
274     # Next clone the Open vSwitch source.
275     git clone git://git.openvswitch.org/openvswitch %(ovs)s
276
277     # Setup environment variables.
278     `%(v)s env`
279
280     # Build the switch.
281     %(v)s conf make
282
283     # Install the kernel module
284     sudo insmod %(ovs)s/datapath/linux/openvswitch.ko
285
286     # Run the switch.
287     %(v)s run
288
289 Commands:
290     conf    - Configure the ovs source.
291     make    - Build the source (must have been configured).
292     check   - Run the unit tests.
293     tag     - Run ctags and cscope over the source.
294     kill    - Kill all running instances of ovs.
295     reset   - Reset any runtime configuration in %(run)s.
296     run     - Run ovs.
297     modinst - Build ovs and install the kernel module.
298     env     - Print the required path environment variable.
299     doc     - Print this message.
300 """ % {"ovs": OVS_SRC, "v": sys.argv[0], "run": ROOT}
301     sys.exit(0)
302 commands.append(doc)
303
304
305 def main():
306     global options
307     global parser
308
309     description = "Open vSwitch developer configuration. Try `%prog doc`."
310     cmd_names = [c.__name__ for c in commands]
311     parser = optparse.OptionParser(usage="usage: %prog"
312                                    + " [options] [%s] ..."
313                                    % "|".join(cmd_names),
314                                    description=description)
315
316     group = optparse.OptionGroup(parser, "conf")
317     group.add_option("--disable-Werror", dest="werror", action="store_false",
318                      default=True, help="compile without the Werror flag")
319     group.add_option("--cache-time", dest="cache_time",
320                      action="store_true", help="configure with cached timing")
321     group.add_option("--mandir", dest="mandir", metavar="MANDIR",
322                      help="configure the man documentation install directory")
323     parser.add_option_group(group)
324
325     group = optparse.OptionGroup(parser, "run")
326     group.add_option("-g", "--gdb", dest="gdb", action="store_true",
327                      help="run ovs-vswitchd under gdb")
328     group.add_option("--valgrind", dest="valgrind", action="store_true",
329                      help="run ovs-vswitchd under valgrind")
330     parser.add_option_group(group)
331
332     options, args = parser.parse_args()
333
334     for arg in args:
335         if arg not in cmd_names:
336             print "Unknown argument " + arg
337             doc()
338
339     try:
340         os.chdir(OVS_SRC)
341     except OSError:
342         print "Missing %s." % OVS_SRC
343         doc()
344
345     for arg in args:
346         for cmd in commands:
347             if arg == cmd.__name__:
348                 cmd()
349
350
351 if __name__ == '__main__':
352     main()