xenserver: Replace customized xen-bugtool with plugin to collect qdisc info.
authorAndrew Evans <aevans@nicira.com>
Fri, 11 Feb 2011 19:29:33 +0000 (11:29 -0800)
committerAndrew Evans <aevans@nicira.com>
Tue, 15 Feb 2011 18:06:01 +0000 (10:06 -0800)
XenServer RPMs have installed a modified /usr/sbin/xen-bugtool that is
identical to upstream except for an additional command to collect tc qdisc
class configuration for each network interface. Since xen-bugtool has an
extension mechanism, use that instead of maintaining a parallel patched
xen-bugtool.

This does change the content of the bug report slightly. Instead of one file
per network interface, qdisc class info for all interfaces is written to one
file. This is an artifact of the xen-bugtool extension mechanism: a single
extension command's output must go to one file, and it is impractical to create
individual <command> tags for each interface dynamically.

Reviewed by Ben Pfaff.

debian/copyright.in
xenserver/README
xenserver/automake.mk
xenserver/etc_xensource_bugtool_network-status_openvswitch.xml [new file with mode: 0644]
xenserver/openvswitch-xen.spec
xenserver/usr_sbin_xen-bugtool [deleted file]
xenserver/usr_share_openvswitch_scripts_xen-bugtool-tc-class-show [new file with mode: 0755]

index f131ea92d51e1507963e9e2fc81624c9706b4856..87cd72b2e2d5a99b59f4b9d75175bcc9440ef9b5 100644 (file)
@@ -25,7 +25,6 @@ License:
        xenserver/opt_xensource_libexec_InterfaceReconfigureVswitch.py
        xenserver/opt_xensource_libexec_interface-reconfigure
        xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py
-       xenserver/usr_sbin_xen-bugtool
 
        * These components are only distributed in the source package.
          They do not appear in any binary packages.
@@ -54,10 +53,6 @@ License:
   GNU Lesser General Public Licence version 2.1.
 
        debian/ovs-bugtool
-       xenserver/usr_sbin_xen-bugtool [*]
-
-       * This component is only distributed in the source package.
-         It does not appear in any binary packages.
 
   On Debian systems, the complete text of the
   GNU Lesser General Public Licence version 2.1 can be found in
index 5023de25bdcd619920d2d260f7519ee37340f2da..3e63374c7a8d723fb793287614cbb5ab61a93ee4 100644 (file)
@@ -34,6 +34,12 @@ files are:
         in the ovs-vswitchd configuration that are managed in the
         xapi database when integrated with Citrix management tools.
 
+    etc_xensource_bugtool_network-status_openvswitch.xml
+
+        xen-bugtool extension to collect networking information relevant to
+        Open vSwitch. Runs
+        usr_share_openvswitch_scripts_xen-bugtool-tc-class-show.
+
     etc_xensource_scripts_vif
 
         Open vSwitch-aware replacement for Citrix script of the same name.
@@ -57,16 +63,18 @@ files are:
         Template for Open vSwitch's /etc/sysconfig/openvswitch 
         configuration file.
 
+    usr_share_openvswitch_scripts_xen-bugtool-tc-class-show
+
+        Script to dump tc class configuration for all network
+        interfaces. Intended to be run by xen-bugtool via
+        etc_xensource_bugtool_network-status_openvswitch.xml.
+
     usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py
 
         xsconsole plugin to configure the pool-wide configuration keys
         used to control Open vSwitch when integrated with Citrix 
         management tools.
 
-    usr_sbin_xen-bugtool
-
-        Open vSwitch-aware replacement for Citrix script of the same name.
-
     uuid.py
 
         This is uuid.py from Python 2.5.  It is installed into the
index 6c0268d8c3f6b5737a18634609c258d90196878c..0a44797d7d23adb15d7b43b0b788d98a3d52203b 100644 (file)
@@ -15,6 +15,7 @@ EXTRA_DIST += \
        xenserver/etc_logrotate.d_openvswitch \
        xenserver/etc_profile.d_openvswitch.sh \
        xenserver/etc_xapi.d_plugins_openvswitch-cfg-update \
+       xenserver/etc_xensource_bugtool_network-status_openvswitch.xml \
        xenserver/etc_xensource_scripts_vif \
        xenserver/openvswitch-xen.spec \
        xenserver/opt_xensource_libexec_InterfaceReconfigure.py \
@@ -22,7 +23,7 @@ EXTRA_DIST += \
        xenserver/opt_xensource_libexec_InterfaceReconfigureVswitch.py \
        xenserver/opt_xensource_libexec_interface-reconfigure \
        xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py \
-       xenserver/usr_sbin_xen-bugtool \
        xenserver/usr_share_openvswitch_scripts_ovs-xapi-sync \
        xenserver/usr_share_openvswitch_scripts_sysconfig.template \
+       xenserver/usr_share_openvswitch_scripts_xen-bugtool-tc-class-show \
        xenserver/uuid.py
diff --git a/xenserver/etc_xensource_bugtool_network-status_openvswitch.xml b/xenserver/etc_xensource_bugtool_network-status_openvswitch.xml
new file mode 100644 (file)
index 0000000..c926d9e
--- /dev/null
@@ -0,0 +1,21 @@
+<!--
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of version 2.1 of the GNU Lesser General Public
+ License as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+
+ Copyright (C) 2011 Nicira Networks.
+-->
+
+<collect>
+  <command label="tc-class-show">/usr/share/openvswitch/scripts/xen-bugtool-tc-class-show</command>
+</collect>
index 1b97a53d21ccb67950cbe53dc59d7b8986374ee9..25e8a96c29da559421d6d97c33657fb3063c551b 100644 (file)
@@ -60,6 +60,9 @@ install -m 755 xenserver/etc_profile.d_openvswitch.sh \
 install -d -m 755 $RPM_BUILD_ROOT/etc/xapi.d/plugins
 install -m 755 xenserver/etc_xapi.d_plugins_openvswitch-cfg-update \
          $RPM_BUILD_ROOT/etc/xapi.d/plugins/openvswitch-cfg-update
+install -d -m 755 $RPM_BUILD_ROOT/etc/xensource/bugtool/network-status
+install -m 644 xenserver/etc_xensource_bugtool_network-status_openvswitch.xml \
+         $RPM_BUILD_ROOT/etc/xensource/bugtool/network-status/openvswitch.xml
 install -d -m 755 $RPM_BUILD_ROOT/usr/share/openvswitch/scripts
 install -m 644 vswitchd/vswitch.ovsschema \
          $RPM_BUILD_ROOT/usr/share/openvswitch/vswitch.ovsschema
@@ -75,10 +78,10 @@ install -m 755 xenserver/etc_xensource_scripts_vif \
              $RPM_BUILD_ROOT/usr/share/openvswitch/scripts/vif
 install -m 755 xenserver/usr_share_openvswitch_scripts_ovs-xapi-sync \
                $RPM_BUILD_ROOT/usr/share/openvswitch/scripts/ovs-xapi-sync
-install -m 755 xenserver/usr_sbin_xen-bugtool \
-             $RPM_BUILD_ROOT/usr/share/openvswitch/scripts/xen-bugtool
 install -m 755 xenserver/usr_share_openvswitch_scripts_sysconfig.template \
          $RPM_BUILD_ROOT/usr/share/openvswitch/scripts/sysconfig.template
+install -m 755 xenserver/usr_share_openvswitch_scripts_xen-bugtool-tc-class-show \
+         $RPM_BUILD_ROOT/usr/share/openvswitch/scripts/xen-bugtool-tc-class-show
 install -m 755 utilities/ovs-save \
          $RPM_BUILD_ROOT/usr/share/openvswitch/scripts/ovs-save
 install -d -m 755 $RPM_BUILD_ROOT/usr/lib/xsconsole/plugins-base
@@ -186,8 +189,7 @@ for f in \
     /opt/xensource/libexec/InterfaceReconfigure.py \
     /opt/xensource/libexec/InterfaceReconfigureBridge.py \
     /opt/xensource/libexec/InterfaceReconfigureVswitch.py \
-    /etc/xensource/scripts/vif \
-    /usr/sbin/xen-bugtool
+    /etc/xensource/scripts/vif
 do
     s=$(basename "$f")
     t=$(readlink "$f")
@@ -248,15 +250,13 @@ rm -f /usr/share/openvswitch/scripts/InterfaceReconfigure.pyc \
     /usr/share/openvswitch/scripts/InterfaceReconfigureVSwitch.pyc \
     /usr/share/openvswitch/scripts/InterfaceReconfigureVSwitch.pyo 
 
-# Restore original XenServer scripts. It's important to do this even on upgrade
-# since the version to be installed may be missing some of these scripts.
+# Restore original XenServer scripts
 for f in \
     /opt/xensource/libexec/interface-reconfigure \
     /opt/xensource/libexec/InterfaceReconfigure.py \
     /opt/xensource/libexec/InterfaceReconfigureBridge.py \
     /opt/xensource/libexec/InterfaceReconfigureVswitch.py \
-    /etc/xensource/scripts/vif \
-    /usr/sbin/xen-bugtool
+    /etc/xensource/scripts/vif
 do
     s=$(basename "$f")
     if [ ! -f "/usr/lib/openvswitch/xs-original/$s" ]; then
@@ -290,6 +290,7 @@ fi
 /etc/init.d/openvswitch
 /etc/init.d/openvswitch-xapi-update
 /etc/xapi.d/plugins/openvswitch-cfg-update
+/etc/xensource/bugtool/network-status/openvswitch.xml
 /etc/logrotate.d/openvswitch
 /etc/profile.d/openvswitch.sh
 /lib/modules/%{xen_version}/kernel/extra/openvswitch/openvswitch_mod.ko
@@ -321,8 +322,8 @@ fi
 /usr/share/openvswitch/scripts/InterfaceReconfigureBridge.py
 /usr/share/openvswitch/scripts/InterfaceReconfigureVswitch.py
 /usr/share/openvswitch/scripts/vif
-/usr/share/openvswitch/scripts/xen-bugtool
 /usr/share/openvswitch/scripts/sysconfig.template
