ovs-dev.py: allow current directory to be used as the working directory
[cascardo/ovs.git] / utilities / ovs-dev.py
1 #!/usr/bin/python
2 # Copyright (c) 2013, 2014, 2015 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 PWD = os.getcwd()
26 OVS_SRC = HOME + "/ovs"
27 if os.path.exists(PWD + "/WHY-OVS.md"):
28     OVS_SRC = PWD  # Use current directory as OVS source tree
29 ROOT = HOME + "/root"
30 BUILD_GCC = OVS_SRC + "/_build-gcc"
31 BUILD_CLANG = OVS_SRC + "/_build-clang"
32
33 options = None
34 parser = None
35 commands = []
36
37 def set_path(build):
38     PATH = "%(ovs)s/utilities:%(ovs)s/ovsdb:%(ovs)s/vswitchd" % {"ovs": build}
39
40     ENV["PATH"] = PATH + ":" + ENV["PATH"]
41
42 def _sh(*args, **kwargs):
43     print "------> " + " ".join(args)
44     shell = len(args) == 1
45     if kwargs.get("capture", False):
46         proc = subprocess.Popen(args, stdout=subprocess.PIPE, shell=shell)
47         return proc.stdout.readlines()
48     elif kwargs.get("check", True):
49         subprocess.check_call(args, shell=shell)
50     else:
51         subprocess.call(args, shell=shell)
52
53
54 def uname():
55     return _sh("uname", "-r", capture=True)[0].strip()
56
57
58 def conf():
59     tag()
60
61     try:
62         os.remove(OVS_SRC + "/Makefile")
63     except OSError:
64         pass
65
66     configure = ["../configure", "--prefix=" + ROOT, "--localstatedir=" + ROOT,
67                  "--with-logdir=%s/log" % ROOT, "--with-rundir=%s/run" % ROOT,
68                  "--enable-silent-rules", "--with-dbdir=" + ROOT, "--silent"]
69
70     cflags = "-g -fno-omit-frame-pointer"
71
72     if options.werror:
73         configure.append("--enable-Werror")
74
75     if options.cache_time:
76         configure.append("--enable-cache-time")
77
78     if options.mandir:
79         configure.append("--mandir=" + options.mandir)
80
81     if options.with_dpdk:
82         configure.append("--with-dpdk=" + options.with_dpdk)
83         cflags += " -Wno-cast-align -Wno-bad-function-cast" # DPDK warnings.
84
85     if options.optimize is None:
86         options.optimize = 0
87
88     cflags += " -O%s" % str(options.optimize)
89
90     ENV["CFLAGS"] = cflags
91
92     _sh("./boot.sh")
93
94     try:
95         os.mkdir(BUILD_GCC)
96     except OSError:
97         pass # Directory exists.
98
99     os.chdir(BUILD_GCC)
100     _sh(*(configure + ["--with-linux=/lib/modules/%s/build" % uname()]))
101
102     try:
103         _sh("clang --version", check=True)
104         clang = True
105     except subprocess.CalledProcessError:
106         clang = False
107
108     try:
109         _sh("sparse --version", check=True)
110         sparse = True
111     except subprocess.CalledProcessError:
112         sparse = False
113
114     if clang:
115         try:
116             os.mkdir(BUILD_CLANG)
117         except OSError:
118             pass # Directory exists.
119
120         ENV["CC"] = "clang"
121         os.chdir(BUILD_CLANG)
122         _sh(*configure)
123
124     if sparse:
125         c1 = "C=1"
126     else:
127         c1 = ""
128
129     os.chdir(OVS_SRC)
130
131     make_str = "\t$(MAKE) -C %s $@\n"
132
133     mf = open(OVS_SRC + "/Makefile", "w")
134     mf.write("all:\n%:\n")
135     if clang:
136         mf.write(make_str % BUILD_CLANG)
137     mf.write("\t$(MAKE) -C %s %s $@\n" % (BUILD_GCC, c1))
138     mf.write("\ncheck-valgrind:\n")
139     mf.write("\ncheck:\n")
140     mf.write(make_str % BUILD_GCC)
141     mf.close()
142 commands.append(conf)
143
144
145 def make(args=""):
146     make = "make -s -j 8 " + args
147     _sh(make)
148 commands.append(make)
149
150
151 def check():
152     flags = ""
153     if options.jobs:
154         flags += "-j%d " % options.jobs
155     else:
156         flags += "-j8 "
157     if options.tests:
158         for arg in str.split(options.tests):
159             if arg[0].isdigit():
160                 flags += "%s " % arg
161             else:
162                 flags += "-k %s " % arg
163     ENV["TESTSUITEFLAGS"] = flags
164     make("check")
165 commands.append(check)
166
167
168 def tag():
169     ctags = ['ctags', '-R', '-f', '.tags']
170
171     try:
172         _sh(*(ctags + ['--exclude="datapath/"']))
173     except:
174         try:
175             _sh(*ctags)  # Some versions of ctags don't have --exclude
176         except:
177             pass
178
179     try:
180         _sh('cscope', '-R', '-b')
181     except:
182         pass
183 commands.append(tag)
184
185
186 def kill():
187     for proc in ["ovs-vswitchd", "ovsdb-server"]:
188         if os.path.exists("%s/run/openvswitch/%s.pid" % (ROOT, proc)):
189             _sh("ovs-appctl", "-t", proc, "exit", check=False)
190             time.sleep(.1)
191         _sh("sudo", "killall", "-q", "-2", proc, check=False)
192 commands.append(kill)
193
194
195 def reset():
196     kill()
197     if os.path.exists(ROOT):
198         shutil.rmtree(ROOT)
199     for dp in _sh("ovs-dpctl dump-dps", capture=True):
200         _sh("ovs-dpctl", "del-dp", dp.strip())
201 commands.append(reset)
202
203
204 def run():
205     kill()
206     for d in ["log", "run"]:
207         d = "%s/%s" % (ROOT, d)
208         shutil.rmtree(d, ignore_errors=True)
209         os.makedirs(d)
210
211     pki_dir = ROOT + "/pki"
212     if not os.path.exists(pki_dir):
213         os.mkdir(pki_dir)
214         os.chdir(pki_dir)
215         _sh("ovs-pki init")
216         _sh("ovs-pki req+sign ovsclient")
217         os.chdir(OVS_SRC)
218
219     if not os.path.exists(ROOT + "/conf.db"):
220         _sh("ovsdb-tool", "create", ROOT + "/conf.db",
221             OVS_SRC + "/vswitchd/vswitch.ovsschema")
222
223     opts = ["--pidfile", "--log-file"]
224
225     _sh(*(["ovsdb-server",
226            "--remote=punix:%s/run/db.sock" % ROOT,
227            "--remote=db:Open_vSwitch,Open_vSwitch,manager_options",
228            "--private-key=db:Open_vSwitch,SSL,private_key",
229            "--certificate=db:Open_vSwitch,SSL,certificate",
230            "--bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert",
231            "--detach", "-vconsole:off"] + opts))
232
233     _sh("ovs-vsctl --no-wait --bootstrap set-ssl %s/ovsclient-privkey.pem" \
234         " %s/ovsclient-cert.pem %s/vswitchd.cacert"
235         % (pki_dir, pki_dir, pki_dir))
236     version = _sh("ovs-vsctl --no-wait --version", capture=True)
237     version = version[0].strip().split()[3]
238     root_uuid = _sh("ovs-vsctl --no-wait --bare list Open_vSwitch",
239                     capture=True)[0].strip()
240     _sh("ovs-vsctl --no-wait set Open_vSwitch %s ovs_version=%s"
241         % (root_uuid, version))
242
243     build = BUILD_CLANG if options.clang else BUILD_GCC
244     cmd = [build + "/vswitchd/ovs-vswitchd"]
245
246     if options.dpdk:
247         cmd.append("--dpdk")
248         cmd.extend(options.dpdk)
249         cmd.append("--")
250
251     if options.gdb:
252         cmd = ["gdb", "--args"] + cmd
253     elif options.valgrind:
254         cmd = ["valgrind", "--track-origins=yes", "--leak-check=full",
255                "--suppressions=%s/tests/glibc.supp" % OVS_SRC,
256                "--suppressions=%s/tests/openssl.supp" % OVS_SRC] + cmd
257     else:
258         cmd = ["sudo"] + cmd
259         opts = opts + ["-vconsole:off", "--detach", "--enable-dummy"]
260     _sh(*(cmd + opts))
261 commands.append(run)
262
263
264 def modinst():
265     if not os.path.exists("/lib/modules"):
266         print "Missing modules directory.  Is this a Linux system?"
267         sys.exit(1)
268
269     try:
270         _sh("rmmod", "openvswitch")
271     except subprocess.CalledProcessError, e:
272         pass  # Module isn't loaded
273
274     try:
275         _sh("rm -f /lib/modules/%s/extra/openvswitch.ko" % uname())
276         _sh("rm -f /lib/modules/%s/extra/vport-*.ko" % uname())
277     except subprocess.CalledProcessError, e:
278         pass  # Module isn't installed
279
280     conf()
281     make()
282     make("modules_install")
283
284     _sh("modprobe", "openvswitch")
285     _sh("dmesg | grep openvswitch | tail -1")
286     _sh("find /lib/modules/%s/ -iname vport-*.ko -exec insmod '{}' \;" % uname())
287 commands.append(modinst)
288
289
290 def env():
291     print "export PATH=" + ENV["PATH"]
292 commands.append(env)
293
294
295 def doc():
296     parser.print_help()
297     print \
298 """
299 This program is designed to help developers build and run Open vSwitch without
300 necessarily needing to know the gory details. Given some basic requirements
301 (described below), it can be used to build and run Open vSwitch, keeping
302 runtime files in the user's home directory.
303
304 Basic Configuration:
305     # This section can be run as a script on ubuntu systems.
306
307     # First install the basic requirements needed to build Open vSwitch.
308     sudo apt-get install git build-essential libtool autoconf pkg-config \\
309             libssl-dev gdb linux-headers-`uname -r`
310
311     # Next clone the Open vSwitch source.
312     git clone https://github.com/openvswitch/ovs.git %(ovs)s
313
314     # Setup environment variables.
315     `%(v)s env`
316
317     # Build the switch.
318     %(v)s conf make
319
320     # Install the kernel module
321     sudo insmod %(ovs)s/datapath/linux/openvswitch.ko
322
323     # If needed, manually load all required vport modules:
324     sudo insmod %(ovs)s/datapath/linux/vport-vxlan.ko
325     sudo insmod %(ovs)s/datapath/linux/vport-geneve.ko
326     [...]
327
328     # Run the switch.
329     %(v)s run
330
331 Commands:
332     conf    - Configure the ovs source.
333     make    - Build the source (must have been configured).
334     check   - Run the unit tests.
335     tag     - Run ctags and cscope over the source.
336     kill    - Kill all running instances of ovs.
337     reset   - Reset any runtime configuration in %(run)s.
338     run     - Run ovs.
339     modinst - Build ovs and install the kernel module.
340     env     - Print the required path environment variable.
341     doc     - Print this message.
342 """ % {"ovs": OVS_SRC, "v": sys.argv[0], "run": ROOT}
343     sys.exit(0)
344 commands.append(doc)
345
346 def parse_subargs(option, opt_str, value, parser):
347     subopts = []
348
349     while parser.rargs:
350         dpdkarg = parser.rargs.pop(0)
351         if dpdkarg == "--":
352             break
353         subopts.append(dpdkarg)
354
355     setattr(parser.values, option.dest, subopts)
356
357 def main():
358     global options
359     global parser
360
361     description = "Open vSwitch developer configuration. Try `%prog doc`."
362     cmd_names = [c.__name__ for c in commands]
363     parser = optparse.OptionParser(usage="usage: %prog"
364                                    + " [options] [%s] ..."
365                                    % "|".join(cmd_names),
366                                    description=description)
367
368     group = optparse.OptionGroup(parser, "conf")
369     group.add_option("--disable-Werror", dest="werror", action="store_false",
370                      default=True, help="compile without the Werror flag")
371     group.add_option("--cache-time", dest="cache_time",
372                      action="store_true", help="configure with cached timing")
373     group.add_option("--mandir", dest="mandir", metavar="MANDIR",
374                      help="configure the man documentation install directory")
375     group.add_option("--with-dpdk", dest="with_dpdk", metavar="DPDK_BUILD",
376                      help="built with dpdk libraries located at DPDK_BUILD");
377     parser.add_option_group(group)
378
379     group = optparse.OptionGroup(parser, "Optimization Flags")
380     for i in ["s", "g"] + range(4) + ["fast"]:
381         group.add_option("--O%s" % str(i), dest="optimize",
382                          action="store_const", const=i,
383                          help="compile with -O%s" % str(i))
384     parser.add_option_group(group)
385
386     group = optparse.OptionGroup(parser, "check")
387     group.add_option("-j", "--jobs", dest="jobs", metavar="N", type="int",
388                      help="Run N tests in parallel")
389     group.add_option("--tests", dest="tests", metavar="FILTER",
390                      help="""run specific tests and/or a test category
391                           eg, --tests=\"1-10 megaflow\"""")
392     parser.add_option_group(group)
393
394     group = optparse.OptionGroup(parser, "run")
395     group.add_option("-g", "--gdb", dest="gdb", action="store_true",
396                      help="run ovs-vswitchd under gdb")
397     group.add_option("--valgrind", dest="valgrind", action="store_true",
398                      help="run ovs-vswitchd under valgrind")
399     group.add_option("--dpdk", dest="dpdk", action="callback",
400                      callback=parse_subargs,
401                      help="run ovs-vswitchd with dpdk subopts (ended by --)")
402     group.add_option("--clang", dest="clang", action="store_true",
403                      help="Use binaries built by clang")
404
405     parser.add_option_group(group)
406
407     options, args = parser.parse_args()
408
409     for arg in args:
410         if arg not in cmd_names:
411             print "Unknown argument " + arg
412             doc()
413
414     if options.clang:
415         set_path(BUILD_CLANG)
416     else:
417         set_path(BUILD_GCC)
418
419     try:
420         os.chdir(OVS_SRC)
421     except OSError:
422         print "Missing %s." % OVS_SRC
423         doc()
424
425     for arg in args:
426         for cmd in commands:
427             if arg == cmd.__name__:
428                 cmd()
429
430
431 if __name__ == '__main__':
432     main()