ofp-actions: Add hex dump of bad actions to log message on error.
[openvswitch] / utilities / bugtool / ovs-bugtool.in
index c2b603f2da9bb77ee42bfe8f3de20a160b2fc177..3bafa134a969d130965f9c8446f5bd01db4a83b0 100755 (executable)
@@ -14,7 +14,7 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 # Copyright (c) 2005, 2007 XenSource Ltd.
-# Copyright (c) 2010, 2011 Nicira Networks.
+# Copyright (c) 2010, 2011 Nicira, Inc.
 
 #
 # To add new entries to the bugtool, you need to:
@@ -67,7 +67,7 @@ OS_RELEASE = platform.release()
 APT_SOURCES_LIST = "/etc/apt/sources.list"
 APT_SOURCES_LIST_D = "/etc/apt/sources.list.d"
 BUG_DIR = "/var/log/ovs-bugtool"
-PLUGIN_DIR = "@sysconfdir@/openvswitch/bugtool-plugins"
+PLUGIN_DIR = "@pkgdatadir@/bugtool-plugins"
 GRUB_CONFIG = '/boot/grub/menu.lst'
 BOOT_KERNEL = '/boot/vmlinuz-' + OS_RELEASE
 BOOT_INITRD = '/boot/initrd-' + OS_RELEASE + '.img'
@@ -111,7 +111,7 @@ HOSTS = '/etc/hosts'
 HOSTS_ALLOW = '/etc/hosts.allow'
 HOSTS_DENY = '/etc/hosts.deny'
 DHCP_LEASE_DIR = ['/var/lib/dhclient', '/var/lib/dhcp3']
-OPENVSWITCH_LOG_DIR = '@LOGDIR@'
+OPENVSWITCH_LOG_DIR = '@LOGDIR@/'
 OPENVSWITCH_DEFAULT_SWITCH = '/etc/default/openvswitch-switch' # Debian
 OPENVSWITCH_SYSCONFIG_SWITCH = '/etc/sysconfig/openvswitch'    # RHEL
 OPENVSWITCH_DEFAULT_CONTROLLER = '/etc/default/openvswitch-controller'
@@ -319,30 +319,42 @@ def cmd_output(cap, args, label = None, filter = None):
                 label = args
         data[label] = {'cap': cap, 'cmd_args': args, 'filter': filter}
 
-def file_output(cap, path_list):
+def file_output(cap, path_list, newest_first=False):
+    """
+    If newest_first is True, the list of files in path_list is sorted
+    by file modification time in descending order, else its sorted
+    in ascending order.
+    """
     if cap in entries:
-        for p in path_list:
-            if os.path.exists(p):
-                if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
-                        cap_sizes[cap] < caps[cap][MAX_SIZE]:
-                    data[p] = {'cap': cap, 'filename': p}
-                    try:
-                        s = os.stat(p)
-                        cap_sizes[cap] += s.st_size
-                    except:
-                        pass
-                else:
-                    output("Omitting %s, size constraint of %s exceeded" % (p, cap))
+        path_entries = []
+        for path in path_list:
+            try:
+                s = os.stat(path)
+            except OSError, e:
+                continue
+            path_entries.append((path, s))
 
-def tree_output(cap, path, pattern = None, negate = False):
+        mtime = lambda(path, stat): stat.st_mtime
+        path_entries.sort(key=mtime, reverse=newest_first)
+        for p in path_entries:
+            if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
+                    cap_sizes[cap] < caps[cap][MAX_SIZE]:
+                data[p] = {'cap': cap, 'filename': p[0]}
+                cap_sizes[cap] += p[1].st_size
+            else:
+                output("Omitting %s, size constraint of %s exceeded" % (p[0], cap))
+
+def tree_output(cap, path, pattern=None, negate=False, newest_first=False):
+    """
+    Walks the directory tree rooted at path. Files in current dir are processed
+    before files in sub-dirs.
+    """
     if cap in entries:
         if os.path.exists(path):
-            for f in os.listdir(path):
-                fn = os.path.join(path, f)
-                if os.path.isfile(fn) and matches(fn, pattern, negate):
-                    file_output(cap, [fn])
-                elif os.path.isdir(fn):
-                    tree_output(cap, fn, pattern, negate)
+            for root, dirs, files in os.walk(path):
+                fns = [fn for fn in [os.path.join(root, f) for f in files]
+                       if os.path.isfile(fn) and matches(fn, pattern, negate)]
+                file_output(cap, fns, newest_first=newest_first)
 
 def func_output(cap, label, func):
     if cap in entries:
@@ -571,13 +583,14 @@ exclude those logs from the archive.
             f = open('/sys/class/net/%s/type' % p, 'r')
             t = f.readline()
             f.close()
-            if int(t) == 1:
+            if os.path.islink('/sys/class/net/%s/device' % p) and int(t) == 1:
                 # ARPHRD_ETHER
                 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, p])
                 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-S', p])
                 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-k', p])
                 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-i', p])
                 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-c', p])
+            if int(t) == 1:
                 cmd_output(CAP_NETWORK_STATUS,
                            [TC, '-s', '-d', 'class', 'show', 'dev', p])
         except:
@@ -586,9 +599,8 @@ exclude those logs from the archive.
     tree_output(CAP_NETWORK_STATUS, PROC_NET_VLAN_DIR)
     cmd_output(CAP_NETWORK_STATUS, [TC, '-s', 'qdisc'])
     file_output(CAP_NETWORK_STATUS, [PROC_NET_SOFTNET_STAT])