+/usr/share/openvswitch/scripts/xen-bugtool-tc-class-show
 /usr/share/openvswitch/scripts/ovs-save
 /usr/share/openvswitch/vswitch.ovsschema
 /usr/sbin/ovs-vswitchd
diff --git a/xenserver/usr_sbin_xen-bugtool b/xenserver/usr_sbin_xen-bugtool
deleted file mode 100755 (executable)
index 1a4fe6f..0000000
+++ /dev/null
@@ -1,1670 +0,0 @@
-#!/usr/bin/env python
-
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of version 2.1 of the GNU Lesser General Public
-# License as published by the Free Software Foundation.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-#
-# Copyright (c) 2005, 2007 XenSource Ltd.
-
-
-#
-# To add new entries to the bugtool, you need to:
-#
-# Create a new capability.  These declare the new entry to the GUI, including
-# the expected size, time to collect, privacy implications, and whether the
-# capability should be selected by default.  One capability may refer to
-# multiple files, assuming that they can be reasonably grouped together, and
-# have the same privacy implications.  You need:
-#
-#   A new CAP_ constant.
-#   A cap() invocation to declare the capability.
-#
-# You then need to add calls to main() to collect the files.  These will
-# typically be calls to the helpers file_output(), tree_output(), cmd_output(),
-# or func_output().
-#
-
-import getopt
-import re
-import os
-import StringIO
-import sys
-import tarfile
-import time
-import commands
-import pprint
-from xml.dom.minidom import parse, getDOMImplementation
-import zipfile
-from subprocess import Popen, PIPE
-from select import select
-from signal import SIGTERM, SIGUSR1
-import md5
-import platform
-import fcntl
-import glob
-import urllib
-import socket
-import base64
-
-sys.path.append('/usr/lib/python')
-sys.path.append('/usr/lib64/python')
-
-import xen.lowlevel.xc
-import XenAPI
-
-OS_RELEASE = platform.release()
-
-#
-# Files & directories
-#
-
-BUG_DIR = "/var/opt/xen/bug-report"
-PLUGIN_DIR = "/etc/xensource/bugtool"
-XAPI_BLOBS = '/var/xapi/blobs'
-EXTLINUX_CONFIG = '/boot/extlinux.conf'
-GRUB_CONFIG = '/boot/grub/menu.lst'
-BOOT_KERNEL = '/boot/vmlinuz-' + OS_RELEASE
-BOOT_INITRD = '/boot/initrd-' + OS_RELEASE + '.img'
-PROC_PARTITIONS = '/proc/partitions'
-FSTAB = '/etc/fstab'
-PROC_MOUNTS = '/proc/mounts'
-ISCSI_CONF = '/etc/iscsi/iscsid.conf'
-ISCSI_INITIATOR = '/etc/iscsi/initiatorname.iscsi'
-LVM_CACHE = '/etc/lvm/cache/.cache'
-LVM_CONFIG = '/etc/lvm/lvm.conf'
-PROC_CPUINFO = '/proc/cpuinfo'
-PROC_MEMINFO = '/proc/meminfo'
-PROC_IOPORTS = '/proc/ioports'
-PROC_INTERRUPTS = '/proc/interrupts'
-PROC_SCSI = '/proc/scsi/scsi'
-FIRSTBOOT_DIR = '/etc/firstboot.d'
-PROC_VERSION = '/proc/version'
-PROC_MODULES = '/proc/modules'
-PROC_DEVICES = '/proc/devices'
-PROC_FILESYSTEMS = '/proc/filesystems'
-PROC_CMDLINE = '/proc/cmdline'
-PROC_CONFIG = '/proc/config.gz'
-PROC_USB_DEV = '/proc/bus/usb/devices'
-PROC_XEN_BALLOON = '/proc/xen/balloon'
-PROC_NET_BONDING_DIR = '/proc/net/bonding'
-PROC_NET_VLAN_DIR = '/proc/net/vlan'
-PROC_NET_SOFTNET_STAT = '/proc/net/softnet_stat'
-PROC_DRIVER_CCISS_DIR = '/proc/driver/cciss'
-MODPROBE_CONF = '/etc/modprobe.conf'
-MODPROBE_DIR = '/etc/modprobe.d'
-BOOT_TIME_CPUS = '/etc/xensource/boot_time_cpus'
-BOOT_TIME_MEMORY = '/etc/xensource/boot_time_memory'
-SYSCONFIG_HWCONF = '/etc/sysconfig/hwconf'
-SYSCONFIG_NETWORK = '/etc/sysconfig/network'
-SYSCONFIG_NETWORK_SCRIPTS = '/etc/sysconfig/network-scripts'
-IFCFG_RE = re.compile(r'^.*/ifcfg-.*')
-ROUTE_RE = re.compile(r'^.*/route-.*')
-NETWORK_DBCACHE = '/var/xapi/network.dbcache'
-RESOLV_CONF = '/etc/resolv.conf'
-MPP_CONF = '/etc/mpp.conf'
-MULTIPATH_CONF = '/etc/multipath.conf'
-NSSWITCH_CONF = '/etc/nsswitch.conf'
-NTP_CONF = '/etc/ntp.conf'
-IPTABLES_CONFIG = '/etc/sysconfig/iptables-config'
-HOSTS = '/etc/hosts'
-HOSTS_ALLOW = '/etc/hosts.allow'
-HOSTS_DENY = '/etc/hosts.deny'
-DHCP_LEASE_DIR = '/var/lib/dhclient'
-OPENVSWITCH_CORE_DIR = '/var/xen/openvswitch'
-OPENVSWITCH_CONF = '/etc/ovs-vswitchd.conf'
-OPENVSWITCH_CONF_DB = '/etc/openvswitch/conf.db'
-OPENVSWITCH_VSWITCHD_PID = '/var/run/openvswitch/ovs-vswitchd.pid'
-VAR_LOG_DIR = '/var/log/'
-VNCTERM_CORE_DIR = '/var/xen/vncterm'
-XENSOURCE_INVENTORY = '/etc/xensource-inventory'
-OEM_CONFIG_DIR = '/var/xsconfig'
-OEM_CONFIG_FILES_RE = re.compile(r'^.*xensource-inventory$')
-OEM_DB_FILES_RE = re.compile(r'^.*state\.db')
-INITIAL_INVENTORY = '/opt/xensource/etc/initial-inventory'
-VENDORKERNEL_INVENTORY = '/etc/vendorkernel-inventory'
-STATIC_VDIS = '/etc/xensource/static-vdis'
-POOL_CONF = '/etc/xensource/pool.conf'
-NETWORK_CONF = '/etc/xensource/network.conf'
-PTOKEN = '/etc/xensource/ptoken'
-XAPI_CONF = '/etc/xensource/xapi.conf'
-XAPI_SSL_CONF = '/etc/xensource/xapi-ssl.conf'
-DB_CONF = '/etc/xensource/db.conf'
-DB_CONF_RIO = '/etc/xensource/db.conf.rio'
-DB_DEFAULT_FIELDS = '/etc/xensource/db-default-fields'
-DB_SCHEMA_SQL = '/etc/xensource/db_schema.sql'
-XENSTORED_DB = '/var/lib/xenstored/tdb'
-HOST_CRASHDUMPS_DIR = '/var/crash'
-HOST_CRASHDUMP_LOGS_RE = re.compile(r'^.*\.log$')
-X11_LOGS_DIR = VAR_LOG_DIR
-X11_LOGS_RE = re.compile(r'.*/Xorg\..*$')
-X11_AUTH_DIR = '/root/'
-X11_AUTH_RE = re.compile(r'.*/\.((Xauthority)|(serverauth\.[0-9]*))$')
-XAPI_DEBUG_DIR = '/var/xapi/debug'
-LOG_CONF = '/etc/xensource/log.conf'
-INSTALLED_REPOS_DIR = '/etc/xensource/installed-repos'
-PATCH_APPLIED_DIR = '/var/patch/applied'
-XENSERVER_LOGS = \
-    [ VAR_LOG_DIR + x for x in
-      ['xensource.log', 'audit.log', 'xenstored-access.log', 'SMlog', 'VMPRlog', 'xen/xenstored-trace.log', 
-       'xen/xen-hotplug.log', 'xen/domain-builder-ng.log', 'squeezed.log',
-       'openvswitch/ovs-vswitchd.log', 'openvswitch/ovsdb-server.log' ] +
-      [ f % n for n in range(1, 20) \
-            for f in ['xensource.log.%d', 'xensource.log.%d.gz','SMlog.%d', 'SMlog.%d.gz', 'VMPRlog.%d', 'VMPRlog.%d.gz',
-                      'audit.log.%d', 'audit.log.%d.gz', 'xenstored-access.log.%d', 'xenstored-access.log.%d.gz', \
-                      'xen/xenstored-access.log.%d', 'xen/xenstored-access.log.%d.gz', 'squeezed.log.%d', \
-                      'openvswitch/ovs-vswitchd.log.%d', 'openvswitch/ovs-vswitchd.log.%d.gz', \
-                      'openvswitch/ovsdb-server.log.%d', 'openvswitch/ovsdb-server.log.%d.gz']]] \
-      + glob.glob('/tmp/qemu.[0-9]*')
-OEM_XENSERVER_LOGS_RE = re.compile(r'^.*xensource\.log$')
-XHA_LOG = '/var/log/xha.log'
-XHAD_CONF = '/etc/xensource/xhad.conf'
-YUM_LOG = '/var/log/yum.log'
-YUM_REPOS_DIR = '/etc/yum.repos.d'
-PAM_DIR = '/etc/pam.d'
-FIST_RE = re.compile(r'.*/fist_')
-LICENSE_LOGS = \
-             [ VAR_LOG_DIR + x for x in
-               ['v6d.log'] +
-               [ f % n for n in range(1, 20) \
-                 for f in ['v6d.log.%d', 'v6d.log.%d.gz' ]]]
-LWIDENTITY_JOIN_LOG = '/tmp/lwidentity.join.log'
-HOSTS_LWIDENTITY_ORIG = '/etc/hosts.lwidentity.orig'
-KRB5_CONF = '/etc/krb5.conf'
-LIKEWISE_DIR = '/var/lib/likewise'
-XENGUEST_LOG = '/tmp/xenguest.log'
-
-#
-# External programs
-#
-
-ARP = '/sbin/arp'
-BIOSDEVNAME = '/sbin/biosdevname'
-BRCTL = '/usr/sbin/brctl'
-CAT = '/bin/cat'
-CHKCONFIG = '/sbin/chkconfig'
-CSL = '/opt/Citrix/StorageLink/bin/csl'
-DF = '/bin/df'
-DMESG = '/bin/dmesg'
-DMIDECODE = '/usr/sbin/dmidecode'
-DMSETUP = '/sbin/dmsetup'
-ETHTOOL = '/sbin/ethtool'
-FDISK = '/sbin/fdisk'
-FIND = '/usr/bin/find'
-HA_QUERY_LIVESET = '/opt/xensource/debug/debug_ha_query_liveset'
-HDPARM = '/sbin/hdparm'
-IFCONFIG = '/sbin/ifconfig'
-IPTABLES = '/sbin/iptables'
-ISCSIADM = '/sbin/iscsiadm'
-LIST_DOMAINS = '/opt/xensource/bin/list_domains'
-LOSETUP = '/sbin/losetup'
-LS = '/bin/ls'
-LSPCI = '/sbin/lspci'
-LVS = '/usr/sbin/lvs'
-LVDISPLAY = '/usr/sbin/lvdisplay'
-MD5SUM = '/usr/bin/md5sum'
-MODINFO = '/sbin/modinfo'
-MPPUTIL = '/usr/sbin/mppUtil'
-MULTIPATHD = '/sbin/multipathd'
-NETSTAT = '/bin/netstat'
-OVS_DPCTL = '/usr/bin/ovs-dpctl'
-OVS_OFCTL = '/usr/bin/ovs-ofctl'
-OVS_VSCTL = '/usr/bin/ovs-vsctl'
-OVS_APPCTL = '/usr/bin/ovs-appctl'
-PS = '/bin/ps'
-PVS = '/usr/sbin/pvs'
-ROUTE = '/sbin/route'
-RPM = '/bin/rpm'
-SG_MAP = '/usr/bin/sg_map'
-SQLITE = '/usr/bin/sqlite3'
-BIN_STATIC_VDIS = '/opt/xensource/bin/static-vdis'
-SYSCTL = '/sbin/sysctl'
-TC = '/sbin/tc'
-UPTIME = '/usr/bin/uptime'
-VGS = '/usr/sbin/vgs'
-VGSCAN = '/sbin/vgscan'
-XAPI_DB_PROCESS = '/opt/xensource/bin/xapi-db-process'
-XE = '/opt/xensource/bin/xe'
-XS = '/opt/xensource/debug/xs'
-XENSTORE_LS = '/usr/bin/xenstore-ls'
-ZCAT = '/bin/zcat'
-
-#
-# PII -- Personally identifiable information.  Of particular concern are
-# things that would identify customers, or their network topology.
-# Passwords are never to be included in any bug report, regardless of any PII
-# declaration.
-#
-# NO            -- No PII will be in these entries.
-# YES           -- PII will likely or certainly be in these entries.
-# MAYBE         -- The user may wish to audit these entries for PII.
-# IF_CUSTOMIZED -- If the files are unmodified, then they will contain no PII,
-# but since we encourage customers to edit these files, PII may have been
-# introduced by the customer.  This is used in particular for the networking
-# scripts in dom0.
-#
-
-PII_NO            = 'no'
-PII_YES           = 'yes'
-PII_MAYBE         = 'maybe'
-PII_IF_CUSTOMIZED = 'if_customized'
-KEY      = 0
-PII      = 1
-MIN_SIZE = 2
-MAX_SIZE = 3
-MIN_TIME = 4
-MAX_TIME = 5
-MIME     = 6
-CHECKED  = 7
-HIDDEN   = 8
-
-MIME_DATA = 'application/data'
-MIME_TEXT = 'text/plain'
-
-INVENTORY_XML_ROOT = "system-status-inventory"
-INVENTORY_XML_SUMMARY = 'system-summary'
-INVENTORY_XML_ELEMENT = 'inventory-entry'
-CAP_XML_ROOT = "system-status-capabilities"
-CAP_XML_ELEMENT = 'capability'
-
-
-CAP_BLOBS                = 'blobs'
-CAP_BOOT_LOADER          = 'boot-loader'
-CAP_CVSM                 = 'CVSM'
-CAP_DISK_INFO            = 'disk-info'
-CAP_FIRSTBOOT            = 'firstboot'
-CAP_HARDWARE_INFO        = 'hardware-info'
-CAP_HDPARM_T             = 'hdparm-t'
-CAP_HIGH_AVAILABILITY    = 'high-availability'
-CAP_HOST_CRASHDUMP_DUMPS = 'host-crashdump-dumps'
-CAP_HOST_CRASHDUMP_LOGS  = 'host-crashdump-logs'
-CAP_KERNEL_INFO          = 'kernel-info'
-CAP_LOSETUP_A            = 'loopback-devices'
-CAP_MULTIPATH            = 'multipath'
-CAP_NETWORK_CONFIG       = 'network-config'
-CAP_NETWORK_STATUS       = 'network-status'
-CAP_OEM                  = 'oem'
-CAP_PAM                  = 'pam'
-CAP_PROCESS_LIST         = 'process-list'
-CAP_PERSISTENT_STATS     = 'persistent-stats'
-CAP_SYSTEM_LOGS          = 'system-logs'
-CAP_SYSTEM_SERVICES      = 'system-services'
-CAP_TAPDISK_LOGS         = 'tapdisk-logs'
-CAP_VNCTERM              = 'vncterm'
-CAP_WLB                  = 'wlb'
-CAP_X11_LOGS             = 'X11'
-CAP_X11_AUTH             = 'X11-auth'
-CAP_XAPI_DEBUG           = 'xapi-debug'
-CAP_XAPI_SUBPROCESS      = 'xapi-subprocess'
-CAP_XENRT                = 'xenrt'
-CAP_XENSERVER_CONFIG     = 'xenserver-config'
-CAP_XENSERVER_DOMAINS    = 'xenserver-domains'
-CAP_XENSERVER_DATABASES  = 'xenserver-databases'
-CAP_XENSERVER_INSTALL    = 'xenserver-install'
-CAP_XENSERVER_LOGS       = 'xenserver-logs'
-CAP_XEN_INFO             = 'xen-info'
-CAP_XHA_LIVESET          = 'xha-liveset'
-CAP_YUM                  = 'yum'
-
-KB = 1024
-MB = 1024 * 1024
-
-caps = {}
-cap_sizes = {}
-unlimited_data = False
-dbg = False
-
-def cap(key, pii=PII_MAYBE, min_size=-1, max_size=-1, min_time=-1,
-        max_time=-1, mime=MIME_TEXT, checked=True, hidden=False):
-    if  os.getenv('XEN_RT') and max_time > 0:
-        max_time *= 5
-    caps[key] = (key, pii, min_size, max_size, min_time, max_time, mime,
-                 checked, hidden)
-    cap_sizes[key] = 0
-
-
-cap(CAP_BLOBS,               PII_NO,                    max_size=5*MB)
-cap(CAP_BOOT_LOADER,         PII_NO,                    max_size=3*KB,
-    max_time=5)
-cap(CAP_CVSM,                PII_NO,                    max_size=3*MB,
-    max_time=120)
-cap(CAP_DISK_INFO,           PII_MAYBE,                 max_size=50*KB,
-    max_time=20)
-cap(CAP_FIRSTBOOT,           PII_YES,   min_size=60*KB, max_size=80*KB)
-cap(CAP_HARDWARE_INFO,       PII_MAYBE,                 max_size=50*KB,
-    max_time=20)
-cap(CAP_HDPARM_T,            PII_NO,    min_size=0,     max_size=5*KB,
-    min_time=20, max_time=90, checked=False, hidden=True)
-cap(CAP_HIGH_AVAILABILITY,   PII_MAYBE,                 max_size=5*MB)
-cap(CAP_HOST_CRASHDUMP_DUMPS,PII_YES, checked = False)
-cap(CAP_HOST_CRASHDUMP_LOGS, PII_NO)
-cap(CAP_KERNEL_INFO,         PII_MAYBE,                 max_size=120*KB,
-    max_time=5)
-cap(CAP_LOSETUP_A,           PII_MAYBE,                 max_size=KB, max_time=5)
-cap(CAP_MULTIPATH,           PII_MAYBE,                 max_size=20*KB,
-    max_time=10)
-cap(CAP_NETWORK_CONFIG,      PII_IF_CUSTOMIZED,
-                                        min_size=0,     max_size=40*KB)
-cap(CAP_NETWORK_STATUS,      PII_YES,                   max_size=19*KB,
-    max_time=30)
-cap(CAP_PAM,                 PII_NO,                    max_size=50*KB)
-cap(CAP_PERSISTENT_STATS,    PII_MAYBE,                 max_size=50*MB,
-    max_time=60)
-cap(CAP_PROCESS_LIST,        PII_YES,                   max_size=30*KB,
-    max_time=20)
-cap(CAP_SYSTEM_LOGS,         PII_MAYBE,                 max_size=50*MB,
-    max_time=5)
-cap(CAP_SYSTEM_SERVICES,     PII_NO,                    max_size=5*KB,
-    max_time=20)
-cap(CAP_TAPDISK_LOGS,        PII_NO,                    max_size=64*KB)
-cap(CAP_VNCTERM,             PII_MAYBE, checked = False)
-cap(CAP_WLB,                 PII_NO,                    max_size=3*MB,
-    max_time=20)
-cap(CAP_X11_LOGS,            PII_NO,                    max_size=100*KB)
-cap(CAP_X11_AUTH,            PII_NO,                    max_size=100*KB)
-cap(CAP_XAPI_DEBUG,          PII_MAYBE,                 max_size=10*MB)
-cap(CAP_XAPI_SUBPROCESS,     PII_NO,                    max_size=5*KB,
-    max_time=10)
-cap(CAP_XENRT,               PII_NO,    min_size=0,     max_size=500*MB,
-    checked=False, hidden=True)
-cap(CAP_XENSERVER_CONFIG,    PII_MAYBE,                 max_size=80*KB,
-    max_time=5)
-cap(CAP_XENSERVER_DOMAINS,   PII_NO,                    max_size=1*KB,
-    max_time=5)
-cap(CAP_XENSERVER_DATABASES, PII_YES,   min_size=500*KB,max_size=2*MB,
-    max_time=40)
-cap(CAP_XENSERVER_INSTALL,   PII_MAYBE, min_size=10*KB, max_size=300*KB)
-cap(CAP_XENSERVER_LOGS,      PII_MAYBE, min_size=0,     max_size=70*MB)
-cap(CAP_XEN_INFO,            PII_MAYBE,                 max_size=20*KB,
-    max_time=10)
-cap(CAP_XHA_LIVESET,         PII_MAYBE,                 max_size=10*KB,
-    max_time=10)
-cap(CAP_YUM,                 PII_IF_CUSTOMIZED,         max_size=10*KB,
-    max_time=30)
-
-ANSWER_YES_TO_ALL = False
-SILENT_MODE = False
-entries = None
-data = {}
-dev_null = open('/dev/null', 'r+')
-
-def output(x):
-    global SILENT_MODE
-    if not SILENT_MODE:
-        print x
-
-def output_ts(x):
-    output("[%s]  %s" % (time.strftime("%x %X %Z"), x))
-
-def cmd_output(cap, args, label = None, filter = None):
-    if cap in entries:
-        if not label:
-            if isinstance(args, list):
-                a = [aa for aa in args]
-                a[0] = os.path.basename(a[0])
-                label = ' '.join(a)
-            else:
-                label = args
-        data[label] = {'cap': cap, 'cmd_args': args, 'filter': filter}
-
-def file_output(cap, path_list):
-    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))
-
-def tree_output(cap, path, pattern = None, negate = False):
-    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)
-
-def func_output(cap, label, func):
-    if cap in entries:
-        t = str(func).split()
-        data[label] = {'cap': cap, 'func': func}
-
-def collect_data():
-    process_lists = {}
-
-    for (k, v) in data.items():
-        cap = v['cap']
-        if v.has_key('cmd_args'):
-            v['output'] = StringIOmtime()
-            if not process_lists.has_key(cap):
-                process_lists[cap] = []
-            process_lists[cap].append(ProcOutput(v['cmd_args'], caps[cap][MAX_TIME], v['output'], v['filter']))
-        elif v.has_key('filename') and v['filename'].startswith('/proc/'):
-            # proc files must be read into memory
-            try:
-                f = open(v['filename'], 'r')
-                s = f.read()
-                f.close()
-                if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
-                        cap_sizes[cap] < caps[cap][MAX_SIZE]:
-                    v['output'] = StringIOmtime(s)
-                    cap_sizes[cap] += len(s)
-                else:
-                    output("Omitting %s, size constraint of %s exceeded" % (v['filename'], cap))
-            except:
-                pass
-        elif v.has_key('func'):
-            try:
-                s = v['func'](cap)
-            except Exception, e:
-                s = str(e)
-            if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
-                    cap_sizes[cap] < caps[cap][MAX_SIZE]:
-                v['output'] = StringIOmtime(s)
-                cap_sizes[cap] += len(s)
-            else:
-                output("Omitting %s, size constraint of %s exceeded" % (k, cap))
-
-    run_procs(process_lists.values())
-
-
-def main(argv = None):
-    global ANSWER_YES_TO_ALL, SILENT_MODE
-    global entries, data, dbg
-
-    # we need access to privileged files, exit if we are not running as root
-    if os.getuid() != 0:
-        print >>sys.stderr, "Error: xen-bugtool must be run as root"
-        return 1
-
-    output_type = 'tar.bz2'
-    output_fd = -1
-    
-    if argv is None:
-        argv = sys.argv
-
-    try:
-        (options, params) = getopt.gnu_getopt(
-            argv, 'sy', ['capabilities', 'silent', 'yestoall', 'entries=',
-                         'output=', 'outfd=', 'all', 'unlimited', 'debug'])
-    except getopt.GetoptError, opterr:
-        print >>sys.stderr, opterr
-        return 2
-
-    try:
-        load_plugins(True)
-    except:
-        pass
-
-    inventory = readKeyValueFile(XENSOURCE_INVENTORY)
-    if inventory.has_key('OEM_BUILD_NUMBER'):
-        cap(CAP_OEM,                 PII_MAYBE,                 max_size=5*MB,
-            max_time=90)
-
-    if  os.getenv('XEN_RT'):
-        entries = [CAP_BLOBS, CAP_BOOT_LOADER, CAP_CVSM, CAP_DISK_INFO, CAP_FIRSTBOOT, CAP_HARDWARE_INFO, 
-                   CAP_HOST_CRASHDUMP_DUMPS, CAP_HOST_CRASHDUMP_LOGS, CAP_KERNEL_INFO, CAP_LOSETUP_A,
-                   CAP_NETWORK_CONFIG, CAP_NETWORK_STATUS, CAP_PROCESS_LIST, CAP_HIGH_AVAILABILITY,
-                   CAP_PAM, CAP_PERSISTENT_STATS, CAP_MULTIPATH,
-                   CAP_SYSTEM_LOGS, CAP_SYSTEM_SERVICES, CAP_TAPDISK_LOGS,
-                   CAP_VNCTERM, CAP_WLB, CAP_X11_LOGS, CAP_X11_AUTH, CAP_XAPI_DEBUG, CAP_XAPI_SUBPROCESS, 
-                   CAP_XENRT, CAP_XENSERVER_CONFIG, CAP_XENSERVER_DOMAINS, CAP_XENSERVER_DATABASES, 
-                   CAP_XENSERVER_INSTALL, CAP_XENSERVER_LOGS, CAP_XEN_INFO, CAP_XHA_LIVESET, CAP_YUM]
-    else:
-        entries = [e for e in caps.keys() if caps[e][CHECKED]]
-
-    for (k, v) in options:
-        if k == '--capabilities':
-            update_capabilities()
-            print_capabilities()
-            return 0
-
-        if k == '--output':
-            if  v in ['tar', 'tar.bz2', 'zip']:
-                output_type = v
-            else:
-                print >>sys.stderr, "Invalid output format '%s'" % v
-                return 2
-
-        # "-s" or "--silent" means suppress output (except for the final
-        # output filename at the end)
-        if k in ['-s', '--silent']:
-            SILENT_MODE = True
-
-        if k == '--entries' and v != '':
-            entries = v.split(',')
-
-        # If the user runs the script with "-y" or "--yestoall" we don't ask
-        # all the really annoying questions.
-        if k in ['-y', '--yestoall']:
-            ANSWER_YES_TO_ALL = True
-
-        if k == '--outfd':
-            output_fd = int(v)
-            try:
-                old = fcntl.fcntl(output_fd, fcntl.F_GETFD)
-                fcntl.fcntl(output_fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
-            except:
-                print >>sys.stderr, "Invalid output file descriptor", output_fd
-                return 2
-
-        elif k == '--all':
-            entries = caps.keys()
-        elif k == '--unlimited':
-            unlimited_data = True
-        elif k == '--debug':
-            dbg = True
-            ProcOutput.debug = True
-
-    if len(params) != 1:
-        print >>sys.stderr, "Invalid additional arguments", str(params)
-        return 2
-
-    if output_fd != -1 and output_type != 'tar':
-        print >>sys.stderr, "Option '--outfd' only valid with '--output=tar'"
-        return 2
-
-    if ANSWER_YES_TO_ALL:
-        output("Warning: '--yestoall' argument provided, will not prompt for individual files.")
-
-    output('''
-This application will collate the Xen dmesg output, details of the
-hardware configuration of your machine, information about the build of
-Xen that you are using, plus, if you allow it, various logs.
-
-The collated information will be saved as a .%s for archiving or
-sending to a Technical Support Representative.
-
-The logs may contain private information, and if you are at all
-worried about that, you should exit now, or you should explicitly
-exclude those logs from the archive.
-
-''' % output_type)
-
-    # assemble potential data
-    tree_output(CAP_BLOBS, XAPI_BLOBS)
-
-    file_output(CAP_BOOT_LOADER, [GRUB_CONFIG, EXTLINUX_CONFIG])
-    cmd_output(CAP_BOOT_LOADER, [LS, '-lR', '/boot'])
-    cmd_output(CAP_BOOT_LOADER, [MD5SUM, BOOT_KERNEL, BOOT_INITRD], label='vmlinuz-initrd.md5sum')
-
-    func_output(CAP_CVSM, 'csl_logs', csl_logs)
-
-    cmd_output(CAP_DISK_INFO, [FDISK, '-l'])
-    file_output(CAP_DISK_INFO, [PROC_PARTITIONS, PROC_MOUNTS])
-    file_output(CAP_DISK_INFO, [FSTAB, ISCSI_CONF, ISCSI_INITIATOR])
-    cmd_output(CAP_DISK_INFO, [DF, '-alT'])
-    cmd_output(CAP_DISK_INFO, [DF, '-alTi'])
-    for d in disk_list():
-        cmd_output(CAP_DISK_INFO, [HDPARM, '-I', '/dev/%s' % d])
-    if len(pidof('iscsid')) != 0:
-        cmd_output(CAP_DISK_INFO, [ISCSIADM, '-m', 'node'])
-    cmd_output(CAP_DISK_INFO, [VGSCAN])
-    cmd_output(CAP_DISK_INFO, [PVS])
-    cmd_output(CAP_DISK_INFO, [VGS])
-    cmd_output(CAP_DISK_INFO, [LVS])
-    file_output(CAP_DISK_INFO, [LVM_CACHE, LVM_CONFIG])
-    cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_host'])
-    cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_disk'])
-    cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/fc_transport'])
-    cmd_output(CAP_DISK_INFO, [SG_MAP, '-x'])
-    func_output(CAP_DISK_INFO, 'scsi-hosts', dump_scsi_hosts)
-    tree_output(CAP_DISK_INFO, PROC_DRIVER_CCISS_DIR)
-    cmd_output(CAP_DISK_INFO, [LVDISPLAY, '--map'])
-
-    tree_output(CAP_FIRSTBOOT, FIRSTBOOT_DIR)
-
-    file_output(CAP_HARDWARE_INFO, [PROC_CPUINFO, PROC_MEMINFO, PROC_IOPORTS, PROC_INTERRUPTS])
-    cmd_output(CAP_HARDWARE_INFO, [DMIDECODE])
-    cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-n'])
-    cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-vv'])
-    file_output(CAP_HARDWARE_INFO, [PROC_USB_DEV, PROC_SCSI])
-    file_output(CAP_HARDWARE_INFO, [BOOT_TIME_CPUS, BOOT_TIME_MEMORY])
-    file_output(CAP_HARDWARE_INFO, [SYSCONFIG_HWCONF])
-    cmd_output(CAP_HARDWARE_INFO, [LS, '-lR', '/dev'])
-    # FIXME IDE?
-
-    for d in disk_list():
-        cmd_output(CAP_HDPARM_T, [HDPARM, '-tT', '/dev/%s' % d])
-
-    file_output(CAP_HIGH_AVAILABILITY, [XHAD_CONF, XHA_LOG])
-
-    tree_output(CAP_HOST_CRASHDUMP_DUMPS, HOST_CRASHDUMPS_DIR,
-                HOST_CRASHDUMP_LOGS_RE, True)
-    tree_output(CAP_HOST_CRASHDUMP_LOGS, HOST_CRASHDUMPS_DIR,
-                HOST_CRASHDUMP_LOGS_RE, False)
-
-    file_output(CAP_KERNEL_INFO, [PROC_VERSION, PROC_MODULES, PROC_DEVICES, 
-                                  PROC_FILESYSTEMS, PROC_CMDLINE])
-    cmd_output(CAP_KERNEL_INFO, [ZCAT, PROC_CONFIG], label='config')
-    cmd_output(CAP_KERNEL_INFO, [SYSCTL, '-A'])
-    file_output(CAP_KERNEL_INFO, [MODPROBE_CONF])
-    tree_output(CAP_KERNEL_INFO, MODPROBE_DIR)
-    func_output(CAP_KERNEL_INFO, 'modinfo', module_info)
-
-    cmd_output(CAP_LOSETUP_A, [LOSETUP, '-a'])
-
-    file_output(CAP_MULTIPATH, [MULTIPATH_CONF, MPP_CONF])
-    cmd_output(CAP_MULTIPATH, [DMSETUP, 'table'])
-    func_output(CAP_MULTIPATH, 'multipathd_topology', multipathd_topology)
-    cmd_output(CAP_MULTIPATH, [MPPUTIL, '-a'])
-    if CAP_MULTIPATH in entries:
-        dump_rdac_groups(CAP_MULTIPATH)
-
-    file_output(CAP_NETWORK_CONFIG, [NETWORK_CONF])
-    file_output(CAP_NETWORK_CONFIG, [NETWORK_DBCACHE])
-    tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, IFCFG_RE)
-    tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, ROUTE_RE)
-    file_output(CAP_NETWORK_CONFIG, [SYSCONFIG_NETWORK, RESOLV_CONF, NSSWITCH_CONF, HOSTS])
-    file_output(CAP_NETWORK_CONFIG, [NTP_CONF, IPTABLES_CONFIG, HOSTS_ALLOW, HOSTS_DENY])
-    file_output(CAP_NETWORK_CONFIG, [OPENVSWITCH_CONF, OPENVSWITCH_CONF_DB])
-
-    cmd_output(CAP_NETWORK_STATUS, [IFCONFIG, '-a'])
-    cmd_output(CAP_NETWORK_STATUS, [ROUTE, '-n'])
-    cmd_output(CAP_NETWORK_STATUS, [ARP, '-n'])
-    cmd_output(CAP_NETWORK_STATUS, [NETSTAT, '-an'])
-    tree_output(CAP_NETWORK_STATUS, DHCP_LEASE_DIR)
-    cmd_output(CAP_NETWORK_STATUS, [IPTABLES, '-nL'])
-    cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'show'])
-    cmd_output(CAP_NETWORK_STATUS, [BIOSDEVNAME, '-d'])
-    for p in os.listdir('/sys/class/net/'):
-        if os.path.isdir('/sys/class/net/%s/bridge' % p):
-            cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'showmacs', p])
-        else:
-            try:
-                f = open('/sys/class/net/%s/type' % p, 'r')
-                t = f.readline()
-                f.close()
-                if 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])
-                    cmd_output(CAP_NETWORK_STATUS,
-                               [TC, '-s', '-d', 'class', 'show', 'dev', p])
-            except:
-                pass
-    tree_output(CAP_NETWORK_STATUS, PROC_NET_BONDING_DIR)
-    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_CORE_DIR)
-    if os.path.exists(OPENVSWITCH_VSWITCHD_PID):
-        cmd_output(CAP_NETWORK_STATUS, [OVS_DPCTL, 'show'])
-        for d in dp_list():
-            cmd_output(CAP_NETWORK_STATUS, [OVS_OFCTL, 'show', d])
-            cmd_output(CAP_NETWORK_STATUS, [OVS_OFCTL, 'status', d])
-            cmd_output(CAP_NETWORK_STATUS, [OVS_OFCTL, 'dump-flows', d])
-            cmd_output(CAP_NETWORK_STATUS, [OVS_DPCTL, 'dump-flows', d])
-        try:
-            vspidfile = open(OPENVSWITCH_VSWITCHD_PID)
-            vspid = int(vspidfile.readline().strip())
-            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-bond-show-%s.out' % b)
-        except e:
-            pass
-
-    tree_output(CAP_PAM, PAM_DIR)
-    file_output(CAP_PAM, [KRB5_CONF])
-    tree_output(CAP_PAM, LIKEWISE_DIR)
-
-    func_output(CAP_PERSISTENT_STATS, 'xapi_rrd-host', dump_xapi_rrds)
-
-    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)
-
-    file_output(CAP_SYSTEM_LOGS,
-         [ VAR_LOG_DIR + x for x in
-           [ 'crit.log', 'kern.log', 'daemon.log', 'user.log', 'syslog', 'messages',
-             'monitor_memory.log', 'secure', 'debug', 'dmesg', 'boot.msg', 'blktap.log' ] +
-           [ 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',
-                           'monitor_memory.log.%d', 'monitor_memory.log.%d.gz',
-                           'secure.%d', 'secure.%d.gz',
-                           'blktap.log.%d']]])
-    if not os.path.exists('/var/log/dmesg') and not os.path.exists('/var/log/boot.msg'):
-        cmd_output(CAP_SYSTEM_LOGS, [DMESG])
-    file_output(CAP_SYSTEM_LOGS, [LWIDENTITY_JOIN_LOG, HOSTS_LWIDENTITY_ORIG])
-
-    cmd_output(CAP_SYSTEM_SERVICES, [CHKCONFIG, '--list'])
-
-    if CAP_TAPDISK_LOGS in entries:
-        generate_tapdisk_logs()
-
-    tree_output(CAP_VNCTERM, VNCTERM_CORE_DIR)
-
-    cmd_output(CAP_WLB, [XE, 'pool-retrieve-wlb-configuration'])
-    cmd_output(CAP_WLB, [XE, 'pool-retrieve-wlb-diagnostics'])
-
-    tree_output(CAP_X11_LOGS, X11_LOGS_DIR, X11_LOGS_RE)
-    tree_output(CAP_X11_AUTH, X11_AUTH_DIR, X11_AUTH_RE)
-
-    tree_output(CAP_XAPI_DEBUG, XAPI_DEBUG_DIR)
-
-    func_output(CAP_XAPI_SUBPROCESS, 'xapi_subprocesses', dump_xapi_subprocess_info)
-
-    tree_output(CAP_XENRT, '/tmp', FIST_RE)
-    # CA-45540: capture QEMU core files
-    tree_output(CAP_XENRT, '/var/xen/qemu')
-    tree_output(CAP_XENRT, '/tmp', re.compile(r'^.*xen\.qemu-dm\.'))
-
-    file_output(CAP_XENSERVER_CONFIG, [INITIAL_INVENTORY])
-    file_output(CAP_XENSERVER_CONFIG, [POOL_CONF, PTOKEN, XAPI_CONF, XAPI_SSL_CONF, 
-                                       XENSOURCE_INVENTORY, VENDORKERNEL_INVENTORY])
-    cmd_output(CAP_XENSERVER_CONFIG, [LS, '-lR', '/opt/xensource'])
-    cmd_output(CAP_XENSERVER_CONFIG, [BIN_STATIC_VDIS, 'list'])
-    tree_output(CAP_XENSERVER_CONFIG, OEM_CONFIG_DIR, OEM_CONFIG_FILES_RE)
-    tree_output(CAP_XENSERVER_CONFIG, STATIC_VDIS)
-    cmd_output(CAP_XENSERVER_CONFIG, [LS, '-lR', STATIC_VDIS])
-
-    func_output(CAP_XENSERVER_DATABASES, 'xapi-db.xml', dump_filtered_xapi_db)
-    cmd_output(CAP_XENSERVER_DATABASES, [XENSTORE_LS, '-f'])
-    file_output(CAP_XENSERVER_DATABASES, [DB_CONF, DB_CONF_RIO, DB_DEFAULT_FIELDS, DB_SCHEMA_SQL])
-    tree_output(CAP_XENSERVER_DATABASES, OEM_CONFIG_DIR, OEM_DB_FILES_RE)
-    file_output(CAP_XENSERVER_DATABASES, [XENSTORED_DB, XENSTORED_DB + '.bak'])
-    cmd_output(CAP_XENSERVER_DATABASES, [XE, 'pool-dump-database', 'file-name='], 
-               label="xapi-db-dumped.xml", filter=filter_db_pii)
-    cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'watches'])
-    cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'quotas'])
-
-    cmd_output(CAP_XENSERVER_DOMAINS, [LIST_DOMAINS])
-
-    tree_output(CAP_XENSERVER_INSTALL, VAR_LOG_DIR + 'installer')
-    file_output(CAP_XENSERVER_INSTALL,
-                [ VAR_LOG_DIR + x for x in 
-                  [ 'firstboot-SR-commands-log', 
-                    'upgrade-commands-log', 'generate-iscsi-iqn-log']] +
-                [ '/root/' + x for x in 
-                  [ 'blockdevs-log', 'cmdline-log', 'devcontents-log',
-                    'dmesg-log', 'install-log', 'lspci-log', 'modules-log',
-                    'pci-log', 'processes-log', 'tty-log', 'uname-log',
-                    'vgscan-log']])
-    tree_output(CAP_XENSERVER_INSTALL, INSTALLED_REPOS_DIR)
-    tree_output(CAP_XENSERVER_INSTALL, PATCH_APPLIED_DIR)
-
-    file_output(CAP_XENSERVER_LOGS, [LOG_CONF, XENGUEST_LOG])
-    file_output(CAP_XENSERVER_LOGS, XENSERVER_LOGS)
-    file_output(CAP_XENSERVER_LOGS, LICENSE_LOGS)
-    tree_output(CAP_XENSERVER_LOGS, OEM_CONFIG_DIR, OEM_XENSERVER_LOGS_RE)
-
-    try:
-        def xen_dmesg(xc):
-            data = xc.readconsolering()
-            xc.send_debug_keys('q')
-            time.sleep(1)
-            return data
-
-        xc = xen.lowlevel.xc.xc()
-
-        func_output(CAP_XEN_INFO, 'xen-dmesg', lambda x: xen_dmesg(xc))
-        func_output(CAP_XEN_INFO, 'physinfo', lambda x: prettyDict(xc.physinfo()))
-        func_output(CAP_XEN_INFO, 'xeninfo', lambda x: prettyDict(xc.xeninfo()))
-    except:
-        pass
-    file_output(CAP_XEN_INFO, [PROC_XEN_BALLOON])
-
-    cmd_output(CAP_XHA_LIVESET, [HA_QUERY_LIVESET])
-
-    file_output(CAP_YUM, [YUM_LOG])
-    tree_output(CAP_YUM, YUM_REPOS_DIR)
-    cmd_output(CAP_YUM, [RPM, '-qa'])
-
-    try:
-        load_plugins()
-    except:
-        pass
-    
-    # permit the user to filter out data
-    for k in sorted(data.keys()):
-        if not ANSWER_YES_TO_ALL and not yes("Include '%s'? [Y/n]: " % k):
-            del data[k]
-
-    # collect selected data now
-    output_ts('Running commands to collect data')
-    collect_data()
-
-    subdir = os.getenv('XENRT_BUGTOOL_BASENAME')
-    if subdir:
-        subdir = os.path.basename(subdir)
-        if subdir == '..' or subdir == '.':
-            subdir = None
-    if not subdir:
-        subdir = "bug-report-%s" % time.strftime("%Y%m%d%H%M%S")
-
-    # include inventory
-    data['inventory.xml'] = {'cap': None, 'output': StringIOmtime(make_inventory(data, subdir))}
-
-    # create archive
-    if output_fd == -1 and not os.path.exists(BUG_DIR):
-        try:
-            os.makedirs(BUG_DIR)
-        except:
-            pass
-
-    if output_fd == -1:
-        output_ts('Creating output file')
-
-    if output_type.startswith('tar'):
-        make_tar(subdir, output_type, output_fd)
-    else:
-        make_zip(subdir)
-
-    clean_tapdisk_logs()
-
-    if dbg:
-        print >>sys.stderr, "Category sizes (max, actual):\n"
-        for c in caps.keys():
-            print >>sys.stderr, "    %s (%d, %d)" % (c, caps[c][MAX_SIZE], 
-                                                     cap_sizes[c])
-    return 0
-
-def find_tapdisk_logs():
-    return glob.glob('/var/log/blktap/*.log*')
-
-def generate_tapdisk_logs():
-    for pid in pidof('tapdisk'):
-       try:
-           os.kill(pid, SIGUSR1)
-            output_ts("Including logs for tapdisk process %d" % pid)
-        except :
-            pass
-    # give processes a second to write their logs
-    time.sleep(1)
-    file_output(CAP_TAPDISK_LOGS, find_tapdisk_logs())
-
-def clean_tapdisk_logs():
-    for filename in find_tapdisk_logs():
-        try:
-            os.remove(filename)
-        except :
-            pass
-
-def dump_xapi_subprocess_info(cap):
-    """Check which fds are open by xapi and its subprocesses to diagnose faults like CA-10543.
-       Returns a string containing a pretty-printed pstree-like structure. """
-    pids = filter(lambda x: x.isdigit(), os.listdir("/proc"))
-    def readlines(filename):
-        lines = ''
-       try:
-            f = open(filename, "r")
-            lines = f.readlines()
-            f.close()
-        except:
-            pass
-        return lines
-    def cmdline(pid):
-       all = readlines("/proc/" + pid + "/cmdline")
-       if all == []:
-          return ""
-       else:
-          return all[0].replace('\x00', ' ')
-    def parent(pid):
-       for i in readlines("/proc/" + pid + "/status"):
-           if i.startswith("PPid:"):
-              return i.split()[-1]
-       return None
-    def pstree(pid):
-       result = { "cmdline": cmdline(pid) }
-       child_pids = filter(lambda x:parent(x) == pid, pids)
-       children = { }
-       for child in child_pids:
-           children[child] = pstree(child)
-       result['children'] = children
-       fds = { }
-       for fd in os.listdir("/proc/" + pid + "/fd"):
-            try:
-                fds[fd] = os.readlink("/proc/" + pid + "/fd/" + fd)
-            except:
-                pass
-       result['fds'] = fds
-       return result   
-    xapis = filter(lambda x: cmdline(x).startswith("/opt/xensource/bin/xapi"), pids)
-    xapis = filter(lambda x: parent(x) == "1", xapis)
-    result = {}
-    for xapi in xapis:
-       result[xapi] = pstree(xapi)
-    pp = pprint.PrettyPrinter(indent=4)
-    return pp.pformat(result)
-
-def dump_xapi_rrds(cap):
-    socket.setdefaulttimeout(5)
-    session = XenAPI.xapi_local()
-    session.xenapi.login_with_password('', '')
-    this_host = session.xenapi.session.get_this_host(session._session)
-    # better way to find pool master?
-    pool = session.xenapi.pool.get_all_records().values()[0]
-    i_am_master = (this_host == pool['master'])
-
-    for vm in session.xenapi.VM.get_all_records().values():
-        if vm['is_a_template']:
-            continue
-        if vm['resident_on'] == this_host or (i_am_master and vm['power_state'] in ['Suspended', 'Halted']):
-            rrd = urllib.urlopen('http://localhost/vm_rrd?session_id=%s&uuid=%s' % (session._session, vm['uuid']))
-            try:
-                (i, o, x) = select([rrd], [], [], 5.0)
-                if len(i) == 1:
-                    data['xapi_rrd-%s' % vm['uuid']] = {'cap': cap, 
-                                                        'output': StringIOmtime(rrd.read())}
-            finally:
-                rrd.close()
-
-    output = ''
-    rrd = urllib.urlopen('http://localhost/host_rrd?session_id=%s' % session._session)
-    try:
-        for line in rrd:
-            output += line
-    finally:
-        rrd.close()
-        
-    session.xenapi.session.logout()
-    return output
-
-'''Filter a Xapi XML database.
-
-    There is one important assumption made in this class:
-    - the XML document does not contain any characters between the end of one
-      tag and the beginning of the next, ie every > is immediately followed by
-      a <
-'''
-class DBFilter:
-    def __init__(self):
-        self.result = ''
-        self.rest = ''
-        self.state = {}
-
-    def filter_secrets(self, s):
-        if 'in_secret_table' not in self.state:
-            self.state['in_secret_table'] = False
-
-        # this logic doesn't deal with <table name="secret" /> properly!!!
-        if s.startswith('<table ') and 'name="secret"' in s:
-            self.state['in_secret_table'] = True
-        elif s.startswith('</table>'):
-            self.state['in_secret_table'] = False
-        
-        if self.state['in_secret_table'] and s.startswith("<row"): # match only on DB rows
-            s = re.sub(r'(value=")[^"]+(")', r'\1REMOVED\2', s)
-        return s
-
-    def feed(self, s):
-        rem = self.rest + s
-        p = rem.find('>')
-        while p != -1:
-            s = rem[:p+1]
-            rem = rem[p+1:]
-            self.result  += self.filter_secrets(s)
-            p = rem.find('>')
-        self.rest = rem
-
-    def output(self):
-        r = self.result + self.filter_secrets(self.rest)
-        self.result, self.rest = '', ''
-        self.state = {}
-        return r
-
-def filter_db_pii(s, state):
-    dbfilter = DBFilter()
-    dbfilter.feed(s)
-    return dbfilter.output()
-
-def dump_filtered_xapi_db(cap):
-    db_file = None
-    format = None
-    state = {}
-
-    # determine db format
-    c = open(DB_CONF, 'r')
-    try:
-        for line in c:
-            l = line.rstrip('\n')
-            if l.startswith('['):
-                db_file = l[1:-1]
-            if l.startswith('format:'):
-                format = l[7:]
-                break
-    finally:
-        c.close()
-
-    pipe = None
-    ih = None
-    output = ''
-
-    if format == 'sqlite':
-        pipe = Popen([XAPI_DB_PROCESS, '-xmltostdout'], bufsize=1, stdin=dev_null, 
-                     stdout=PIPE, stderr=dev_null)
-        ih = pipe.stdout
-    elif db_file:
-        ih = open(db_file, 'r')
-
-    if not ih:
-        return ''
-
-    dbfilter = DBFilter()
-    rec = ih.read(2048)
-    while rec != '':
-        dbfilter.feed(rec)
-        rec = ih.read(2048)
-    output = dbfilter.output()
-
-    if pipe:
-        pipe.wait()
-    else:
-        ih.close()
-    return output
-
-def dump_scsi_hosts(cap):
-    output = ''
-    l = os.listdir('/sys/class/scsi_host')
-    l.sort()
-
-    for h in l:
-        procname = ''
-        try:
-                f = open('/sys/class/scsi_host/%s/proc_name' % h)
-                procname = f.readline().strip("\n")
-                f.close()
-        except:
-                pass
-        modelname = None
-        try:
-                f = open('/sys/class/scsi_host/%s/model_name' % h)
-                modelname = f.readline().strip("\n")
-                f.close()
-        except:
-                pass
-
-        output += "%s:\n" %h
-        output += "    %s%s\n" % (procname, modelname and (" -> %s" % modelname) or '')
-
-    return output
-
-def module_info(cap):
-    output = StringIO.StringIO()
-    modules = open(PROC_MODULES, 'r')
-    procs = []
-
-    for line in modules:
-        module = line.split()[0]
-        procs.append(ProcOutput([MODINFO, module], caps[cap][MAX_TIME], output))
-    modules.close()
-
-    run_procs([procs])
-
-    return output.getvalue()
-
-def csl_logs(cap):
-    socket.setdefaulttimeout(5)
-    session = XenAPI.xapi_local()
-    session.xenapi.login_with_password('', '')
-    this_host = session.xenapi.session.get_this_host(session._session)
-    # better way to find pool master?
-    pool = session.xenapi.pool.get_all_records().values()[0]
-    i_am_master = (this_host == pool['master'])
-
-    output = StringIO.StringIO()
-    procs = []
-    csl_targets_fetched = []
-
-    for pbd in session.xenapi.PBD.get_all_records().values():
-        if pbd.has_key('device_config') and pbd['device_config'].has_key('target'):
-            if pbd['device_config']['target'] in csl_targets_fetched:
-                continue
-            sr = session.xenapi.SR.get_record(pbd['SR'])
-            if sr.has_key('type') and sr['type'] == 'cslg':
-                if sr['shared'] and pbd['host'] != this_host and not i_am_master:
-                    continue
-                
-                dev_cfg = pbd['device_config']
-                server = "server=%s" % socket.gethostbyname(dev_cfg['target'])
-                if dev_cfg.has_key('port'):
-                    server += ':' + dev_cfg['port']
-                if dev_cfg.has_key('username'):
-                    server += ',' + dev_cfg['username']
-                if dev_cfg.has_key('password_secret'):
-                    sec_ref = session.xenapi.secret.get_by_uuid(dev_cfg['password_secret'])
-                    server += ',' + session.xenapi.secret.get_value(sec_ref)
-                procs.append(ProcOutput([CSL, server, 'srv-log-get'], caps[cap][MAX_TIME], output))
-                csl_targets_fetched.append(dev_cfg['target'])
-
-    session.xenapi.session.logout()
-
-    run_procs([procs])
-
-    return output.getvalue()
-
-def multipathd_topology(cap):
-    pipe = Popen([MULTIPATHD, '-k'], bufsize=1, stdin=PIPE, 
-                     stdout=PIPE, stderr=dev_null)
-    stdout, stderr = pipe.communicate('show topology')
-
-    return stdout
-
-def dp_list():
-    output = StringIO.StringIO()
-    procs = [ProcOutput([OVS_DPCTL, 'dump-dps'], caps[CAP_NETWORK_STATUS][MAX_TIME], output)]
-
-    run_procs([procs])
-
-    if not procs[0].timed_out:
-        return output.getvalue().splitlines()
-    return []
-
-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)]
-
-    run_procs([procs])
-
-    if not procs[0].timed_out:
-        bonds = output.getvalue().splitlines()[1:]
-        return [x.split('\t')[1] for x in bonds]
-    return []
-
-def fd_usage(cap):
-    output = ''
-    fd_dict = {}
-    for d in [p for p in os.listdir('/proc') if p.isdigit()]:
-        try:
-            fh = open('/proc/'+d+'/cmdline')
-            name = fh.readline()
-            num_fds = len(os.listdir(os.path.join('/proc/'+d+'/fd')))
-            if num_fds > 0:
-                if not num_fds in fd_dict:
-                    fd_dict[num_fds] = []
-                fd_dict[num_fds].append(name.replace('\0', ' ').strip())
-        finally:
-            fh.close()
-    keys = fd_dict.keys()
-    keys.sort(lambda a, b: int(b) - int(a))
-    for k in keys:
-        output += "%s: %s\n" % (k, str(fd_dict[k]))
-    return output
-
-def dump_rdac_groups(cap):
-    output = StringIO.StringIO()
-    procs = [ProcOutput([MPPUTIL, '-a'], caps[cap][MAX_TIME], output)]
-
-    run_procs([procs])
-
-    if not procs[0].timed_out:
-        proc_line = 0
-        for line in output.getvalue().splitlines():
-            if line.startswith('ID'):
-                proc_line = 2
-            elif line.startswith('----'):
-                proc_line -= 1
-            elif proc_line > 0:
-                group, _ = line.split(None, 1)
-                cmd_output(cap, [MPPUTIL, '-g', group])
-
-def load_plugins(just_capabilities = False):
-    def getText(nodelist):
-        rc = ""
-        for node in nodelist:
-            if node.nodeType == node.TEXT_NODE:
-                rc += node.data
-        return rc.encode()
-
-    def getBoolAttr(el, attr, default = False):
-        ret = default
-        val = el.getAttribute(attr).lower()
-        if val in ['true', 'false', 'yes', 'no']:
-            ret = val in ['true', 'yes']
-        return ret
-        
-    for dir in [d for d in os.listdir(PLUGIN_DIR) if os.path.isdir(os.path.join(PLUGIN_DIR, d))]:
-        if not caps.has_key(dir):
-            if not os.path.exists("%s/%s.xml" % (PLUGIN_DIR, dir)):
-                continue
-            xmldoc = parse("%s/%s.xml" % (PLUGIN_DIR, dir))
-            assert xmldoc.documentElement.tagName == "capability"
-
-            pii, min_size, max_size, min_time, max_time, mime = \
-                 PII_MAYBE, -1,-1,-1,-1, MIME_TEXT
-
-            if xmldoc.documentElement.getAttribute("pii") in [PII_NO, PII_YES, PII_MAYBE, PII_IF_CUSTOMIZED]:
-                pii = xmldoc.documentElement.getAttribute("pii")
-            if xmldoc.documentElement.getAttribute("min_size") != '':
-                min_size = long(xmldoc.documentElement.getAttribute("min_size"))
-            if xmldoc.documentElement.getAttribute("max_size") != '':
-                max_size = long(xmldoc.documentElement.getAttribute("max_size"))
-            if xmldoc.documentElement.getAttribute("min_time") != '':
-                min_time = int(xmldoc.documentElement.getAttribute("min_time"))
-            if xmldoc.documentElement.getAttribute("max_time") != '':
-                max_time = int(xmldoc.documentElement.getAttribute("max_time"))
-            if xmldoc.documentElement.getAttribute("mime") in [MIME_DATA, MIME_TEXT]:
-                mime = xmldoc.documentElement.getAttribute("mime")
-            checked = getBoolAttr(xmldoc.documentElement, 'checked', True)
-            hidden = getBoolAttr(xmldoc.documentElement, 'hidden', False)
-
-            cap(dir, pii, min_size, max_size, min_time, max_time, mime, checked, hidden)
-
-        if just_capabilities:
-            continue
-                    
-        plugdir = os.path.join(PLUGIN_DIR, dir)
-        for file in [f for f in os.listdir(plugdir) if f.endswith('.xml')]:
-            xmldoc = parse(os.path.join(plugdir, file))
-            assert xmldoc.documentElement.tagName == "collect"
-
-            for el in xmldoc.documentElement.getElementsByTagName("*"):
-                if el.tagName == "files":
-                    file_output(dir, getText(el.childNodes).split())
-                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)
-                elif el.tagName == "command":
-                    label = el.getAttribute("label")
-                    if label == '': label = None
-                    cmd_output(dir, getText(el.childNodes), label)
-
-def make_tar(subdir, suffix, output_fd):
-    global SILENT_MODE, data
-
-    mode = 'w'
-    if suffix == 'tar.bz2':
-        mode = 'w:bz2'
-    filename = "%s/%s.%s" % (BUG_DIR, subdir, suffix)
-
-    if output_fd == -1:
-        tf = tarfile.open(filename, mode)
-    else:
-        tf = tarfile.open(None, 'w', os.fdopen(output_fd, 'a'))
-
-    try:
-        for (k, v) in data.items():
-            try:
-                tar_filename = os.path.join(subdir, construct_filename(k, v))
-                ti = tarfile.TarInfo(tar_filename)
-
-                ti.uname = 'root'
-                ti.gname = 'root'
-
-                if v.has_key('output'):
-                    ti.mtime = v['output'].mtime
-                    ti.size = len(v['output'].getvalue())
-                    v['output'].seek(0)
-                    tf.addfile(ti, v['output'])
-                elif v.has_key('filename'):
-                    s = os.stat(v['filename'])
-                    ti.mtime = s.st_mtime
-                    ti.size = s.st_size
-                    tf.addfile(ti, file(v['filename']))
-            except:
-                pass
-    finally:
-        tf.close()
-
-    if output_fd == -1:
-        output ('Writing tarball %s successful.' % filename)
-        if SILENT_MODE:
-            print filename
-
-
-def make_zip(subdir):
-    global SILENT_MODE, data
-
-    filename = "%s/%s.zip" % (BUG_DIR, subdir)
-    zf = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED)
-
-    try:
-        for (k, v) in data.items():
-            try:
-                dest = os.path.join(subdir, construct_filename(k, v))
-            
-                if v.has_key('output'):
-                    zf.writestr(dest, v['output'].getvalue())
-                elif v.has_key('filename'):
-                    if os.stat(v['filename']).st_size < 50:
-                        compress_type = zipfile.ZIP_STORED
-                    else:
-                        compress_type = zipfile.ZIP_DEFLATED
-                    zf.write(v['filename'], dest, compress_type)
-            except:
-                pass
-    finally:
-        zf.close()
-    
-    output ('Writing archive %s successful.' % filename)
-    if SILENT_MODE:
-        print filename
-
-
-def make_inventory(inventory, subdir):
-    document = getDOMImplementation().createDocument(
-        None, INVENTORY_XML_ROOT, None)
-
-    # create summary entry
-    s = document.createElement(INVENTORY_XML_SUMMARY)
-    user = os.getenv('SUDO_USER', os.getenv('USER'))
-    if user:
-        s.setAttribute('user', user)
-    s.setAttribute('date', time.strftime('%c'))
-    s.setAttribute('hostname', platform.node())
-    s.setAttribute('uname', ' '.join(platform.uname()))
-    s.setAttribute('uptime', commands.getoutput(UPTIME))
-    document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(s)
-
-    map(lambda (k, v): inventory_entry(document, subdir, k, v),
-        inventory.items())
-    return document.toprettyxml()
-
-def inventory_entry(document, subdir, k, v):
-    try:
-        el = document.createElement(INVENTORY_XML_ELEMENT)
-        el.setAttribute('capability', v['cap'])
-        el.setAttribute('filename', os.path.join(subdir, construct_filename(k, v)))
-        el.setAttribute('md5sum', md5sum(v))
-        document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(el)
-    except:
-        pass
-
-
-def md5sum(d):
-    m = md5.new()
-    if d.has_key('filename'):
-        f = open(d['filename'])
-        data = f.read(1024)
-        while len(data) > 0:
-            m.update(data)
-            data = f.read(1024)
-        f.close()
-    elif d.has_key('output'):
-        m.update(d['output'].getvalue())
-    return m.hexdigest()
-
-
-def construct_filename(k, v):
-    if v.has_key('filename'):
-        if v['filename'][0] == '/':
-            return v['filename'][1:]
-        else:
-            return v['filename']
-    s = k.replace(' ', '-')
-    s = s.replace('--', '-')
-    s = s.replace('/', '%')
-    if s.find('.') == -1:
-        s += '.out'
-
-    return s
-
-
-def update_capabilities():
-    update_cap_size(CAP_HOST_CRASHDUMP_LOGS,
-                    size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE))
-    update_cap_size(CAP_HOST_CRASHDUMP_DUMPS,
-                    size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE,
-                                True))
-    update_cap_size(CAP_XAPI_DEBUG, size_of_dir(XAPI_DEBUG_DIR))
-    update_cap_size(CAP_XENSERVER_LOGS, size_of_all(XENSERVER_LOGS))
-
-
-def update_cap_size(cap, size):
-    update_cap(cap, MIN_SIZE, size)
-    update_cap(cap, MAX_SIZE, size)
-    update_cap(cap, CHECKED, size > 0)
-
-
-def update_cap(cap, k, v):
-    global caps
-    l = list(caps[cap])
-    l[k] = v
-    caps[cap] = tuple(l)
-
-
-def size_of_dir(d, pattern = None, negate = False):
-    if os.path.isdir(d):
-        return size_of_all([os.path.join(d, fn) for fn in os.listdir(d)],
-                           pattern, negate)
-    else:
-        return 0
-
-
-def size_of_all(files, pattern = None, negate = False):
-    return sum([size_of(f, pattern, negate) for f in files])
-
-
-def matches(f, pattern, negate):
-    if negate:
-        return not matches(f, pattern, False)
-    else:
-        return pattern is None or pattern.match(f)
-
-
-def size_of(f, pattern, negate):
-    if os.path.isfile(f) and matches(f, pattern, negate):
-        return os.stat(f)[6]
-    else:
-        return size_of_dir(f, pattern, negate)
-
-
-def print_capabilities():
-    document = getDOMImplementation().createDocument(
-        "ns", CAP_XML_ROOT, None)
-    map(lambda key: capability(document, key), [k for k in caps.keys() if not caps[k][HIDDEN]])
-    print document.toprettyxml()
-
-def capability(document, key):
-    c = caps[key]
-    el = document.createElement(CAP_XML_ELEMENT)
-    el.setAttribute('key', c[KEY])
-    el.setAttribute('pii', c[PII])
-    el.setAttribute('min-size', str(c[MIN_SIZE]))
-    el.setAttribute('max-size', str(c[MAX_SIZE]))
-    el.setAttribute('min-time', str(c[MIN_TIME]))
-    el.setAttribute('max-time', str(c[MAX_TIME]))
-    el.setAttribute('content-type', c[MIME])
-    el.setAttribute('default-checked', c[CHECKED] and 'yes' or 'no')
-    document.getElementsByTagName(CAP_XML_ROOT)[0].appendChild(el)
-
-
-def prettyDict(d):
-    format = '%%-%ds: %%s' % max(map(len, [k for k, _ in d.items()]))
-    return '\n'.join([format % i for i in d.items()]) + '\n'
-
-
-def yes(prompt):
-    yn = raw_input(prompt)
-
-    return len(yn) == 0 or yn.lower()[0] == 'y'
-
-
-partition_re = re.compile(r'(.*[0-9]+$)|(^xvd)')
-
-def disk_list():
-    disks = []
-    try:
-        f = open('/proc/partitions')
-        f.readline()
-        f.readline()
-        for line in f.readlines():
-            (major, minor, blocks, name) = line.split()
-            if int(major) < 254 and not partition_re.match(name):
-                disks.append(name)
-        f.close()
-    except:
-        pass
-    return disks
-
-
-class ProcOutput:
-    debug = False
-
-    def __init__(self, command, max_time, inst=None, filter=None):
-        self.command = command
-        self.max_time = max_time
-        self.inst = inst
-        self.running = False
-        self.status = None
-        self.timed_out = False
-        self.failed = False
-        self.timeout = int(time.time()) + self.max_time
-        self.filter = filter
-        self.filter_state = {}
-
-    def __del__(self):
-        self.terminate()
-
-    def cmdAsStr(self):
-        return isinstance(self.command, list) and ' '.join(self.command) or self.command
-
-    def run(self):
-        self.timed_out = False
-        try:
-            if ProcOutput.debug:
-                output_ts("Starting '%s'" % self.cmdAsStr())
-            self.proc = Popen(self.command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null, shell=isinstance(self.command, str))
-            old = fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_GETFD)
-            fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
-            self.running = True
-            self.failed = False
-        except:
-            output_ts("'%s' failed" % self.cmdAsStr())
-            self.running = False
-            self.failed = True
-
-    def terminate(self):
-        if self.running:
-            try:
-                os.kill(self.proc.pid, SIGTERM)
-            except:
-                pass
-            self.proc = None
-            self.running = False
-            self.status = SIGTERM
-
-    def read_line(self):
-        assert self.running
-        line = self.proc.stdout.readline()
-        if line == '':
-            # process exited
-            self.status = self.proc.wait()
-            self.proc = None
-            self.running = False
-        else:
-            if self.filter:
-                line = self.filter(line, self.filter_state)
-            if self.inst:
-                self.inst.write(line)
-
-def run_procs(procs):
-    while True:
-        pipes = []
-        active_procs = []
-
-        for pp in procs:
-            for p in pp:
-                if p.running:
-                    active_procs.append(p)
-                    pipes.append(p.proc.stdout)
-                    break
-                elif p.status == None and not p.failed and not p.timed_out:
-                    p.run()
-                    if p.running:
-                        active_procs.append(p)
-                        pipes.append(p.proc.stdout)
-                        break
-
-        if len(pipes) == 0:
-            # all finished
-            break
-
-        (i, o, x) = select(pipes, [], [], 1.0)
-        now = int(time.time())
-
-        # handle process output
-        for p in active_procs:
-            if p.proc.stdout in i:
-                p.read_line()
-
-            # handle timeout
-            if p.running and now > p.timeout:
-                output_ts("'%s' timed out" % p.cmdAsStr())
-                if p.inst:
-                    p.inst.write("\n** timeout **\n")
-                p.timed_out = True
-                p.terminate()
-
-
-def pidof(name):
-    pids = []
-
-    for d in [p for p in os.listdir('/proc') if p.isdigit()]:
-        try:
-            if os.path.basename(os.readlink('/proc/%s/exe' % d)) == name:
-                pids.append(int(d))
-        except:
-            pass
-        
-    return pids
-
-
-def readKeyValueFile(filename, allowed_keys = None, strip_quotes = True, assert_quotes = True):
-    """ Reads a KEY=Value style file (e.g. xensource-inventory). Returns a 
-    dictionary of key/values in the file.  Not designed for use with large files
-    as the file is read entirely into memory."""
-
-    f = open(filename, "r")
-    lines = [x.strip("\n") for x in f.readlines()]
-    f.close()
-
-    # remove lines contain
-    if allowed_keys:
-        lines = filter(lambda x: True in [x.startswith(y) for y in allowed_keys],
-                       lines)
-    
-    defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ]
-
-    if strip_quotes:
-        def quotestrip(x):
-            if assert_quotes:
-                assert x.startswith("'") and x.endswith("'")
-            return x.strip("'")
-        defs = [ (a, quotestrip(b)) for (a,b) in defs ]
-
-    return dict(defs)
-
-
-class StringIOmtime(StringIO.StringIO):
-    def __init__(self, buf = ''):
-        StringIO.StringIO.__init__(self, buf)
-        self.mtime = time.time()
-
-    def write(self, s):
-        StringIO.StringIO.write(self, s)
-        self.mtime = time.time()
-
-
-if __name__ == "__main__":
-    try:
-        sys.exit(main())
-    except KeyboardInterrupt:
-        print "\nInterrupted."
-        sys.exit(3)
diff --git a/xenserver/usr_share_openvswitch_scripts_xen-bugtool-tc-class-show b/xenserver/usr_share_openvswitch_scripts_xen-bugtool-tc-class-show
new file mode 100755 (executable)
index 0000000..df07f2a
--- /dev/null
@@ -0,0 +1,25 @@
+#! /bin/sh
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General
+# Public License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+#
+# Copyright (C) 2011 Nicira Networks.
+
+for iface in $(cd /sys/class/net && echo *); do
+    if [ -d /sys/class/net/$iface ]; then
+       echo Interface $iface:
+       # indent tc output so it's clear which interface it pertains to
+       /sbin/tc -s -d class show dev $iface | /bin/sed 's/^/ /'
+    fi
+done