3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of version 2.1 of the GNU Lesser General Public
5 # License as published by the Free Software Foundation.
7 # This library is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 # Lesser General Public License for more details.
12 # You should have received a copy of the GNU Lesser General Public
13 # License along with this library; if not, write to the Free Software
14 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 # Copyright (c) 2005, 2007 XenSource Ltd.
20 # To add new entries to the bugtool, you need to:
22 # Create a new capability. These declare the new entry to the GUI, including
23 # the expected size, time to collect, privacy implications, and whether the
24 # capability should be selected by default. One capability may refer to
25 # multiple files, assuming that they can be reasonably grouped together, and
26 # have the same privacy implications. You need:
28 # A new CAP_ constant.
29 # A cap() invocation to declare the capability.
31 # You then need to add calls to main() to collect the files. These will
32 # typically be calls to the helpers file_output(), tree_output(), cmd_output(),
45 from xml.dom.minidom import parse, getDOMImplementation
47 from subprocess import Popen, PIPE
48 from select import select
49 from signal import SIGTERM, SIGUSR1
58 sys.path.append('/usr/lib/python')
59 sys.path.append('/usr/lib64/python')
61 import xen.lowlevel.xc
64 OS_RELEASE = platform.release()
70 BUG_DIR = "/var/opt/xen/bug-report"
71 PLUGIN_DIR = "/etc/xensource/bugtool"
72 XAPI_BLOBS = '/var/xapi/blobs'
73 EXTLINUX_CONFIG = '/boot/extlinux.conf'
74 GRUB_CONFIG = '/boot/grub/menu.lst'
75 BOOT_KERNEL = '/boot/vmlinuz-' + OS_RELEASE
76 BOOT_INITRD = '/boot/initrd-' + OS_RELEASE + '.img'
77 PROC_PARTITIONS = '/proc/partitions'
79 PROC_MOUNTS = '/proc/mounts'
80 ISCSI_CONF = '/etc/iscsi/iscsid.conf'
81 ISCSI_INITIATOR = '/etc/iscsi/initiatorname.iscsi'
82 LVM_CACHE = '/etc/lvm/cache/.cache'
83 LVM_CONFIG = '/etc/lvm/lvm.conf'
84 PROC_CPUINFO = '/proc/cpuinfo'
85 PROC_MEMINFO = '/proc/meminfo'
86 PROC_IOPORTS = '/proc/ioports'
87 PROC_INTERRUPTS = '/proc/interrupts'
88 PROC_SCSI = '/proc/scsi/scsi'
89 FIRSTBOOT_DIR = '/etc/firstboot.d'
90 PROC_VERSION = '/proc/version'
91 PROC_MODULES = '/proc/modules'
92 PROC_DEVICES = '/proc/devices'
93 PROC_FILESYSTEMS = '/proc/filesystems'
94 PROC_CMDLINE = '/proc/cmdline'
95 PROC_CONFIG = '/proc/config.gz'
96 PROC_USB_DEV = '/proc/bus/usb/devices'
97 PROC_XEN_BALLOON = '/proc/xen/balloon'
98 PROC_NET_BONDING_DIR = '/proc/net/bonding'
99 PROC_NET_VLAN_DIR = '/proc/net/vlan'
100 PROC_NET_SOFTNET_STAT = '/proc/net/softnet_stat'
101 PROC_DRIVER_CCISS_DIR = '/proc/driver/cciss'
102 MODPROBE_CONF = '/etc/modprobe.conf'
103 MODPROBE_DIR = '/etc/modprobe.d'
104 BOOT_TIME_CPUS = '/etc/xensource/boot_time_cpus'
105 BOOT_TIME_MEMORY = '/etc/xensource/boot_time_memory'
106 SYSCONFIG_HWCONF = '/etc/sysconfig/hwconf'
107 SYSCONFIG_NETWORK = '/etc/sysconfig/network'
108 SYSCONFIG_NETWORK_SCRIPTS = '/etc/sysconfig/network-scripts'
109 IFCFG_RE = re.compile(r'^.*/ifcfg-.*')
110 ROUTE_RE = re.compile(r'^.*/route-.*')
111 NETWORK_DBCACHE = '/var/xapi/network.dbcache'
112 RESOLV_CONF = '/etc/resolv.conf'
113 MPP_CONF = '/etc/mpp.conf'
114 MULTIPATH_CONF = '/etc/multipath.conf'
115 NSSWITCH_CONF = '/etc/nsswitch.conf'
116 NTP_CONF = '/etc/ntp.conf'
117 IPTABLES_CONFIG = '/etc/sysconfig/iptables-config'
119 HOSTS_ALLOW = '/etc/hosts.allow'
120 HOSTS_DENY = '/etc/hosts.deny'
121 DHCP_LEASE_DIR = '/var/lib/dhclient'
122 OPENVSWITCH_CORE_DIR = '/var/xen/openvswitch'
123 OPENVSWITCH_CONF = '/etc/ovs-vswitchd.conf'
124 OPENVSWITCH_CONF_DB = '/etc/openvswitch/conf.db'
125 OPENVSWITCH_VSWITCHD_PID = '/var/run/openvswitch/ovs-vswitchd.pid'
126 VAR_LOG_DIR = '/var/log/'
127 VNCTERM_CORE_DIR = '/var/xen/vncterm'
128 XENSOURCE_INVENTORY = '/etc/xensource-inventory'
129 OEM_CONFIG_DIR = '/var/xsconfig'
130 OEM_CONFIG_FILES_RE = re.compile(r'^.*xensource-inventory$')
131 OEM_DB_FILES_RE = re.compile(r'^.*state\.db')
132 INITIAL_INVENTORY = '/opt/xensource/etc/initial-inventory'
133 VENDORKERNEL_INVENTORY = '/etc/vendorkernel-inventory'
134 STATIC_VDIS = '/etc/xensource/static-vdis'
135 POOL_CONF = '/etc/xensource/pool.conf'
136 NETWORK_CONF = '/etc/xensource/network.conf'
137 PTOKEN = '/etc/xensource/ptoken'
138 XAPI_CONF = '/etc/xensource/xapi.conf'
139 XAPI_SSL_CONF = '/etc/xensource/xapi-ssl.conf'
140 DB_CONF = '/etc/xensource/db.conf'
141 DB_CONF_RIO = '/etc/xensource/db.conf.rio'
142 DB_DEFAULT_FIELDS = '/etc/xensource/db-default-fields'
143 DB_SCHEMA_SQL = '/etc/xensource/db_schema.sql'
144 XENSTORED_DB = '/var/lib/xenstored/tdb'
145 HOST_CRASHDUMPS_DIR = '/var/crash'
146 HOST_CRASHDUMP_LOGS_RE = re.compile(r'^.*\.log$')
147 X11_LOGS_DIR = VAR_LOG_DIR
148 X11_LOGS_RE = re.compile(r'.*/Xorg\..*$')
149 X11_AUTH_DIR = '/root/'
150 X11_AUTH_RE = re.compile(r'.*/\.((Xauthority)|(serverauth\.[0-9]*))$')
151 XAPI_DEBUG_DIR = '/var/xapi/debug'
152 LOG_CONF = '/etc/xensource/log.conf'
153 INSTALLED_REPOS_DIR = '/etc/xensource/installed-repos'
154 PATCH_APPLIED_DIR = '/var/patch/applied'
156 [ VAR_LOG_DIR + x for x in
157 ['xensource.log', 'audit.log', 'xenstored-access.log', 'SMlog', 'VMPRlog', 'xen/xenstored-trace.log',
158 'xen/xen-hotplug.log', 'xen/domain-builder-ng.log', 'squeezed.log',
159 'openvswitch/ovs-vswitchd.log', 'openvswitch/ovsdb-server.log' ] +
160 [ f % n for n in range(1, 20) \
161 for f in ['xensource.log.%d', 'xensource.log.%d.gz','SMlog.%d', 'SMlog.%d.gz', 'VMPRlog.%d', 'VMPRlog.%d.gz',
162 'audit.log.%d', 'audit.log.%d.gz', 'xenstored-access.log.%d', 'xenstored-access.log.%d.gz', \
163 'xen/xenstored-access.log.%d', 'xen/xenstored-access.log.%d.gz', 'squeezed.log.%d', \
164 'openvswitch/ovs-vswitchd.log.%d', 'openvswitch/ovs-vswitchd.log.%d.gz', \
165 'openvswitch/ovsdb-server.log.%d', 'openvswitch/ovsdb-server.log.%d.gz']]] \
166 + glob.glob('/tmp/qemu.[0-9]*')
167 OEM_XENSERVER_LOGS_RE = re.compile(r'^.*xensource\.log$')
168 XHA_LOG = '/var/log/xha.log'
169 XHAD_CONF = '/etc/xensource/xhad.conf'
170 YUM_LOG = '/var/log/yum.log'
171 YUM_REPOS_DIR = '/etc/yum.repos.d'
172 PAM_DIR = '/etc/pam.d'
173 FIST_RE = re.compile(r'.*/fist_')
175 [ VAR_LOG_DIR + x for x in
177 [ f % n for n in range(1, 20) \
178 for f in ['v6d.log.%d', 'v6d.log.%d.gz' ]]]
179 LWIDENTITY_JOIN_LOG = '/tmp/lwidentity.join.log'
180 HOSTS_LWIDENTITY_ORIG = '/etc/hosts.lwidentity.orig'
181 KRB5_CONF = '/etc/krb5.conf'
182 LIKEWISE_DIR = '/var/lib/likewise'
183 XENGUEST_LOG = '/tmp/xenguest.log'
190 BIOSDEVNAME = '/sbin/biosdevname'
191 BRCTL = '/usr/sbin/brctl'
193 CHKCONFIG = '/sbin/chkconfig'
194 CSL = '/opt/Citrix/StorageLink/bin/csl'
197 DMIDECODE = '/usr/sbin/dmidecode'
198 DMSETUP = '/sbin/dmsetup'
199 ETHTOOL = '/sbin/ethtool'
200 FDISK = '/sbin/fdisk'
201 FIND = '/usr/bin/find'
202 HA_QUERY_LIVESET = '/opt/xensource/debug/debug_ha_query_liveset'
203 HDPARM = '/sbin/hdparm'
204 IFCONFIG = '/sbin/ifconfig'
205 IPTABLES = '/sbin/iptables'
206 ISCSIADM = '/sbin/iscsiadm'
207 LIST_DOMAINS = '/opt/xensource/bin/list_domains'
208 LOSETUP = '/sbin/losetup'
210 LSPCI = '/sbin/lspci'
211 LVS = '/usr/sbin/lvs'
212 LVDISPLAY = '/usr/sbin/lvdisplay'
213 MD5SUM = '/usr/bin/md5sum'
214 MODINFO = '/sbin/modinfo'
215 MPPUTIL = '/usr/sbin/mppUtil'
216 MULTIPATHD = '/sbin/multipathd'
217 NETSTAT = '/bin/netstat'
218 OVS_DPCTL = '/usr/bin/ovs-dpctl'
219 OVS_OFCTL = '/usr/bin/ovs-ofctl'
220 OVS_VSCTL = '/usr/bin/ovs-vsctl'
221 OVS_APPCTL = '/usr/bin/ovs-appctl'
223 PVS = '/usr/sbin/pvs'
224 ROUTE = '/sbin/route'
226 SG_MAP = '/usr/bin/sg_map'
227 SQLITE = '/usr/bin/sqlite3'
228 BIN_STATIC_VDIS = '/opt/xensource/bin/static-vdis'
229 SYSCTL = '/sbin/sysctl'
231 UPTIME = '/usr/bin/uptime'
232 VGS = '/usr/sbin/vgs'
233 VGSCAN = '/sbin/vgscan'
234 XAPI_DB_PROCESS = '/opt/xensource/bin/xapi-db-process'
235 XE = '/opt/xensource/bin/xe'
236 XS = '/opt/xensource/debug/xs'
237 XENSTORE_LS = '/usr/bin/xenstore-ls'
241 # PII -- Personally identifiable information. Of particular concern are
242 # things that would identify customers, or their network topology.
243 # Passwords are never to be included in any bug report, regardless of any PII
246 # NO -- No PII will be in these entries.
247 # YES -- PII will likely or certainly be in these entries.
248 # MAYBE -- The user may wish to audit these entries for PII.
249 # IF_CUSTOMIZED -- If the files are unmodified, then they will contain no PII,
250 # but since we encourage customers to edit these files, PII may have been
251 # introduced by the customer. This is used in particular for the networking
258 PII_IF_CUSTOMIZED = 'if_customized'
269 MIME_DATA = 'application/data'
270 MIME_TEXT = 'text/plain'
272 INVENTORY_XML_ROOT = "system-status-inventory"
273 INVENTORY_XML_SUMMARY = 'system-summary'
274 INVENTORY_XML_ELEMENT = 'inventory-entry'
275 CAP_XML_ROOT = "system-status-capabilities"
276 CAP_XML_ELEMENT = 'capability'
280 CAP_BOOT_LOADER = 'boot-loader'
282 CAP_DISK_INFO = 'disk-info'
283 CAP_FIRSTBOOT = 'firstboot'
284 CAP_HARDWARE_INFO = 'hardware-info'
285 CAP_HDPARM_T = 'hdparm-t'
286 CAP_HIGH_AVAILABILITY = 'high-availability'
287 CAP_HOST_CRASHDUMP_DUMPS = 'host-crashdump-dumps'
288 CAP_HOST_CRASHDUMP_LOGS = 'host-crashdump-logs'
289 CAP_KERNEL_INFO = 'kernel-info'
290 CAP_LOSETUP_A = 'loopback-devices'
291 CAP_MULTIPATH = 'multipath'
292 CAP_NETWORK_CONFIG = 'network-config'
293 CAP_NETWORK_STATUS = 'network-status'
296 CAP_PROCESS_LIST = 'process-list'
297 CAP_PERSISTENT_STATS = 'persistent-stats'
298 CAP_SYSTEM_LOGS = 'system-logs'
299 CAP_SYSTEM_SERVICES = 'system-services'
300 CAP_TAPDISK_LOGS = 'tapdisk-logs'
301 CAP_VNCTERM = 'vncterm'
304 CAP_X11_AUTH = 'X11-auth'
305 CAP_XAPI_DEBUG = 'xapi-debug'
306 CAP_XAPI_SUBPROCESS = 'xapi-subprocess'
308 CAP_XENSERVER_CONFIG = 'xenserver-config'
309 CAP_XENSERVER_DOMAINS = 'xenserver-domains'
310 CAP_XENSERVER_DATABASES = 'xenserver-databases'
311 CAP_XENSERVER_INSTALL = 'xenserver-install'
312 CAP_XENSERVER_LOGS = 'xenserver-logs'
313 CAP_XEN_INFO = 'xen-info'
314 CAP_XHA_LIVESET = 'xha-liveset'
322 unlimited_data = False
325 def cap(key, pii=PII_MAYBE, min_size=-1, max_size=-1, min_time=-1,
326 max_time=-1, mime=MIME_TEXT, checked=True, hidden=False):
327 if os.getenv('XEN_RT') and max_time > 0:
329 caps[key] = (key, pii, min_size, max_size, min_time, max_time, mime,
334 cap(CAP_BLOBS, PII_NO, max_size=5*MB)
335 cap(CAP_BOOT_LOADER, PII_NO, max_size=3*KB,
337 cap(CAP_CVSM, PII_NO, max_size=3*MB,
339 cap(CAP_DISK_INFO, PII_MAYBE, max_size=50*KB,
341 cap(CAP_FIRSTBOOT, PII_YES, min_size=60*KB, max_size=80*KB)
342 cap(CAP_HARDWARE_INFO, PII_MAYBE, max_size=50*KB,
344 cap(CAP_HDPARM_T, PII_NO, min_size=0, max_size=5*KB,
345 min_time=20, max_time=90, checked=False, hidden=True)
346 cap(CAP_HIGH_AVAILABILITY, PII_MAYBE, max_size=5*MB)
347 cap(CAP_HOST_CRASHDUMP_DUMPS,PII_YES, checked = False)
348 cap(CAP_HOST_CRASHDUMP_LOGS, PII_NO)
349 cap(CAP_KERNEL_INFO, PII_MAYBE, max_size=120*KB,
351 cap(CAP_LOSETUP_A, PII_MAYBE, max_size=KB, max_time=5)
352 cap(CAP_MULTIPATH, PII_MAYBE, max_size=20*KB,
354 cap(CAP_NETWORK_CONFIG, PII_IF_CUSTOMIZED,
355 min_size=0, max_size=40*KB)
356 cap(CAP_NETWORK_STATUS, PII_YES, max_size=19*KB,
358 cap(CAP_PAM, PII_NO, max_size=50*KB)
359 cap(CAP_PERSISTENT_STATS, PII_MAYBE, max_size=50*MB,
361 cap(CAP_PROCESS_LIST, PII_YES, max_size=30*KB,
363 cap(CAP_SYSTEM_LOGS, PII_MAYBE, max_size=50*MB,
365 cap(CAP_SYSTEM_SERVICES, PII_NO, max_size=5*KB,
367 cap(CAP_TAPDISK_LOGS, PII_NO, max_size=64*KB)
368 cap(CAP_VNCTERM, PII_MAYBE, checked = False)
369 cap(CAP_WLB, PII_NO, max_size=3*MB,
371 cap(CAP_X11_LOGS, PII_NO, max_size=100*KB)
372 cap(CAP_X11_AUTH, PII_NO, max_size=100*KB)
373 cap(CAP_XAPI_DEBUG, PII_MAYBE, max_size=10*MB)
374 cap(CAP_XAPI_SUBPROCESS, PII_NO, max_size=5*KB,
376 cap(CAP_XENRT, PII_NO, min_size=0, max_size=500*MB,
377 checked=False, hidden=True)
378 cap(CAP_XENSERVER_CONFIG, PII_MAYBE, max_size=80*KB,
380 cap(CAP_XENSERVER_DOMAINS, PII_NO, max_size=1*KB,
382 cap(CAP_XENSERVER_DATABASES, PII_YES, min_size=500*KB,max_size=2*MB,
384 cap(CAP_XENSERVER_INSTALL, PII_MAYBE, min_size=10*KB, max_size=300*KB)
385 cap(CAP_XENSERVER_LOGS, PII_MAYBE, min_size=0, max_size=70*MB)
386 cap(CAP_XEN_INFO, PII_MAYBE, max_size=20*KB,
388 cap(CAP_XHA_LIVESET, PII_MAYBE, max_size=10*KB,
390 cap(CAP_YUM, PII_IF_CUSTOMIZED, max_size=10*KB,
393 ANSWER_YES_TO_ALL = False
397 dev_null = open('/dev/null', 'r+')
405 output("[%s] %s" % (time.strftime("%x %X %Z"), x))
407 def cmd_output(cap, args, label = None, filter = None):
410 if isinstance(args, list):
411 a = [aa for aa in args]
412 a[0] = os.path.basename(a[0])
416 data[label] = {'cap': cap, 'cmd_args': args, 'filter': filter}
418 def file_output(cap, path_list):
421 if os.path.exists(p):
422 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
423 cap_sizes[cap] < caps[cap][MAX_SIZE]:
424 data[p] = {'cap': cap, 'filename': p}
427 cap_sizes[cap] += s.st_size
431 output("Omitting %s, size constraint of %s exceeded" % (p, cap))
433 def tree_output(cap, path, pattern = None, negate = False):
435 if os.path.exists(path):
436 for f in os.listdir(path):
437 fn = os.path.join(path, f)
438 if os.path.isfile(fn) and matches(fn, pattern, negate):
439 file_output(cap, [fn])
440 elif os.path.isdir(fn):
441 tree_output(cap, fn, pattern, negate)
443 def func_output(cap, label, func):
445 t = str(func).split()
446 data[label] = {'cap': cap, 'func': func}
451 for (k, v) in data.items():
453 if v.has_key('cmd_args'):
454 v['output'] = StringIOmtime()
455 if not process_lists.has_key(cap):
456 process_lists[cap] = []
457 process_lists[cap].append(ProcOutput(v['cmd_args'], caps[cap][MAX_TIME], v['output'], v['filter']))
458 elif v.has_key('filename') and v['filename'].startswith('/proc/'):
459 # proc files must be read into memory
461 f = open(v['filename'], 'r')
464 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
465 cap_sizes[cap] < caps[cap][MAX_SIZE]:
466 v['output'] = StringIOmtime(s)
467 cap_sizes[cap] += len(s)
469 output("Omitting %s, size constraint of %s exceeded" % (v['filename'], cap))
472 elif v.has_key('func'):
477 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
478 cap_sizes[cap] < caps[cap][MAX_SIZE]:
479 v['output'] = StringIOmtime(s)
480 cap_sizes[cap] += len(s)
482 output("Omitting %s, size constraint of %s exceeded" % (k, cap))
484 run_procs(process_lists.values())
487 def main(argv = None):
488 global ANSWER_YES_TO_ALL, SILENT_MODE
489 global entries, data, dbg
491 # we need access to privileged files, exit if we are not running as root
493 print >>sys.stderr, "Error: xen-bugtool must be run as root"
496 output_type = 'tar.bz2'
503 (options, params) = getopt.gnu_getopt(
504 argv, 'sy', ['capabilities', 'silent', 'yestoall', 'entries=',
505 'output=', 'outfd=', 'all', 'unlimited', 'debug'])
506 except getopt.GetoptError, opterr:
507 print >>sys.stderr, opterr
515 inventory = readKeyValueFile(XENSOURCE_INVENTORY)
516 if inventory.has_key('OEM_BUILD_NUMBER'):
517 cap(CAP_OEM, PII_MAYBE, max_size=5*MB,
520 if os.getenv('XEN_RT'):
521 entries = [CAP_BLOBS, CAP_BOOT_LOADER, CAP_CVSM, CAP_DISK_INFO, CAP_FIRSTBOOT, CAP_HARDWARE_INFO,
522 CAP_HOST_CRASHDUMP_DUMPS, CAP_HOST_CRASHDUMP_LOGS, CAP_KERNEL_INFO, CAP_LOSETUP_A,
523 CAP_NETWORK_CONFIG, CAP_NETWORK_STATUS, CAP_PROCESS_LIST, CAP_HIGH_AVAILABILITY,
524 CAP_PAM, CAP_PERSISTENT_STATS, CAP_MULTIPATH,
525 CAP_SYSTEM_LOGS, CAP_SYSTEM_SERVICES, CAP_TAPDISK_LOGS,
526 CAP_VNCTERM, CAP_WLB, CAP_X11_LOGS, CAP_X11_AUTH, CAP_XAPI_DEBUG, CAP_XAPI_SUBPROCESS,
527 CAP_XENRT, CAP_XENSERVER_CONFIG, CAP_XENSERVER_DOMAINS, CAP_XENSERVER_DATABASES,
528 CAP_XENSERVER_INSTALL, CAP_XENSERVER_LOGS, CAP_XEN_INFO, CAP_XHA_LIVESET, CAP_YUM]
530 entries = [e for e in caps.keys() if caps[e][CHECKED]]
532 for (k, v) in options:
533 if k == '--capabilities':
534 update_capabilities()
539 if v in ['tar', 'tar.bz2', 'zip']:
542 print >>sys.stderr, "Invalid output format '%s'" % v
545 # "-s" or "--silent" means suppress output (except for the final
546 # output filename at the end)
547 if k in ['-s', '--silent']:
550 if k == '--entries' and v != '':
551 entries = v.split(',')
553 # If the user runs the script with "-y" or "--yestoall" we don't ask
554 # all the really annoying questions.
555 if k in ['-y', '--yestoall']:
556 ANSWER_YES_TO_ALL = True
561 old = fcntl.fcntl(output_fd, fcntl.F_GETFD)
562 fcntl.fcntl(output_fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
564 print >>sys.stderr, "Invalid output file descriptor", output_fd
568 entries = caps.keys()
569 elif k == '--unlimited':
570 unlimited_data = True
573 ProcOutput.debug = True
576 print >>sys.stderr, "Invalid additional arguments", str(params)
579 if output_fd != -1 and output_type != 'tar':
580 print >>sys.stderr, "Option '--outfd' only valid with '--output=tar'"
583 if ANSWER_YES_TO_ALL:
584 output("Warning: '--yestoall' argument provided, will not prompt for individual files.")
587 This application will collate the Xen dmesg output, details of the
588 hardware configuration of your machine, information about the build of
589 Xen that you are using, plus, if you allow it, various logs.
591 The collated information will be saved as a .%s for archiving or
592 sending to a Technical Support Representative.
594 The logs may contain private information, and if you are at all
595 worried about that, you should exit now, or you should explicitly
596 exclude those logs from the archive.
600 # assemble potential data
601 tree_output(CAP_BLOBS, XAPI_BLOBS)
603 file_output(CAP_BOOT_LOADER, [GRUB_CONFIG, EXTLINUX_CONFIG])
604 cmd_output(CAP_BOOT_LOADER, [LS, '-lR', '/boot'])
605 cmd_output(CAP_BOOT_LOADER, [MD5SUM, BOOT_KERNEL, BOOT_INITRD], label='vmlinuz-initrd.md5sum')
607 func_output(CAP_CVSM, 'csl_logs', csl_logs)
609 cmd_output(CAP_DISK_INFO, [FDISK, '-l'])
610 file_output(CAP_DISK_INFO, [PROC_PARTITIONS, PROC_MOUNTS])
611 file_output(CAP_DISK_INFO, [FSTAB, ISCSI_CONF, ISCSI_INITIATOR])
612 cmd_output(CAP_DISK_INFO, [DF, '-alT'])
613 cmd_output(CAP_DISK_INFO, [DF, '-alTi'])
614 for d in disk_list():
615 cmd_output(CAP_DISK_INFO, [HDPARM, '-I', '/dev/%s' % d])
616 if len(pidof('iscsid')) != 0:
617 cmd_output(CAP_DISK_INFO, [ISCSIADM, '-m', 'node'])
618 cmd_output(CAP_DISK_INFO, [VGSCAN])
619 cmd_output(CAP_DISK_INFO, [PVS])
620 cmd_output(CAP_DISK_INFO, [VGS])
621 cmd_output(CAP_DISK_INFO, [LVS])
622 file_output(CAP_DISK_INFO, [LVM_CACHE, LVM_CONFIG])
623 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_host'])
624 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_disk'])
625 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/fc_transport'])
626 cmd_output(CAP_DISK_INFO, [SG_MAP, '-x'])
627 func_output(CAP_DISK_INFO, 'scsi-hosts', dump_scsi_hosts)
628 tree_output(CAP_DISK_INFO, PROC_DRIVER_CCISS_DIR)
629 cmd_output(CAP_DISK_INFO, [LVDISPLAY, '--map'])
631 tree_output(CAP_FIRSTBOOT, FIRSTBOOT_DIR)
633 file_output(CAP_HARDWARE_INFO, [PROC_CPUINFO, PROC_MEMINFO, PROC_IOPORTS, PROC_INTERRUPTS])
634 cmd_output(CAP_HARDWARE_INFO, [DMIDECODE])
635 cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-n'])
636 cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-vv'])
637 file_output(CAP_HARDWARE_INFO, [PROC_USB_DEV, PROC_SCSI])
638 file_output(CAP_HARDWARE_INFO, [BOOT_TIME_CPUS, BOOT_TIME_MEMORY])
639 file_output(CAP_HARDWARE_INFO, [SYSCONFIG_HWCONF])
640 cmd_output(CAP_HARDWARE_INFO, [LS, '-lR', '/dev'])
643 for d in disk_list():
644 cmd_output(CAP_HDPARM_T, [HDPARM, '-tT', '/dev/%s' % d])
646 file_output(CAP_HIGH_AVAILABILITY, [XHAD_CONF, XHA_LOG])
648 tree_output(CAP_HOST_CRASHDUMP_DUMPS, HOST_CRASHDUMPS_DIR,
649 HOST_CRASHDUMP_LOGS_RE, True)
650 tree_output(CAP_HOST_CRASHDUMP_LOGS, HOST_CRASHDUMPS_DIR,
651 HOST_CRASHDUMP_LOGS_RE, False)
653 file_output(CAP_KERNEL_INFO, [PROC_VERSION, PROC_MODULES, PROC_DEVICES,
654 PROC_FILESYSTEMS, PROC_CMDLINE])
655 cmd_output(CAP_KERNEL_INFO, [ZCAT, PROC_CONFIG], label='config')
656 cmd_output(CAP_KERNEL_INFO, [SYSCTL, '-A'])
657 file_output(CAP_KERNEL_INFO, [MODPROBE_CONF])
658 tree_output(CAP_KERNEL_INFO, MODPROBE_DIR)
659 func_output(CAP_KERNEL_INFO, 'modinfo', module_info)
661 cmd_output(CAP_LOSETUP_A, [LOSETUP, '-a'])
663 file_output(CAP_MULTIPATH, [MULTIPATH_CONF, MPP_CONF])
664 cmd_output(CAP_MULTIPATH, [DMSETUP, 'table'])
665 func_output(CAP_MULTIPATH, 'multipathd_topology', multipathd_topology)
666 cmd_output(CAP_MULTIPATH, [MPPUTIL, '-a'])
667 if CAP_MULTIPATH in entries:
668 dump_rdac_groups(CAP_MULTIPATH)
670 file_output(CAP_NETWORK_CONFIG, [NETWORK_CONF])
671 file_output(CAP_NETWORK_CONFIG, [NETWORK_DBCACHE])
672 tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, IFCFG_RE)
673 tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, ROUTE_RE)
674 file_output(CAP_NETWORK_CONFIG, [SYSCONFIG_NETWORK, RESOLV_CONF, NSSWITCH_CONF, HOSTS])
675 file_output(CAP_NETWORK_CONFIG, [NTP_CONF, IPTABLES_CONFIG, HOSTS_ALLOW, HOSTS_DENY])
676 file_output(CAP_NETWORK_CONFIG, [OPENVSWITCH_CONF, OPENVSWITCH_CONF_DB])
678 cmd_output(CAP_NETWORK_STATUS, [IFCONFIG, '-a'])
679 cmd_output(CAP_NETWORK_STATUS, [ROUTE, '-n'])
680 cmd_output(CAP_NETWORK_STATUS, [ARP, '-n'])
681 cmd_output(CAP_NETWORK_STATUS, [NETSTAT, '-an'])
682 tree_output(CAP_NETWORK_STATUS, DHCP_LEASE_DIR)
683 cmd_output(CAP_NETWORK_STATUS, [IPTABLES, '-nL'])
684 cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'show'])
685 cmd_output(CAP_NETWORK_STATUS, [BIOSDEVNAME, '-d'])
686 for p in os.listdir('/sys/class/net/'):
687 if os.path.isdir('/sys/class/net/%s/bridge' % p):
688 cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'showmacs', p])
691 f = open('/sys/class/net/%s/type' % p, 'r')
696 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, p])
697 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-S', p])
698 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-k', p])
699 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-i', p])
700 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-c', p])
701 cmd_output(CAP_NETWORK_STATUS,
702 [TC, '-s', '-d', 'class', 'show', 'dev', p])
705 tree_output(CAP_NETWORK_STATUS, PROC_NET_BONDING_DIR)
706 tree_output(CAP_NETWORK_STATUS, PROC_NET_VLAN_DIR)
707 cmd_output(CAP_NETWORK_STATUS, [TC, '-s', 'qdisc'])
708 file_output(CAP_NETWORK_STATUS, [PROC_NET_SOFTNET_STAT])
709 tree_output(CAP_NETWORK_STATUS, OPENVSWITCH_CORE_DIR)
710 if os.path.exists(OPENVSWITCH_VSWITCHD_PID):
711 cmd_output(CAP_NETWORK_STATUS, [OVS_DPCTL, 'show'])
713 cmd_output(CAP_NETWORK_STATUS, [OVS_OFCTL, 'show', d])
714 cmd_output(CAP_NETWORK_STATUS, [OVS_OFCTL, 'status', d])
715 cmd_output(CAP_NETWORK_STATUS, [OVS_OFCTL, 'dump-flows', d])
716 cmd_output(CAP_NETWORK_STATUS, [OVS_DPCTL, 'dump-flows', d])
718 vspidfile = open(OPENVSWITCH_VSWITCHD_PID)
719 vspid = int(vspidfile.readline().strip())
721 for b in bond_list(vspid):
722 cmd_output(CAP_NETWORK_STATUS,
723 [OVS_APPCTL, '-t', '/var/run/ovs-vswitchd.%s.ctl' % vspid, '-e' 'bond/show %s' % b],
724 'ovs-appctl-bond-show-%s.out' % b)
728 tree_output(CAP_PAM, PAM_DIR)
729 file_output(CAP_PAM, [KRB5_CONF])
730 tree_output(CAP_PAM, LIKEWISE_DIR)
732 func_output(CAP_PERSISTENT_STATS, 'xapi_rrd-host', dump_xapi_rrds)
734 cmd_output(CAP_PROCESS_LIST, [PS, 'wwwaxf', '-eo', 'pid,tty,stat,time,nice,psr,pcpu,pmem,nwchan,wchan:25,args'], label='process-tree')
735 func_output(CAP_PROCESS_LIST, 'fd_usage', fd_usage)
737 file_output(CAP_SYSTEM_LOGS,
738 [ VAR_LOG_DIR + x for x in
739 [ 'crit.log', 'kern.log', 'daemon.log', 'user.log', 'syslog', 'messages',
740 'monitor_memory.log', 'secure', 'debug', 'dmesg', 'boot.msg', 'blktap.log' ] +
741 [ f % n for n in range(1, 20) \
742 for f in ['crit.log.%d', 'crit.log.%d.gz',
743 'kern.log.%d', 'kern.log.%d.gz',
744 'daemon.log.%d', 'daemon.log.%d.gz',
745 'user.log.%d', 'user.log.%d.gz',
746 'messages.%d', 'messages.%d.gz',
747 'monitor_memory.log.%d', 'monitor_memory.log.%d.gz',
748 'secure.%d', 'secure.%d.gz',
750 if not os.path.exists('/var/log/dmesg') and not os.path.exists('/var/log/boot.msg'):
751 cmd_output(CAP_SYSTEM_LOGS, [DMESG])
752 file_output(CAP_SYSTEM_LOGS, [LWIDENTITY_JOIN_LOG, HOSTS_LWIDENTITY_ORIG])
754 cmd_output(CAP_SYSTEM_SERVICES, [CHKCONFIG, '--list'])
756 if CAP_TAPDISK_LOGS in entries:
757 generate_tapdisk_logs()
759 tree_output(CAP_VNCTERM, VNCTERM_CORE_DIR)
761 cmd_output(CAP_WLB, [XE, 'pool-retrieve-wlb-configuration'])
762 cmd_output(CAP_WLB, [XE, 'pool-retrieve-wlb-diagnostics'])
764 tree_output(CAP_X11_LOGS, X11_LOGS_DIR, X11_LOGS_RE)
765 tree_output(CAP_X11_AUTH, X11_AUTH_DIR, X11_AUTH_RE)
767 tree_output(CAP_XAPI_DEBUG, XAPI_DEBUG_DIR)
769 func_output(CAP_XAPI_SUBPROCESS, 'xapi_subprocesses', dump_xapi_subprocess_info)
771 tree_output(CAP_XENRT, '/tmp', FIST_RE)
772 # CA-45540: capture QEMU core files
773 tree_output(CAP_XENRT, '/var/xen/qemu')
774 tree_output(CAP_XENRT, '/tmp', re.compile(r'^.*xen\.qemu-dm\.'))
776 file_output(CAP_XENSERVER_CONFIG, [INITIAL_INVENTORY])
777 file_output(CAP_XENSERVER_CONFIG, [POOL_CONF, PTOKEN, XAPI_CONF, XAPI_SSL_CONF,
778 XENSOURCE_INVENTORY, VENDORKERNEL_INVENTORY])
779 cmd_output(CAP_XENSERVER_CONFIG, [LS, '-lR', '/opt/xensource'])
780 cmd_output(CAP_XENSERVER_CONFIG, [BIN_STATIC_VDIS, 'list'])
781 tree_output(CAP_XENSERVER_CONFIG, OEM_CONFIG_DIR, OEM_CONFIG_FILES_RE)
782 tree_output(CAP_XENSERVER_CONFIG, STATIC_VDIS)
783 cmd_output(CAP_XENSERVER_CONFIG, [LS, '-lR', STATIC_VDIS])
785 func_output(CAP_XENSERVER_DATABASES, 'xapi-db.xml', dump_filtered_xapi_db)
786 cmd_output(CAP_XENSERVER_DATABASES, [XENSTORE_LS, '-f'])
787 file_output(CAP_XENSERVER_DATABASES, [DB_CONF, DB_CONF_RIO, DB_DEFAULT_FIELDS, DB_SCHEMA_SQL])
788 tree_output(CAP_XENSERVER_DATABASES, OEM_CONFIG_DIR, OEM_DB_FILES_RE)
789 file_output(CAP_XENSERVER_DATABASES, [XENSTORED_DB, XENSTORED_DB + '.bak'])
790 cmd_output(CAP_XENSERVER_DATABASES, [XE, 'pool-dump-database', 'file-name='],
791 label="xapi-db-dumped.xml", filter=filter_db_pii)
792 cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'watches'])
793 cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'quotas'])
795 cmd_output(CAP_XENSERVER_DOMAINS, [LIST_DOMAINS])
797 tree_output(CAP_XENSERVER_INSTALL, VAR_LOG_DIR + 'installer')
798 file_output(CAP_XENSERVER_INSTALL,
799 [ VAR_LOG_DIR + x for x in
800 [ 'firstboot-SR-commands-log',
801 'upgrade-commands-log', 'generate-iscsi-iqn-log']] +
802 [ '/root/' + x for x in
803 [ 'blockdevs-log', 'cmdline-log', 'devcontents-log',
804 'dmesg-log', 'install-log', 'lspci-log', 'modules-log',
805 'pci-log', 'processes-log', 'tty-log', 'uname-log',
807 tree_output(CAP_XENSERVER_INSTALL, INSTALLED_REPOS_DIR)
808 tree_output(CAP_XENSERVER_INSTALL, PATCH_APPLIED_DIR)
810 file_output(CAP_XENSERVER_LOGS, [LOG_CONF, XENGUEST_LOG])
811 file_output(CAP_XENSERVER_LOGS, XENSERVER_LOGS)
812 file_output(CAP_XENSERVER_LOGS, LICENSE_LOGS)
813 tree_output(CAP_XENSERVER_LOGS, OEM_CONFIG_DIR, OEM_XENSERVER_LOGS_RE)
817 data = xc.readconsolering()
818 xc.send_debug_keys('q')
822 xc = xen.lowlevel.xc.xc()
824 func_output(CAP_XEN_INFO, 'xen-dmesg', lambda x: xen_dmesg(xc))
825 func_output(CAP_XEN_INFO, 'physinfo', lambda x: prettyDict(xc.physinfo()))
826 func_output(CAP_XEN_INFO, 'xeninfo', lambda x: prettyDict(xc.xeninfo()))
829 file_output(CAP_XEN_INFO, [PROC_XEN_BALLOON])
831 cmd_output(CAP_XHA_LIVESET, [HA_QUERY_LIVESET])
833 file_output(CAP_YUM, [YUM_LOG])
834 tree_output(CAP_YUM, YUM_REPOS_DIR)
835 cmd_output(CAP_YUM, [RPM, '-qa'])
842 # permit the user to filter out data
843 for k in sorted(data.keys()):
844 if not ANSWER_YES_TO_ALL and not yes("Include '%s'? [Y/n]: " % k):
847 # collect selected data now
848 output_ts('Running commands to collect data')
851 subdir = os.getenv('XENRT_BUGTOOL_BASENAME')
853 subdir = os.path.basename(subdir)
854 if subdir == '..' or subdir == '.':
857 subdir = "bug-report-%s" % time.strftime("%Y%m%d%H%M%S")
860 data['inventory.xml'] = {'cap': None, 'output': StringIOmtime(make_inventory(data, subdir))}
863 if output_fd == -1 and not os.path.exists(BUG_DIR):
870 output_ts('Creating output file')
872 if output_type.startswith('tar'):
873 make_tar(subdir, output_type, output_fd)
880 print >>sys.stderr, "Category sizes (max, actual):\n"
881 for c in caps.keys():
882 print >>sys.stderr, " %s (%d, %d)" % (c, caps[c][MAX_SIZE],
886 def find_tapdisk_logs():
887 return glob.glob('/var/log/blktap/*.log*')
889 def generate_tapdisk_logs():
890 for pid in pidof('tapdisk'):
892 os.kill(pid, SIGUSR1)
893 output_ts("Including logs for tapdisk process %d" % pid)
896 # give processes a second to write their logs
898 file_output(CAP_TAPDISK_LOGS, find_tapdisk_logs())
900 def clean_tapdisk_logs():
901 for filename in find_tapdisk_logs():
907 def dump_xapi_subprocess_info(cap):
908 """Check which fds are open by xapi and its subprocesses to diagnose faults like CA-10543.
909 Returns a string containing a pretty-printed pstree-like structure. """
910 pids = filter(lambda x: x.isdigit(), os.listdir("/proc"))
911 def readlines(filename):
914 f = open(filename, "r")
915 lines = f.readlines()
921 all = readlines("/proc/" + pid + "/cmdline")
925 return all[0].replace('\x00', ' ')
927 for i in readlines("/proc/" + pid + "/status"):
928 if i.startswith("PPid:"):
932 result = { "cmdline": cmdline(pid) }
933 child_pids = filter(lambda x:parent(x) == pid, pids)
935 for child in child_pids:
936 children[child] = pstree(child)
937 result['children'] = children
939 for fd in os.listdir("/proc/" + pid + "/fd"):
941 fds[fd] = os.readlink("/proc/" + pid + "/fd/" + fd)
946 xapis = filter(lambda x: cmdline(x).startswith("/opt/xensource/bin/xapi"), pids)
947 xapis = filter(lambda x: parent(x) == "1", xapis)
950 result[xapi] = pstree(xapi)
951 pp = pprint.PrettyPrinter(indent=4)
952 return pp.pformat(result)
954 def dump_xapi_rrds(cap):
955 socket.setdefaulttimeout(5)
956 session = XenAPI.xapi_local()
957 session.xenapi.login_with_password('', '')
958 this_host = session.xenapi.session.get_this_host(session._session)
959 # better way to find pool master?
960 pool = session.xenapi.pool.get_all_records().values()[0]
961 i_am_master = (this_host == pool['master'])
963 for vm in session.xenapi.VM.get_all_records().values():
964 if vm['is_a_template']:
966 if vm['resident_on'] == this_host or (i_am_master and vm['power_state'] in ['Suspended', 'Halted']):
967 rrd = urllib.urlopen('http://localhost/vm_rrd?session_id=%s&uuid=%s' % (session._session, vm['uuid']))
969 (i, o, x) = select([rrd], [], [], 5.0)
971 data['xapi_rrd-%s' % vm['uuid']] = {'cap': cap,
972 'output': StringIOmtime(rrd.read())}
977 rrd = urllib.urlopen('http://localhost/host_rrd?session_id=%s' % session._session)
984 session.xenapi.session.logout()
987 '''Filter a Xapi XML database.
989 There is one important assumption made in this class:
990 - the XML document does not contain any characters between the end of one
991 tag and the beginning of the next, ie every > is immediately followed by
1000 def filter_secrets(self, s):
1001 if 'in_secret_table' not in self.state:
1002 self.state['in_secret_table'] = False
1004 # this logic doesn't deal with <table name="secret" /> properly!!!
1005 if s.startswith('<table ') and 'name="secret"' in s:
1006 self.state['in_secret_table'] = True
1007 elif s.startswith('</table>'):
1008 self.state['in_secret_table'] = False
1010 if self.state['in_secret_table'] and s.startswith("<row"): # match only on DB rows
1011 s = re.sub(r'(value=")[^"]+(")', r'\1REMOVED\2', s)
1020 self.result += self.filter_secrets(s)
1025 r = self.result + self.filter_secrets(self.rest)
1026 self.result, self.rest = '', ''
1030 def filter_db_pii(s, state):
1031 dbfilter = DBFilter()
1033 return dbfilter.output()
1035 def dump_filtered_xapi_db(cap):
1040 # determine db format
1041 c = open(DB_CONF, 'r')
1044 l = line.rstrip('\n')
1045 if l.startswith('['):
1047 if l.startswith('format:'):
1057 if format == 'sqlite':
1058 pipe = Popen([XAPI_DB_PROCESS, '-xmltostdout'], bufsize=1, stdin=dev_null,
1059 stdout=PIPE, stderr=dev_null)
1062 ih = open(db_file, 'r')
1067 dbfilter = DBFilter()
1072 output = dbfilter.output()
1080 def dump_scsi_hosts(cap):
1082 l = os.listdir('/sys/class/scsi_host')
1088 f = open('/sys/class/scsi_host/%s/proc_name' % h)
1089 procname = f.readline().strip("\n")
1095 f = open('/sys/class/scsi_host/%s/model_name' % h)
1096 modelname = f.readline().strip("\n")
1101 output += "%s:\n" %h
1102 output += " %s%s\n" % (procname, modelname and (" -> %s" % modelname) or '')
1106 def module_info(cap):
1107 output = StringIO.StringIO()
1108 modules = open(PROC_MODULES, 'r')
1111 for line in modules:
1112 module = line.split()[0]
1113 procs.append(ProcOutput([MODINFO, module], caps[cap][MAX_TIME], output))
1118 return output.getvalue()
1121 socket.setdefaulttimeout(5)
1122 session = XenAPI.xapi_local()
1123 session.xenapi.login_with_password('', '')
1124 this_host = session.xenapi.session.get_this_host(session._session)
1125 # better way to find pool master?
1126 pool = session.xenapi.pool.get_all_records().values()[0]
1127 i_am_master = (this_host == pool['master'])
1129 output = StringIO.StringIO()
1131 csl_targets_fetched = []
1133 for pbd in session.xenapi.PBD.get_all_records().values():
1134 if pbd.has_key('device_config') and pbd['device_config'].has_key('target'):
1135 if pbd['device_config']['target'] in csl_targets_fetched:
1137 sr = session.xenapi.SR.get_record(pbd['SR'])
1138 if sr.has_key('type') and sr['type'] == 'cslg':
1139 if sr['shared'] and pbd['host'] != this_host and not i_am_master:
1142 dev_cfg = pbd['device_config']
1143 server = "server=%s" % socket.gethostbyname(dev_cfg['target'])
1144 if dev_cfg.has_key('port'):
1145 server += ':' + dev_cfg['port']
1146 if dev_cfg.has_key('username'):
1147 server += ',' + dev_cfg['username']
1148 if dev_cfg.has_key('password_secret'):
1149 sec_ref = session.xenapi.secret.get_by_uuid(dev_cfg['password_secret'])
1150 server += ',' + session.xenapi.secret.get_value(sec_ref)
1151 procs.append(ProcOutput([CSL, server, 'srv-log-get'], caps[cap][MAX_TIME], output))
1152 csl_targets_fetched.append(dev_cfg['target'])
1154 session.xenapi.session.logout()
1158 return output.getvalue()
1160 def multipathd_topology(cap):
1161 pipe = Popen([MULTIPATHD, '-k'], bufsize=1, stdin=PIPE,
1162 stdout=PIPE, stderr=dev_null)
1163 stdout, stderr = pipe.communicate('show topology')
1168 output = StringIO.StringIO()
1169 procs = [ProcOutput([OVS_DPCTL, 'dump-dps'], caps[CAP_NETWORK_STATUS][MAX_TIME], output)]
1173 if not procs[0].timed_out:
1174 return output.getvalue().splitlines()
1178 output = StringIO.StringIO()
1179 procs = [ProcOutput([OVS_APPCTL, '-t', '/var/run/ovs-vswitchd.%s.ctl' % pid, '-e' 'bond/list'], caps[CAP_NETWORK_STATUS][MAX_TIME], output)]
1183 if not procs[0].timed_out:
1184 bonds = output.getvalue().splitlines()[1:]
1185 return [x.split('\t')[1] for x in bonds]
1191 for d in [p for p in os.listdir('/proc') if p.isdigit()]:
1193 fh = open('/proc/'+d+'/cmdline')
1194 name = fh.readline()
1195 num_fds = len(os.listdir(os.path.join('/proc/'+d+'/fd')))
1197 if not num_fds in fd_dict:
1198 fd_dict[num_fds] = []
1199 fd_dict[num_fds].append(name.replace('\0', ' ').strip())
1202 keys = fd_dict.keys()
1203 keys.sort(lambda a, b: int(b) - int(a))
1205 output += "%s: %s\n" % (k, str(fd_dict[k]))
1208 def dump_rdac_groups(cap):
1209 output = StringIO.StringIO()
1210 procs = [ProcOutput([MPPUTIL, '-a'], caps[cap][MAX_TIME], output)]
1214 if not procs[0].timed_out:
1216 for line in output.getvalue().splitlines():
1217 if line.startswith('ID'):
1219 elif line.startswith('----'):
1222 group, _ = line.split(None, 1)
1223 cmd_output(cap, [MPPUTIL, '-g', group])
1225 def load_plugins(just_capabilities = False):
1226 def getText(nodelist):
1228 for node in nodelist:
1229 if node.nodeType == node.TEXT_NODE:
1233 def getBoolAttr(el, attr, default = False):
1235 val = el.getAttribute(attr).lower()
1236 if val in ['true', 'false', 'yes', 'no']:
1237 ret = val in ['true', 'yes']
1240 for dir in [d for d in os.listdir(PLUGIN_DIR) if os.path.isdir(os.path.join(PLUGIN_DIR, d))]:
1241 if not caps.has_key(dir):
1242 if not os.path.exists("%s/%s.xml" % (PLUGIN_DIR, dir)):
1244 xmldoc = parse("%s/%s.xml" % (PLUGIN_DIR, dir))
1245 assert xmldoc.documentElement.tagName == "capability"
1247 pii, min_size, max_size, min_time, max_time, mime = \
1248 PII_MAYBE, -1,-1,-1,-1, MIME_TEXT
1250 if xmldoc.documentElement.getAttribute("pii") in [PII_NO, PII_YES, PII_MAYBE, PII_IF_CUSTOMIZED]:
1251 pii = xmldoc.documentElement.getAttribute("pii")
1252 if xmldoc.documentElement.getAttribute("min_size") != '':
1253 min_size = long(xmldoc.documentElement.getAttribute("min_size"))
1254 if xmldoc.documentElement.getAttribute("max_size") != '':
1255 max_size = long(xmldoc.documentElement.getAttribute("max_size"))
1256 if xmldoc.documentElement.getAttribute("min_time") != '':
1257 min_time = int(xmldoc.documentElement.getAttribute("min_time"))
1258 if xmldoc.documentElement.getAttribute("max_time") != '':
1259 max_time = int(xmldoc.documentElement.getAttribute("max_time"))
1260 if xmldoc.documentElement.getAttribute("mime") in [MIME_DATA, MIME_TEXT]:
1261 mime = xmldoc.documentElement.getAttribute("mime")
1262 checked = getBoolAttr(xmldoc.documentElement, 'checked', True)
1263 hidden = getBoolAttr(xmldoc.documentElement, 'hidden', False)
1265 cap(dir, pii, min_size, max_size, min_time, max_time, mime, checked, hidden)
1267 if just_capabilities:
1270 plugdir = os.path.join(PLUGIN_DIR, dir)
1271 for file in [f for f in os.listdir(plugdir) if f.endswith('.xml')]:
1272 xmldoc = parse(os.path.join(plugdir, file))
1273 assert xmldoc.documentElement.tagName == "collect"
1275 for el in xmldoc.documentElement.getElementsByTagName("*"):
1276 if el.tagName == "files":
1277 file_output(dir, getText(el.childNodes).split())
1278 elif el.tagName == "directory":
1279 pattern = el.getAttribute("pattern")
1280 if pattern == '': pattern = None
1281 negate = getBoolAttr(el, 'negate')
1282 tree_output(dir, getText(el.childNodes), pattern and re.compile(pattern) or None, negate)
1283 elif el.tagName == "command":
1284 label = el.getAttribute("label")
1285 if label == '': label = None
1286 cmd_output(dir, getText(el.childNodes), label)
1288 def make_tar(subdir, suffix, output_fd):
1289 global SILENT_MODE, data
1292 if suffix == 'tar.bz2':
1294 filename = "%s/%s.%s" % (BUG_DIR, subdir, suffix)
1297 tf = tarfile.open(filename, mode)
1299 tf = tarfile.open(None, 'w', os.fdopen(output_fd, 'a'))
1302 for (k, v) in data.items():
1304 tar_filename = os.path.join(subdir, construct_filename(k, v))
1305 ti = tarfile.TarInfo(tar_filename)
1310 if v.has_key('output'):
1311 ti.mtime = v['output'].mtime
1312 ti.size = len(v['output'].getvalue())
1314 tf.addfile(ti, v['output'])
1315 elif v.has_key('filename'):
1316 s = os.stat(v['filename'])
1317 ti.mtime = s.st_mtime
1319 tf.addfile(ti, file(v['filename']))
1326 output ('Writing tarball %s successful.' % filename)
1331 def make_zip(subdir):
1332 global SILENT_MODE, data
1334 filename = "%s/%s.zip" % (BUG_DIR, subdir)
1335 zf = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED)
1338 for (k, v) in data.items():
1340 dest = os.path.join(subdir, construct_filename(k, v))
1342 if v.has_key('output'):
1343 zf.writestr(dest, v['output'].getvalue())
1344 elif v.has_key('filename'):
1345 if os.stat(v['filename']).st_size < 50:
1346 compress_type = zipfile.ZIP_STORED
1348 compress_type = zipfile.ZIP_DEFLATED
1349 zf.write(v['filename'], dest, compress_type)
1355 output ('Writing archive %s successful.' % filename)
1360 def make_inventory(inventory, subdir):
1361 document = getDOMImplementation().createDocument(
1362 None, INVENTORY_XML_ROOT, None)
1364 # create summary entry
1365 s = document.createElement(INVENTORY_XML_SUMMARY)
1366 user = os.getenv('SUDO_USER', os.getenv('USER'))
1368 s.setAttribute('user', user)
1369 s.setAttribute('date', time.strftime('%c'))
1370 s.setAttribute('hostname', platform.node())
1371 s.setAttribute('uname', ' '.join(platform.uname()))
1372 s.setAttribute('uptime', commands.getoutput(UPTIME))
1373 document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(s)
1375 map(lambda (k, v): inventory_entry(document, subdir, k, v),
1377 return document.toprettyxml()
1379 def inventory_entry(document, subdir, k, v):
1381 el = document.createElement(INVENTORY_XML_ELEMENT)
1382 el.setAttribute('capability', v['cap'])
1383 el.setAttribute('filename', os.path.join(subdir, construct_filename(k, v)))
1384 el.setAttribute('md5sum', md5sum(v))
1385 document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(el)
1392 if d.has_key('filename'):
1393 f = open(d['filename'])
1395 while len(data) > 0:
1399 elif d.has_key('output'):
1400 m.update(d['output'].getvalue())
1401 return m.hexdigest()
1404 def construct_filename(k, v):
1405 if v.has_key('filename'):
1406 if v['filename'][0] == '/':
1407 return v['filename'][1:]
1409 return v['filename']
1410 s = k.replace(' ', '-')
1411 s = s.replace('--', '-')
1412 s = s.replace('/', '%')
1413 if s.find('.') == -1:
1419 def update_capabilities():
1420 update_cap_size(CAP_HOST_CRASHDUMP_LOGS,
1421 size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE))
1422 update_cap_size(CAP_HOST_CRASHDUMP_DUMPS,
1423 size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE,
1425 update_cap_size(CAP_XAPI_DEBUG, size_of_dir(XAPI_DEBUG_DIR))
1426 update_cap_size(CAP_XENSERVER_LOGS, size_of_all(XENSERVER_LOGS))
1429 def update_cap_size(cap, size):
1430 update_cap(cap, MIN_SIZE, size)
1431 update_cap(cap, MAX_SIZE, size)
1432 update_cap(cap, CHECKED, size > 0)
1435 def update_cap(cap, k, v):
1439 caps[cap] = tuple(l)
1442 def size_of_dir(d, pattern = None, negate = False):
1443 if os.path.isdir(d):
1444 return size_of_all([os.path.join(d, fn) for fn in os.listdir(d)],
1450 def size_of_all(files, pattern = None, negate = False):
1451 return sum([size_of(f, pattern, negate) for f in files])
1454 def matches(f, pattern, negate):
1456 return not matches(f, pattern, False)
1458 return pattern is None or pattern.match(f)
1461 def size_of(f, pattern, negate):
1462 if os.path.isfile(f) and matches(f, pattern, negate):
1463 return os.stat(f)[6]
1465 return size_of_dir(f, pattern, negate)
1468 def print_capabilities():
1469 document = getDOMImplementation().createDocument(
1470 "ns", CAP_XML_ROOT, None)
1471 map(lambda key: capability(document, key), [k for k in caps.keys() if not caps[k][HIDDEN]])
1472 print document.toprettyxml()
1474 def capability(document, key):
1476 el = document.createElement(CAP_XML_ELEMENT)
1477 el.setAttribute('key', c[KEY])
1478 el.setAttribute('pii', c[PII])
1479 el.setAttribute('min-size', str(c[MIN_SIZE]))
1480 el.setAttribute('max-size', str(c[MAX_SIZE]))
1481 el.setAttribute('min-time', str(c[MIN_TIME]))
1482 el.setAttribute('max-time', str(c[MAX_TIME]))
1483 el.setAttribute('content-type', c[MIME])
1484 el.setAttribute('default-checked', c[CHECKED] and 'yes' or 'no')
1485 document.getElementsByTagName(CAP_XML_ROOT)[0].appendChild(el)
1489 format = '%%-%ds: %%s' % max(map(len, [k for k, _ in d.items()]))
1490 return '\n'.join([format % i for i in d.items()]) + '\n'
1494 yn = raw_input(prompt)
1496 return len(yn) == 0 or yn.lower()[0] == 'y'
1499 partition_re = re.compile(r'(.*[0-9]+$)|(^xvd)')
1504 f = open('/proc/partitions')
1507 for line in f.readlines():
1508 (major, minor, blocks, name) = line.split()
1509 if int(major) < 254 and not partition_re.match(name):
1520 def __init__(self, command, max_time, inst=None, filter=None):
1521 self.command = command
1522 self.max_time = max_time
1524 self.running = False
1526 self.timed_out = False
1528 self.timeout = int(time.time()) + self.max_time
1529 self.filter = filter
1530 self.filter_state = {}
1536 return isinstance(self.command, list) and ' '.join(self.command) or self.command
1539 self.timed_out = False
1541 if ProcOutput.debug:
1542 output_ts("Starting '%s'" % self.cmdAsStr())
1543 self.proc = Popen(self.command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null, shell=isinstance(self.command, str))
1544 old = fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_GETFD)
1545 fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
1549 output_ts("'%s' failed" % self.cmdAsStr())
1550 self.running = False
1553 def terminate(self):
1556 os.kill(self.proc.pid, SIGTERM)
1560 self.running = False
1561 self.status = SIGTERM
1563 def read_line(self):
1565 line = self.proc.stdout.readline()
1568 self.status = self.proc.wait()
1570 self.running = False
1573 line = self.filter(line, self.filter_state)
1575 self.inst.write(line)
1577 def run_procs(procs):
1585 active_procs.append(p)
1586 pipes.append(p.proc.stdout)
1588 elif p.status == None and not p.failed and not p.timed_out:
1591 active_procs.append(p)
1592 pipes.append(p.proc.stdout)
1599 (i, o, x) = select(pipes, [], [], 1.0)
1600 now = int(time.time())
1602 # handle process output
1603 for p in active_procs:
1604 if p.proc.stdout in i:
1608 if p.running and now > p.timeout:
1609 output_ts("'%s' timed out" % p.cmdAsStr())
1611 p.inst.write("\n** timeout **\n")
1619 for d in [p for p in os.listdir('/proc') if p.isdigit()]:
1621 if os.path.basename(os.readlink('/proc/%s/exe' % d)) == name:
1629 def readKeyValueFile(filename, allowed_keys = None, strip_quotes = True, assert_quotes = True):
1630 """ Reads a KEY=Value style file (e.g. xensource-inventory). Returns a
1631 dictionary of key/values in the file. Not designed for use with large files
1632 as the file is read entirely into memory."""
1634 f = open(filename, "r")
1635 lines = [x.strip("\n") for x in f.readlines()]
1638 # remove lines contain
1640 lines = filter(lambda x: True in [x.startswith(y) for y in allowed_keys],
1643 defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ]
1648 assert x.startswith("'") and x.endswith("'")
1650 defs = [ (a, quotestrip(b)) for (a,b) in defs ]
1655 class StringIOmtime(StringIO.StringIO):
1656 def __init__(self, buf = ''):
1657 StringIO.StringIO.__init__(self, buf)
1658 self.mtime = time.time()
1661 StringIO.StringIO.write(self, s)
1662 self.mtime = time.time()
1665 if __name__ == "__main__":
1668 except KeyboardInterrupt:
1669 print "\nInterrupted."