-    tree_output(CAP_NETWORK_STATUS, OPENVSWITCH_LOG_DIR)
     if os.path.exists(OPENVSWITCH_VSWITCHD_PID):
-        cmd_output(CAP_NETWORK_STATUS, [OVS_DPCTL, 'show'])
+        cmd_output(CAP_NETWORK_STATUS, [OVS_DPCTL, 'show', '-s'])
         for d in dp_list():
             cmd_output(CAP_NETWORK_STATUS, [OVS_OFCTL, 'show', d])
             cmd_output(CAP_NETWORK_STATUS, [OVS_OFCTL, 'dump-flows', d])
@@ -599,7 +611,7 @@ exclude those logs from the archive.
             vspidfile.close()
             for b in bond_list(vspid):
                 cmd_output(CAP_NETWORK_STATUS,
-                           [OVS_APPCTL, '-t', '/var/run/ovs-vswitchd.%s.ctl' % vspid, '-e' 'bond/show %s' % b],
+                           [OVS_APPCTL, '-t', '@RUNDIR@/ovs-vswitchd.%s.ctl' % vspid, '-e' 'bond/show %s' % b],
                            'ovs-appctl-bond-show-%s.out' % b)
         except e:
             pass
@@ -610,17 +622,18 @@ exclude those logs from the archive.
     cmd_output(CAP_PROCESS_LIST, [PS, 'wwwaxf', '-eo', 'pid,tty,stat,time,nice,psr,pcpu,pmem,nwchan,wchan:25,args'], label='process-tree')
     func_output(CAP_PROCESS_LIST, 'fd_usage', fd_usage)
 
+    logs = ([ VAR_LOG_DIR + x for x in
+             [ 'crit.log', 'kern.log', 'daemon.log', 'user.log',
+             'syslog', 'messages', 'secure', 'debug', 'dmesg', 'boot' ]]
+            + [ OPENVSWITCH_LOG_DIR + x for x in
+                [ 'ovs-vswitchd.log', 'ovs-brcompatd.log', 'ovsdb-server.log',
+                  'ovs-xapi-sync.log', 'ovs-monitor-ipsec.log' ]])
+    file_output(CAP_SYSTEM_LOGS, logs)
+    file_output(CAP_SYSTEM_LOGS,
+                [ '%s.%d' % (f, n) for n in range(20) for f in logs ])
     file_output(CAP_SYSTEM_LOGS,
-         [ VAR_LOG_DIR + x for x in
-           [ 'crit.log', 'kern.log', 'daemon.log', 'user.log', 'syslog', 
-             'messages', 'secure', 'debug', 'dmesg', 'boot'] +
-           [ f % n for n in range(1, 20) \
-                 for f in ['crit.log.%d', 'crit.log.%d.gz',
-                           'kern.log.%d', 'kern.log.%d.gz',
-                           'daemon.log.%d', 'daemon.log.%d.gz',
-                           'user.log.%d', 'user.log.%d.gz',
-                           'messages.%d', 'messages.%d.gz',
-                           'syslog.%d', 'syslog.%d.gz']]])
+                [ '%s.%d.gz' % (f, n) for n in range(20) for f in logs ])
+
     if not os.path.exists('/var/log/dmesg') and not os.path.exists('/var/log/boot'):
         cmd_output(CAP_SYSTEM_LOGS, [DMESG])
 
@@ -778,7 +791,7 @@ def dp_list():
 
 def bond_list(pid):
     output = StringIO.StringIO()
-    procs = [ProcOutput([OVS_APPCTL, '-t', '/var/run/ovs-vswitchd.%s.ctl' % pid, '-e' 'bond/list'], caps[CAP_NETWORK_STATUS][MAX_TIME], output)]
+    procs = [ProcOutput([OVS_APPCTL, '-t', '@RUNDIR@/ovs-vswitchd.%s.ctl' % pid, '-e' 'bond/list'], caps[CAP_NETWORK_STATUS][MAX_TIME], output)]
 
     run_procs([procs])
 
@@ -876,12 +889,16 @@ def load_plugins(just_capabilities = False):
 
             for el in xmldoc.documentElement.getElementsByTagName("*"):
                 if el.tagName == "files":
-                    file_output(dir, getText(el.childNodes).split())
+                    newest_first = getBoolAttr(el, 'newest_first')
+                    file_output(dir, getText(el.childNodes).split(),
+                                newest_first=newest_first)
                 elif el.tagName == "directory":
                     pattern = el.getAttribute("pattern")
                     if pattern == '': pattern = None
                     negate = getBoolAttr(el, 'negate')
-                    tree_output(dir, getText(el.childNodes), pattern and re.compile(pattern) or None, negate)
+                    newest_first = getBoolAttr(el, 'newest_first')
+                    tree_output(dir, getText(el.childNodes), pattern and re.compile(pattern) or None,
+                                negate=negate, newest_first=newest_first)
                 elif el.tagName == "command":
                     label = el.getAttribute("label")
                     if label == '': label = None
@@ -1159,6 +1176,7 @@ class ProcOutput:
     def terminate(self):
         if self.running:
             try:
+                self.proc.stdout.close()
                 os.kill(self.proc.pid, SIGTERM)
             except:
                 pass
@@ -1171,6 +1189,7 @@ class ProcOutput:
         line = self.proc.stdout.readline()
         if line == '':
             # process exited
+            self.proc.stdout.close()
             self.status = self.proc.wait()
             self.proc = None
             self.running = False