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 XAPI_BLOBS = '/var/xapi/blobs'
72 EXTLINUX_CONFIG = '/boot/extlinux.conf'
73 GRUB_CONFIG = '/boot/grub/menu.lst'
74 BOOT_KERNEL = '/boot/vmlinuz-' + OS_RELEASE
75 BOOT_INITRD = '/boot/initrd-' + OS_RELEASE + '.img'
76 PROC_PARTITIONS = '/proc/partitions'
78 PROC_MOUNTS = '/proc/mounts'
79 ISCSI_CONF = '/etc/iscsi/iscsid.conf'
80 ISCSI_INITIATOR = '/etc/iscsi/initiatorname.iscsi'
81 LVM_CACHE = '/etc/lvm/.cache'
82 PROC_CPUINFO = '/proc/cpuinfo'
83 PROC_MEMINFO = '/proc/meminfo'
84 PROC_IOPORTS = '/proc/ioports'
85 PROC_INTERRUPTS = '/proc/interrupts'
86 PROC_SCSI = '/proc/scsi/scsi'
87 FIRSTBOOT_DIR = '/etc/firstboot.d'
88 PROC_VERSION = '/proc/version'
89 PROC_MODULES = '/proc/modules'
90 PROC_DEVICES = '/proc/devices'
91 PROC_FILESYSTEMS = '/proc/filesystems'
92 PROC_CMDLINE = '/proc/cmdline'
93 PROC_CONFIG = '/proc/config.gz'
94 PROC_USB_DEV = '/proc/bus/usb/devices'
95 PROC_XEN_BALLOON = '/proc/xen/balloon'
96 PROC_NET_BONDING_DIR = '/proc/net/bonding'
97 PROC_NET_VLAN_DIR = '/proc/net/vlan'
98 PROC_NET_SOFTNET_STAT = '/proc/net/softnet_stat'
99 PROC_DRIVER_CCISS_DIR = '/proc/driver/cciss'
100 MODPROBE_CONF = '/etc/modprobe.conf'
101 MODPROBE_DIR = '/etc/modprobe.d'
102 BOOT_TIME_CPUS = '/etc/xensource/boot_time_cpus'
103 BOOT_TIME_MEMORY = '/etc/xensource/boot_time_memory'
104 SYSCONFIG_HWCONF = '/etc/sysconfig/hwconf'
105 SYSCONFIG_NETWORK = '/etc/sysconfig/network'
106 SYSCONFIG_NETWORK_SCRIPTS = '/etc/sysconfig/network-scripts'
107 IFCFG_RE = re.compile(r'^.*/ifcfg-.*')
108 ROUTE_RE = re.compile(r'^.*/route-.*')
109 RESOLV_CONF = '/etc/resolv.conf'
110 MULTIPATH_CONF = '/etc/multipath.conf'
111 NSSWITCH_CONF = '/etc/nsswitch.conf'
112 NTP_CONF = '/etc/ntp.conf'
113 IPTABLES_CONFIG = '/etc/sysconfig/iptables-config'
114 HOSTS_ALLOW = '/etc/hosts.allow'
115 HOSTS_DENY = '/etc/hosts.deny'
116 DHCP_LEASE_DIR = '/var/lib/dhclient'
117 DELL_OMSA_LOGS = '/var/log/dell'
118 HP_CMA_LOG = '/var/spool/compaq/cma.log'
119 HP_HPASMD_LOG = '/var/spool/compaq/hpasmd.log'
120 VAR_LOG_DIR = '/var/log/'
121 VNCTERM_CORE_DIR = '/var/xen/vncterm'
122 OPENVSWITCH_CORE_DIR = '/var/xen/openvswitch'
123 OPENVSWITCH_CONF = '/etc/openvswitch/conf.db'
124 OPENVSWITCH_DBCACHE = '/var/xapi/network.dbcache'
125 OPENVSWITCH_LOG_DIR = '/var/log/openvswitch'
126 XENSOURCE_INVENTORY = '/etc/xensource-inventory'
127 OEM_CONFIG_DIR = '/var/xsconfig'
128 OEM_CONFIG_FILES_RE = re.compile(r'^.*xensource-inventory$')
129 OEM_DB_FILES_RE = re.compile(r'^.*state\.db')
130 INITIAL_INVENTORY = '/opt/xensource/etc/initial-inventory'
131 VENDORKERNEL_INVENTORY = '/etc/vendorkernel-inventory'
132 STATIC_VDIS = '/etc/xensource/static-vdis'
133 POOL_CONF = '/etc/xensource/pool.conf'
134 PTOKEN = '/etc/xensource/ptoken'
135 XAPI_CONF = '/etc/xensource/xapi.conf'
136 XAPI_SSL_CONF = '/etc/xensource/xapi-ssl.conf'
137 DB_CONF = '/etc/xensource/db.conf'
138 DB_CONF_RIO = '/etc/xensource/db.conf.rio'
139 DB_DEFAULT_FIELDS = '/etc/xensource/db-default-fields'
140 DB_SCHEMA_SQL = '/etc/xensource/db_schema.sql'
141 XENSTORED_DB = '/var/lib/xenstored/tdb'
142 HOST_CRASHDUMPS_DIR = '/var/crash'
143 HOST_CRASHDUMP_LOGS_RE = re.compile(r'^.*\.log$')
144 X11_LOGS_DIR = VAR_LOG_DIR
145 X11_LOGS_RE = re.compile(r'.*/Xorg\..*$')
146 X11_AUTH_DIR = '/root/'
147 X11_AUTH_RE = re.compile(r'.*/\.((Xauthority)|(serverauth\.[0-9]*))$')
148 XAPI_DEBUG_DIR = '/var/xapi/debug'
149 LOG_CONF = '/etc/xensource/log.conf'
150 INSTALLED_REPOS_DIR = '/etc/xensource/installed-repos'
151 PATCH_APPLIED_DIR = '/var/patch/applied'
153 [ VAR_LOG_DIR + x for x in
154 ['xensource.log', 'xenstored-access.log', 'SMlog', 'xen/xenstored-trace.log',
155 'xen/xen-hotplug.log', 'xen/domain-builder-ng.log'] +
156 [ f % n for n in range(1, 20) \
157 for f in ['xensource.log.%d', 'xensource.log.%d.gz','SMlog.%d', 'SMlog.%d.gz',
158 'xenstored-access.log.%d', 'xenstored-access.log.%d.gz', \
159 'xen/xenstored-access.log.%d', 'xen/xenstored-access.log.%d.gz' ]]] \
160 + glob.glob('/tmp/qemu.[0-9]*')
161 OEM_XENSERVER_LOGS_RE = re.compile(r'^.*xensource\.log$')
162 XHA_LOG = '/var/log/xha.log'
163 XHAD_CONF = '/etc/xensource/xhad.conf'
164 YUM_LOG = '/var/log/yum.log'
165 YUM_REPOS_DIR = '/etc/yum.repos.d'
166 PAM_DIR = '/etc/pam.d'
174 BIOSDEVNAME = '/sbin/biosdevname'
175 BRCTL = '/usr/sbin/brctl'
177 CHKCONFIG = '/sbin/chkconfig'
178 CSL = '/opt/Citrix/StorageLink/bin/csl'
181 DMIDECODE = '/usr/sbin/dmidecode'
182 DMSETUP = '/sbin/dmsetup'
183 ETHTOOL = '/sbin/ethtool'
184 FDISK = '/sbin/fdisk'
185 FIND = '/usr/bin/find'
186 HA_QUERY_LIVESET = '/opt/xensource/debug/debug_ha_query_liveset'
187 HDPARM = '/sbin/hdparm'
188 IFCONFIG = '/sbin/ifconfig'
189 IPTABLES = '/sbin/iptables'
190 ISCSIADM = '/sbin/iscsiadm'
191 LIST_DOMAINS = '/opt/xensource/bin/list_domains'
192 LOSETUP = '/sbin/losetup'
194 LSPCI = '/sbin/lspci'
195 LVS = '/usr/sbin/lvs'
196 MD5SUM = '/usr/bin/md5sum'
197 MULTIPATHD = '/sbin/multipathd'
198 NETSTAT = '/bin/netstat'
199 OMREPORT = '/opt/dell/srvadmin/oma/bin/omreport'
200 OVS_DPCTL = '/usr/bin/ovs-dpctl'
201 OVS_OFCTL = '/usr/bin/ovs-ofctl'
203 PVS = '/usr/sbin/pvs'
204 ROUTE = '/sbin/route'
206 SG_MAP = '/usr/bin/sg_map'
207 SQLITE = '/usr/bin/sqlite3'
208 BIN_STATIC_VDIS = '/opt/xensource/bin/static-vdis'
209 SYSCTL = '/sbin/sysctl'
211 UPTIME = '/usr/bin/uptime'
212 VGS = '/usr/sbin/vgs'
213 VGSCAN = '/sbin/vgscan'
214 XAPI_DB_PROCESS = '/opt/xensource/bin/xapi-db-process'
215 XE = '/opt/xensource/bin/xe'
216 XS = '/opt/xensource/debug/xs'
217 XENSTORE_LS = '/usr/bin/xenstore-ls'
221 # PII -- Personally identifiable information. Of particular concern are
222 # things that would identify customers, or their network topology.
223 # Passwords are never to be included in any bug report, regardless of any PII
226 # NO -- No PII will be in these entries.
227 # YES -- PII will likely or certainly be in these entries.
228 # MAYBE -- The user may wish to audit these entries for PII.
229 # IF_CUSTOMIZED -- If the files are unmodified, then they will contain no PII,
230 # but since we encourage customers to edit these files, PII may have been
231 # introduced by the customer. This is used in particular for the networking
238 PII_IF_CUSTOMIZED = 'if_customized'
249 MIME_DATA = 'application/data'
250 MIME_TEXT = 'text/plain'
252 INVENTORY_XML_ROOT = "system-status-inventory"
253 INVENTORY_XML_SUMMARY = 'system-summary'
254 INVENTORY_XML_ELEMENT = 'inventory-entry'
255 CAP_XML_ROOT = "system-status-capabilities"
256 CAP_XML_ELEMENT = 'capability'
260 CAP_BOOT_LOADER = 'boot-loader'
262 CAP_DISK_INFO = 'disk-info'
263 CAP_FIRSTBOOT = 'firstboot'
264 CAP_HARDWARE_INFO = 'hardware-info'
265 CAP_HDPARM_T = 'hdparm-t'
266 CAP_HIGH_AVAILABILITY = 'high-availability'
267 CAP_HOST_CRASHDUMP_DUMPS = 'host-crashdump-dumps'
268 CAP_HOST_CRASHDUMP_LOGS = 'host-crashdump-logs'
269 CAP_KERNEL_INFO = 'kernel-info'
270 CAP_LOSETUP_A = 'loopback-devices'
271 CAP_MULTIPATH = 'multipath'
272 CAP_NETWORK_CONFIG = 'network-config'
273 CAP_NETWORK_STATUS = 'network-status'
276 CAP_PROCESS_LIST = 'process-list'
277 CAP_PERSISTENT_STATS = 'persistent-stats'
278 CAP_SYSTEM_LOGS = 'system-logs'
279 CAP_SYSTEM_SERVICES = 'system-services'
280 CAP_TAPDISK_LOGS = 'tapdisk-logs'
281 CAP_VNCTERM = 'vncterm'
282 CAP_OPENVSWITCH_CONFIG = 'openvswitch-config'
283 CAP_OPENVSWITCH_LOGS = 'openvswitch-logs'
284 CAP_OPENVSWITCH_STATUS = 'openvswitch-status'
287 CAP_X11_AUTH = 'X11-auth'
288 CAP_XAPI_DEBUG = 'xapi-debug'
289 CAP_XAPI_SUBPROCESS = 'xapi-subprocess'
290 CAP_XENSERVER_CONFIG = 'xenserver-config'
291 CAP_XENSERVER_DOMAINS = 'xenserver-domains'
292 CAP_XENSERVER_DATABASES = 'xenserver-databases'
293 CAP_XENSERVER_INSTALL = 'xenserver-install'
294 CAP_XENSERVER_LOGS = 'xenserver-logs'
295 CAP_XEN_INFO = 'xen-info'
296 CAP_XHA_LIVESET = 'xha-liveset'
304 unlimited_data = False
307 def cap(key, pii=PII_MAYBE, min_size=-1, max_size=-1, min_time=-1,
308 max_time=-1, mime=MIME_TEXT, checked=True):
309 caps[key] = (key, pii, min_size, max_size, min_time, max_time, mime,
314 cap(CAP_BLOBS, PII_NO, max_size=5*MB)
315 cap(CAP_BOOT_LOADER, PII_NO, max_size=3*KB,
317 cap(CAP_CVSM, PII_NO, max_size=3*MB,
319 cap(CAP_DISK_INFO, PII_MAYBE, max_size=25*KB,
321 cap(CAP_FIRSTBOOT, PII_YES, min_size=60*KB, max_size=80*KB)
322 cap(CAP_HARDWARE_INFO, PII_MAYBE, max_size=30*KB,
324 cap(CAP_HDPARM_T, PII_NO, min_size=0, max_size=5*KB,
325 min_time=20, max_time=90, checked=False)
326 cap(CAP_HIGH_AVAILABILITY, PII_MAYBE, max_size=5*MB)
327 cap(CAP_HOST_CRASHDUMP_DUMPS,PII_YES, checked = False)
328 cap(CAP_HOST_CRASHDUMP_LOGS, PII_NO)
329 cap(CAP_KERNEL_INFO, PII_MAYBE, max_size=80*KB,
331 cap(CAP_LOSETUP_A, PII_MAYBE, max_size=KB, max_time=5)
332 cap(CAP_MULTIPATH, PII_MAYBE, max_size=10*KB,
334 cap(CAP_NETWORK_CONFIG, PII_IF_CUSTOMIZED,
335 min_size=0, max_size=20*KB)
336 cap(CAP_NETWORK_STATUS, PII_YES, max_size=19*KB,
338 cap(CAP_PAM, PII_NO, max_size=10*KB)
339 cap(CAP_PERSISTENT_STATS, PII_MAYBE, max_size=50*MB,
341 cap(CAP_PROCESS_LIST, PII_YES, max_size=10*KB,
343 cap(CAP_SYSTEM_LOGS, PII_MAYBE, max_size=50*MB,
345 cap(CAP_SYSTEM_SERVICES, PII_NO, max_size=5*KB,
347 cap(CAP_TAPDISK_LOGS, PII_NO, max_size=64*KB)
348 cap(CAP_VNCTERM, PII_MAYBE, checked = False)
349 cap(CAP_OPENVSWITCH_CONFIG, PII_YES,
350 min_size=0, max_size=20*MB)
351 cap(CAP_OPENVSWITCH_LOGS, PII_YES, max_size=20*MB)
352 cap(CAP_OPENVSWITCH_STATUS, PII_YES, max_size=19*KB,
354 cap(CAP_WLB, PII_NO, max_size=3*MB,
356 cap(CAP_X11_LOGS, PII_NO, max_size=100*KB)
357 cap(CAP_X11_AUTH, PII_NO, max_size=100*KB)
358 cap(CAP_XAPI_DEBUG, PII_MAYBE, max_size=10*MB)
359 cap(CAP_XAPI_SUBPROCESS, PII_NO, max_size=5*KB,
361 cap(CAP_XENSERVER_CONFIG, PII_MAYBE, max_size=50*KB,
363 cap(CAP_XENSERVER_DOMAINS, PII_NO, max_size=1*KB,
365 cap(CAP_XENSERVER_DATABASES, PII_YES, min_size=500*KB,max_size=2*MB,
367 cap(CAP_XENSERVER_INSTALL, PII_MAYBE, min_size=10*KB, max_size=300*KB)
368 cap(CAP_XENSERVER_LOGS, PII_MAYBE, min_size=0, max_size=50*MB)
369 cap(CAP_XEN_INFO, PII_MAYBE, max_size=20*KB,
371 cap(CAP_XHA_LIVESET, PII_MAYBE, max_size=10*KB,
373 cap(CAP_YUM, PII_IF_CUSTOMIZED, max_size=10*KB,
376 ANSWER_YES_TO_ALL = False
380 dev_null = open('/dev/null', 'r+')
388 output("[%s] %s" % (time.strftime("%x %X %Z"), x))
390 def cmd_output(cap, args, label = None, filter = None):
392 a = [aa for aa in args]
393 a[0] = os.path.basename(a[0])
396 data[label] = {'cap': cap, 'cmd_args': args, 'filter': filter}
398 def file_output(cap, path_list):
401 if os.path.exists(p):
402 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
403 cap_sizes[cap] < caps[cap][MAX_SIZE]:
404 data[p] = {'cap': cap, 'filename': p}
407 cap_sizes[cap] += s.st_size
411 output("Omitting %s, size constraint of %s exceeded" % (p, cap))
413 def tree_output(cap, path, pattern = None, negate = False):
415 if os.path.exists(path):
416 for f in os.listdir(path):
417 fn = os.path.join(path, f)
418 if os.path.isfile(fn) and matches(fn, pattern, negate):
419 file_output(cap, [fn])
420 elif os.path.isdir(fn):
421 tree_output(cap, fn, pattern, negate)
423 def func_output(cap, label, func):
425 t = str(func).split()
426 data[label] = {'cap': cap, 'func': func}
431 for (k, v) in data.items():
433 if v.has_key('cmd_args'):
434 v['output'] = StringIOmtime()
435 if not process_lists.has_key(cap):
436 process_lists[cap] = []
437 process_lists[cap].append(ProcOutput(v['cmd_args'], caps[cap][MAX_TIME], v['output'], v['filter']))
438 elif v.has_key('filename') and v['filename'].startswith('/proc/'):
439 # proc files must be read into memory
441 f = open(v['filename'], 'r')
444 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
445 cap_sizes[cap] < caps[cap][MAX_SIZE]:
446 v['output'] = StringIOmtime(s)
447 cap_sizes[cap] += len(s)
449 output("Omitting %s, size constraint of %s exceeded" % (v['filename'], cap))
452 elif v.has_key('func'):
457 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
458 cap_sizes[cap] < caps[cap][MAX_SIZE]:
459 v['output'] = StringIOmtime(s)
460 cap_sizes[cap] += len(s)
462 output("Omitting %s, size constraint of %s exceeded" % (k, cap))
464 run_procs(process_lists.values())
467 def main(argv = None):
468 global ANSWER_YES_TO_ALL, SILENT_MODE
469 global entries, data, dbg
471 # we need access to privileged files, exit if we are not running as root
473 print >>sys.stderr, "Error: xen-bugtool must be run as root"
476 output_type = 'tar.bz2'
483 (options, params) = getopt.gnu_getopt(
484 argv, 'sy', ['capabilities', 'silent', 'yestoall', 'entries=',
485 'output=', 'outfd=', 'all', 'unlimited', 'debug'])
486 except getopt.GetoptError, opterr:
487 print >>sys.stderr, opterr
490 inventory = readKeyValueFile(XENSOURCE_INVENTORY)
491 if inventory.has_key('OEM_BUILD_NUMBER'):
492 cap(CAP_OEM, PII_MAYBE, max_size=5*MB,
495 if os.getenv('XEN_RT'):
496 entries = [CAP_BLOBS, CAP_BOOT_LOADER, CAP_CVSM, CAP_DISK_INFO, CAP_FIRSTBOOT, CAP_HARDWARE_INFO,
497 CAP_HOST_CRASHDUMP_DUMPS, CAP_HOST_CRASHDUMP_LOGS, CAP_KERNEL_INFO, CAP_LOSETUP_A,
498 CAP_NETWORK_CONFIG, CAP_NETWORK_STATUS, CAP_PROCESS_LIST, CAP_HIGH_AVAILABILITY,
499 CAP_PAM, CAP_PERSISTENT_STATS, CAP_MULTIPATH,
500 CAP_SYSTEM_LOGS, CAP_SYSTEM_SERVICES, CAP_TAPDISK_LOGS,
501 CAP_VNCTERM, CAP_OPENVSWITCH_CONFIG,
502 CAP_OPENVSWITCH_LOGS, CAP_OPENVSWITCH_STATUS, CAP_WLB,
503 CAP_X11_LOGS, CAP_X11_AUTH, CAP_XAPI_DEBUG, CAP_XAPI_SUBPROCESS,
504 CAP_XENSERVER_CONFIG, CAP_XENSERVER_DOMAINS, CAP_XENSERVER_DATABASES,
505 CAP_XENSERVER_INSTALL, CAP_XENSERVER_LOGS, CAP_XEN_INFO, CAP_XHA_LIVESET, CAP_YUM]
507 entries = [e for e in caps.keys() if caps[e][CHECKED]]
509 for (k, v) in options:
510 if k == '--capabilities':
511 update_capabilities()
516 if v in ['tar', 'tar.bz2', 'zip']:
519 print >>sys.stderr, "Invalid output format '%s'" % v
522 # "-s" or "--silent" means suppress output (except for the final
523 # output filename at the end)
524 if k in ['-s', '--silent']:
527 if k == '--entries' and v != '':
528 entries = v.split(',')
530 # If the user runs the script with "-y" or "--yestoall" we don't ask
531 # all the really annoying questions.
532 if k in ['-y', '--yestoall']:
533 ANSWER_YES_TO_ALL = True
538 old = fcntl.fcntl(output_fd, fcntl.F_GETFD)
539 fcntl.fcntl(output_fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
541 print >>sys.stderr, "Invalid output file descriptor", output_fd
545 entries = caps.keys()
546 elif k == '--unlimited':
547 unlimited_data = True
550 ProcOutput.debug = True
553 print >>sys.stderr, "Invalid additional arguments", str(params)
556 if output_fd != -1 and output_type != 'tar':
557 print >>sys.stderr, "Option '--outfd' only valid with '--output=tar'"
560 if ANSWER_YES_TO_ALL:
561 output("Warning: '--yestoall' argument provided, will not prompt for individual files.")
564 This application will collate the Xen dmesg output, details of the
565 hardware configuration of your machine, information about the build of
566 Xen that you are using, plus, if you allow it, various logs.
568 The collated information will be saved as a .%s for archiving or
569 sending to a Technical Support Representative.
571 The logs may contain private information, and if you are at all
572 worried about that, you should exit now, or you should explicitly
573 exclude those logs from the archive.
577 # assemble potential data
578 tree_output(CAP_BLOBS, XAPI_BLOBS)
580 file_output(CAP_BOOT_LOADER, [GRUB_CONFIG, EXTLINUX_CONFIG])
581 cmd_output(CAP_BOOT_LOADER, [LS, '-lR', '/boot'])
582 cmd_output(CAP_BOOT_LOADER, [MD5SUM, BOOT_KERNEL, BOOT_INITRD], label='vmlinuz-initrd.md5sum')
584 func_output(CAP_CVSM, 'csl_logs', csl_logs)
586 cmd_output(CAP_DISK_INFO, [FDISK, '-l'])
587 file_output(CAP_DISK_INFO, [PROC_PARTITIONS, PROC_MOUNTS])
588 file_output(CAP_DISK_INFO, [FSTAB, ISCSI_CONF, ISCSI_INITIATOR])
589 cmd_output(CAP_DISK_INFO, [DF, '-alT'])
590 cmd_output(CAP_DISK_INFO, [DF, '-alTi'])
591 for d in disk_list():
592 cmd_output(CAP_DISK_INFO, [HDPARM, '-I', '/dev/%s' % d])
593 if len(pidof('iscsid')) != 0:
594 cmd_output(CAP_DISK_INFO, [ISCSIADM, '-m', 'node'])
595 cmd_output(CAP_DISK_INFO, [VGSCAN])
596 cmd_output(CAP_DISK_INFO, [PVS])
597 cmd_output(CAP_DISK_INFO, [VGS])
598 cmd_output(CAP_DISK_INFO, [LVS])
599 file_output(CAP_DISK_INFO, [LVM_CACHE])
600 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_host'])
601 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_disk'])
602 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/fc_transport'])
603 cmd_output(CAP_DISK_INFO, [SG_MAP, '-x'])
604 func_output(CAP_DISK_INFO, 'scsi-hosts', dump_scsi_hosts)
605 tree_output(CAP_DISK_INFO, PROC_DRIVER_CCISS_DIR)
607 tree_output(CAP_FIRSTBOOT, FIRSTBOOT_DIR)
609 file_output(CAP_HARDWARE_INFO, [PROC_CPUINFO, PROC_MEMINFO, PROC_IOPORTS, PROC_INTERRUPTS])
610 cmd_output(CAP_HARDWARE_INFO, [DMIDECODE])
611 cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-n'])
612 cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-vv'])
613 file_output(CAP_HARDWARE_INFO, [PROC_USB_DEV, PROC_SCSI])
614 file_output(CAP_HARDWARE_INFO, [BOOT_TIME_CPUS, BOOT_TIME_MEMORY])
615 file_output(CAP_HARDWARE_INFO, [SYSCONFIG_HWCONF])
618 for d in disk_list():
619 cmd_output(CAP_HDPARM_T, [HDPARM, '-tT', '/dev/%s' % d])
621 file_output(CAP_HIGH_AVAILABILITY, [XHAD_CONF, XHA_LOG])
623 tree_output(CAP_HOST_CRASHDUMP_DUMPS, HOST_CRASHDUMPS_DIR,
624 HOST_CRASHDUMP_LOGS_RE, True)
625 tree_output(CAP_HOST_CRASHDUMP_LOGS, HOST_CRASHDUMPS_DIR,
626 HOST_CRASHDUMP_LOGS_RE, False)
628 file_output(CAP_KERNEL_INFO, [PROC_VERSION, PROC_MODULES, PROC_DEVICES,
629 PROC_FILESYSTEMS, PROC_CMDLINE])
630 cmd_output(CAP_KERNEL_INFO, [ZCAT, PROC_CONFIG], label='config')
631 cmd_output(CAP_KERNEL_INFO, [SYSCTL, '-A'])
632 file_output(CAP_KERNEL_INFO, [MODPROBE_CONF])
633 tree_output(CAP_KERNEL_INFO, MODPROBE_DIR)
635 cmd_output(CAP_LOSETUP_A, [LOSETUP, '-a'])
637 file_output(CAP_MULTIPATH, [MULTIPATH_CONF])
638 cmd_output(CAP_MULTIPATH, [DMSETUP, 'status'])
639 func_output(CAP_MULTIPATH, 'multipathd_topology', multipathd_topology)
641 tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, IFCFG_RE)
642 tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, ROUTE_RE)
643 file_output(CAP_NETWORK_CONFIG, [SYSCONFIG_NETWORK, RESOLV_CONF, NSSWITCH_CONF])
644 file_output(CAP_NETWORK_CONFIG, [NTP_CONF, IPTABLES_CONFIG, HOSTS_ALLOW, HOSTS_DENY])
646 cmd_output(CAP_NETWORK_STATUS, [IFCONFIG, '-a'])
647 cmd_output(CAP_NETWORK_STATUS, [ROUTE, '-n'])
648 cmd_output(CAP_NETWORK_STATUS, [ARP, '-n'])
649 cmd_output(CAP_NETWORK_STATUS, [NETSTAT, '-an'])
650 tree_output(CAP_NETWORK_STATUS, DHCP_LEASE_DIR)
651 cmd_output(CAP_NETWORK_STATUS, [IPTABLES, '-nL'])
652 cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'show'])
653 cmd_output(CAP_NETWORK_STATUS, [BIOSDEVNAME, '-d'])
654 for p in os.listdir('/sys/class/net/'):
655 if os.path.isdir('/sys/class/net/%s/bridge' % p):
656 cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'showmacs', p])
659 f = open('/sys/class/net/%s/type' % p, 'r')
664 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, p])
665 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-S', p])
666 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-k', p])
667 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-i', p])
668 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-c', p])
671 tree_output(CAP_NETWORK_STATUS, PROC_NET_BONDING_DIR)
672 tree_output(CAP_NETWORK_STATUS, PROC_NET_VLAN_DIR)
673 cmd_output(CAP_NETWORK_STATUS, [TC, '-s', 'qdisc'])
674 file_output(CAP_NETWORK_STATUS, [PROC_NET_SOFTNET_STAT])
676 tree_output(CAP_OEM, DELL_OMSA_LOGS)
677 file_output(CAP_OEM, [HP_CMA_LOG, HP_HPASMD_LOG])
678 if os.path.exists(OMREPORT):
679 cmd_output(CAP_OEM, [OMREPORT, 'system', 'alertlog'])
680 cmd_output(CAP_OEM, [OMREPORT, 'system', 'cmdlog'])
681 cmd_output(CAP_OEM, [OMREPORT, 'system', 'esmlog'])
682 cmd_output(CAP_OEM, [OMREPORT, 'system', 'postlog'])
683 cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'fans'])
684 cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'memory'])
685 cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'temps'])
686 cmd_output(CAP_OEM, [OMREPORT, 'storage', 'controller'])
687 for i in range(0, 4):
688 cmd_output(CAP_OEM, [OMREPORT, 'storage', 'adisk', 'controller=%d' % i])
689 cmd_output(CAP_OEM, [OMREPORT, 'storage', 'vdisk', 'controller=%d' % i])
690 cmd_output(CAP_OEM, [FIND, '/.state', '-size', '+20k', '-exec', 'ls', '-l', '{}',';'],
693 tree_output(CAP_PAM, PAM_DIR)
695 func_output(CAP_PERSISTENT_STATS, 'xapi_rrd-host', dump_xapi_rrds)
697 cmd_output(CAP_PROCESS_LIST, [PS, 'wwwaxf', '-eo', 'pid,tty,stat,time,nice,psr,pcpu,pmem,wchan:25,args'], label='process-tree')
699 file_output(CAP_SYSTEM_LOGS,
700 [ VAR_LOG_DIR + x for x in
701 [ 'syslog', 'messages', 'monitor_memory.log', 'secure', 'debug', 'dmesg', 'boot.msg' ] +
702 [ f % n for n in range(1, 20) \
703 for f in ['messages.%d', 'messages.%d.gz', 'monitor_memory.log.%d',
704 'monitor_memory.log.%d.gz', 'secure.%d', 'secure.%d.gz']]])
705 if not os.path.exists('/var/log/dmesg') and not os.path.exists('/var/log/boot.msg'):
706 cmd_output(CAP_SYSTEM_LOGS, [DMESG])
708 cmd_output(CAP_SYSTEM_SERVICES, [CHKCONFIG, '--list'])
710 if CAP_TAPDISK_LOGS in entries:
711 generate_tapdisk_logs()
713 tree_output(CAP_VNCTERM, VNCTERM_CORE_DIR)
715 file_output(CAP_OPENVSWITCH_CONFIG, [OPENVSWITCH_CONF])
716 file_output(CAP_OPENVSWITCH_CONFIG, [OPENVSWITCH_DBCACHE])
718 file_output(CAP_OPENVSWITCH_LOGS,
719 [ OPENVSWITCH_LOG_DIR + x for x in
720 [ 'ovs-brcompatd.log', 'ovs-vswitchd.log', 'ovsdb-server.log',
721 'openvswitch-cfg-update.log', 'openvswitch-xsplugin.log' ] +
722 [ f % n for n in range(1, 20) \
723 for f in ['ovs-brcompatd.log.%d', 'ovs-brcompatd.log.%d.gz',
724 'ovs-vswitchd.log.%d', 'ovs-vswitchd.log.%d.gz',
725 'ovsdb-server.log.%d', 'ovsdb-server.log.%d.gz']]])
727 cmd_output(CAP_OPENVSWITCH_STATUS, [OVS_DPCTL, 'show'])
728 tree_output(CAP_OPENVSWITCH_STATUS, OPENVSWITCH_CORE_DIR)
730 cmd_output(CAP_OPENVSWITCH_STATUS, [OVS_OFCTL, 'show', d])
731 cmd_output(CAP_OPENVSWITCH_STATUS, [OVS_OFCTL, 'status', d])
732 cmd_output(CAP_OPENVSWITCH_STATUS, [OVS_OFCTL, 'dump-flows', d])
733 cmd_output(CAP_OPENVSWITCH_STATUS, [OVS_DPCTL, 'dump-flows', d])
735 cmd_output(CAP_WLB, [XE, 'pool-retrieve-wlb-diagnostics'])
737 tree_output(CAP_X11_LOGS, X11_LOGS_DIR, X11_LOGS_RE)
738 tree_output(CAP_X11_AUTH, X11_AUTH_DIR, X11_AUTH_RE)
740 tree_output(CAP_XAPI_DEBUG, XAPI_DEBUG_DIR)
742 func_output(CAP_XAPI_SUBPROCESS, 'xapi_subprocesses', dump_xapi_subprocess_info)
744 file_output(CAP_XENSERVER_CONFIG, [INITIAL_INVENTORY])
745 file_output(CAP_XENSERVER_CONFIG, [POOL_CONF, PTOKEN, XAPI_CONF, XAPI_SSL_CONF, STATIC_VDIS,
746 XENSOURCE_INVENTORY, VENDORKERNEL_INVENTORY])
747 cmd_output(CAP_XENSERVER_CONFIG, [LS, '-lR', '/opt/xensource'])
748 cmd_output(CAP_XENSERVER_CONFIG, [BIN_STATIC_VDIS, 'list'])
749 tree_output(CAP_XENSERVER_CONFIG, OEM_CONFIG_DIR, OEM_CONFIG_FILES_RE)
751 func_output(CAP_XENSERVER_DATABASES, 'xapi-db.xml', dump_filtered_xapi_db)
752 cmd_output(CAP_XENSERVER_DATABASES, [XENSTORE_LS])
753 file_output(CAP_XENSERVER_DATABASES, [DB_CONF, DB_CONF_RIO, DB_DEFAULT_FIELDS, DB_SCHEMA_SQL])
754 tree_output(CAP_XENSERVER_DATABASES, OEM_CONFIG_DIR, OEM_DB_FILES_RE)
755 file_output(CAP_XENSERVER_DATABASES, [XENSTORED_DB, XENSTORED_DB + '.bak'])
756 cmd_output(CAP_XENSERVER_DATABASES, [XE, 'pool-dump-database', 'file-name='],
757 label="xapi-db-dumped.xml", filter=filter_db_pii)
758 cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'watches'])
759 cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'quotas'])
761 cmd_output(CAP_XENSERVER_DOMAINS, [LIST_DOMAINS])
763 tree_output(CAP_XENSERVER_INSTALL, VAR_LOG_DIR + 'installer')
764 file_output(CAP_XENSERVER_INSTALL,
765 [ VAR_LOG_DIR + x for x in
766 [ 'firstboot-SR-commands-log',
767 'upgrade-commands-log', 'generate-iscsi-iqn-log']] +
768 [ '/root/' + x for x in
769 [ 'blockdevs-log', 'cmdline-log', 'devcontents-log',
770 'dmesg-log', 'install-log', 'lspci-log', 'modules-log',
771 'pci-log', 'processes-log', 'tty-log', 'uname-log',
773 tree_output(CAP_XENSERVER_INSTALL, INSTALLED_REPOS_DIR)
774 tree_output(CAP_XENSERVER_INSTALL, PATCH_APPLIED_DIR)
776 file_output(CAP_XENSERVER_LOGS, [LOG_CONF])
777 file_output(CAP_XENSERVER_LOGS, XENSERVER_LOGS)
778 tree_output(CAP_XENSERVER_LOGS, OEM_CONFIG_DIR, OEM_XENSERVER_LOGS_RE)
782 data = xc.readconsolering()
783 xc.send_debug_keys('q')
787 xc = xen.lowlevel.xc.xc()
789 func_output(CAP_XEN_INFO, 'xen-dmesg', lambda x: xen_dmesg(xc))
790 func_output(CAP_XEN_INFO, 'physinfo', lambda x: prettyDict(xc.physinfo()))
791 func_output(CAP_XEN_INFO, 'xeninfo', lambda x: prettyDict(xc.xeninfo()))
794 file_output(CAP_XEN_INFO, [PROC_XEN_BALLOON])
796 cmd_output(CAP_XHA_LIVESET, [HA_QUERY_LIVESET])
798 file_output(CAP_YUM, [YUM_LOG])
799 tree_output(CAP_YUM, YUM_REPOS_DIR)
800 cmd_output(CAP_YUM, [RPM, '-qa'])
802 # permit the user to filter out data
803 for k in sorted(data.keys()):
804 if not ANSWER_YES_TO_ALL and not yes("Include '%s'? [Y/n]: " % k):
807 # collect selected data now
808 output_ts('Running commands to collect data')
811 subdir = os.getenv('XENRT_BUGTOOL_BASENAME')
813 subdir = os.path.basename(subdir)
814 if subdir == '..' or subdir == '.':
817 subdir = "bug-report-%s" % time.strftime("%Y%m%d%H%M%S")
820 data['inventory.xml'] = {'cap': None, 'output': StringIOmtime(make_inventory(data, subdir))}
823 if output_fd == -1 and not os.path.exists(BUG_DIR):
830 output_ts('Creating output file')
832 if output_type.startswith('tar'):
833 make_tar(subdir, output_type, output_fd)
840 print >>sys.stderr, "Category sizes (max, actual):\n"
841 for c in caps.keys():
842 print >>sys.stderr, " %s (%d, %d)" % (c, caps[c][MAX_SIZE],
846 def generate_tapdisk_logs():
847 for pid in pidof('tapdisk'):
849 os.kill(pid, SIGUSR1)
850 output_ts("Including logs for tapdisk process %d" % pid)
853 # give processes a second to write their logs
855 file_output(CAP_TAPDISK_LOGS, ['/tmp/tapdisk.log.%d' % pid for pid in pidof('tapdisk')])
857 def clean_tapdisk_logs():
858 for filename in [f for f in os.listdir('/tmp') if f.startswith('tapdisk.log.')]:
860 os.remove(os.path.join('tmp', filename))
864 def dump_xapi_subprocess_info(cap):
865 """Check which fds are open by xapi and its subprocesses to diagnose faults like CA-10543.
866 Returns a string containing a pretty-printed pstree-like structure. """
867 pids = filter(lambda x: x.isdigit(), os.listdir("/proc"))
868 def readlines(filename):
871 f = open(filename, "r")
872 lines = f.readlines()
878 all = readlines("/proc/" + pid + "/cmdline")
882 return all[0].replace('\x00', ' ')
884 for i in readlines("/proc/" + pid + "/status"):
885 if i.startswith("PPid:"):
889 result = { "cmdline": cmdline(pid) }
890 child_pids = filter(lambda x:parent(x) == pid, pids)
892 for child in child_pids:
893 children[child] = pstree(child)
894 result['children'] = children
896 for fd in os.listdir("/proc/" + pid + "/fd"):
898 fds[fd] = os.readlink("/proc/" + pid + "/fd/" + fd)
903 xapis = filter(lambda x: cmdline(x).startswith("/opt/xensource/bin/xapi"), pids)
904 xapis = filter(lambda x: parent(x) == "1", xapis)
907 result[xapi] = pstree(xapi)
908 pp = pprint.PrettyPrinter(indent=4)
909 return pp.pformat(result)
911 def dump_xapi_rrds(cap):
912 socket.setdefaulttimeout(5)
913 session = XenAPI.xapi_local()
914 session.xenapi.login_with_password('', '')
915 this_host = session.xenapi.session.get_this_host(session._session)
916 # better way to find pool master?
917 pool = session.xenapi.pool.get_all_records().values()[0]
918 i_am_master = (this_host == pool['master'])
920 for vm in session.xenapi.VM.get_all_records().values():
921 if vm['is_a_template']:
923 if vm['resident_on'] == this_host or (i_am_master and vm['power_state'] in ['Suspended', 'Halted']):
924 rrd = urllib.urlopen('http://localhost/vm_rrd?session_id=%s&uuid=%s' % (session._session, vm['uuid']))
926 (i, o, x) = select([rrd], [], [], 5.0)
928 data['xapi_rrd-%s' % vm['uuid']] = {'cap': cap,
929 'output': StringIOmtime(rrd.read())}
934 rrd = urllib.urlopen('http://localhost/host_rrd?session_id=%s' % session._session)
941 session.xenapi.session.logout()
944 def filter_db_pii(str):
945 str = re.sub(r'(password_transformed" ")[^ ]+(")', r'\1REMOVED\2', str)
946 str = re.sub(r'(wlb_password=")[^"]+(")', r'\1REMOVED\2', str)
949 def dump_filtered_xapi_db(cap):
953 # determine db format
954 c = open(DB_CONF, 'r')
957 l = line.rstrip('\n')
958 if l.startswith('['):
960 if l.startswith('format:'):
970 if format == 'sqlite':
971 pipe = Popen([XAPI_DB_PROCESS, '-xmltostdout'], bufsize=1, stdin=dev_null,
972 stdout=PIPE, stderr=dev_null)
975 ih = open(db_file, 'r')
987 remain = remain[p+1:]
988 output += filter_db_pii(str)
999 def dump_scsi_hosts(cap):
1001 l = os.listdir('/sys/class/scsi_host')
1007 f = open('/sys/class/scsi_host/%s/proc_name' % h)
1008 procname = f.readline().strip("\n")
1014 f = open('/sys/class/scsi_host/%s/model_name' % h)
1015 modelname = f.readline().strip("\n")
1020 output += "%s:\n" %h
1021 output += " %s%s\n" % (procname, modelname and (" -> %s" % modelname) or '')
1026 socket.setdefaulttimeout(5)
1027 session = XenAPI.xapi_local()
1028 session.xenapi.login_with_password('', '')
1029 this_host = session.xenapi.session.get_this_host(session._session)
1030 # better way to find pool master?
1031 pool = session.xenapi.pool.get_all_records().values()[0]
1032 i_am_master = (this_host == pool['master'])
1034 output = StringIO.StringIO()
1037 def rotate_string(x, n):
1039 for a in range(0, 256):
1040 transtbl = transtbl + chr(a)
1041 transtbl = transtbl[n:] + transtbl[0:n]
1042 return x.translate(transtbl)
1044 def _untransform_string(str, remove_trailing_nulls=False):
1045 """De-obfuscate string. To cope with an obfuscation bug in Rio, the argument
1046 remove_trailing_nulls should be set to True"""
1047 tmp = base64.decodestring(str)
1048 if remove_trailing_nulls:
1049 tmp = tmp.rstrip('\x00')
1050 return rotate_string(tmp, -13)
1052 for pbd in session.xenapi.PBD.get_all_records().values():
1053 if pbd.has_key('device_config') and pbd['device_config'].has_key('target'):
1054 sr = session.xenapi.SR.get_record(pbd['SR'])
1055 if sr.has_key('type') and sr['type'] == 'cslg':
1056 if sr['shared'] and pbd['host'] != this_host and not i_am_master:
1059 dev_cfg = pbd['device_config']
1060 server = "server=%s" % socket.gethostbyname(dev_cfg['target'])
1061 if dev_cfg.has_key('port'):
1062 server += ':' + dev_cfg['port']
1063 if dev_cfg.has_key('username'):
1064 server += ',' + dev_cfg['username']
1065 if dev_cfg.has_key('password_transformed'):
1066 server += ',' + _untransform_string(dev_cfg['password_transformed'])
1067 procs.append(ProcOutput([CSL, server, 'srv-log-get'], caps[cap][MAX_TIME], output))
1069 session.xenapi.session.logout()
1073 return output.getvalue()
1075 def multipathd_topology(cap):
1076 pipe = Popen([MULTIPATHD, '-k'], bufsize=1, stdin=PIPE,
1077 stdout=PIPE, stderr=dev_null)
1078 stdout, stderr = pipe.communicate('show topology')
1082 def make_tar(subdir, suffix, output_fd):
1083 global SILENT_MODE, data
1086 if suffix == 'tar.bz2':
1088 filename = "%s/%s.%s" % (BUG_DIR, subdir, suffix)
1091 tf = tarfile.open(filename, mode)
1093 tf = tarfile.open(None, 'w', os.fdopen(output_fd, 'a'))
1096 for (k, v) in data.items():
1098 tar_filename = os.path.join(subdir, construct_filename(k, v))
1099 ti = tarfile.TarInfo(tar_filename)
1104 if v.has_key('output'):
1105 ti.mtime = v['output'].mtime
1106 ti.size = len(v['output'].getvalue())
1108 tf.addfile(ti, v['output'])
1109 elif v.has_key('filename'):
1110 s = os.stat(v['filename'])
1111 ti.mtime = s.st_mtime
1113 tf.addfile(ti, file(v['filename']))
1120 output ('Writing tarball %s successful.' % filename)
1125 def make_zip(subdir):
1126 global SILENT_MODE, data
1128 filename = "%s/%s.zip" % (BUG_DIR, subdir)
1129 zf = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED)
1132 for (k, v) in data.items():
1134 dest = os.path.join(subdir, construct_filename(k, v))
1136 if v.has_key('output'):
1137 zf.writestr(dest, v['output'].getvalue())
1139 if os.stat(v['filename']).st_size < 50:
1140 compress_type = zipfile.ZIP_STORED
1142 compress_type = zipfile.ZIP_DEFLATED
1143 zf.write(v['filename'], dest, compress_type)
1149 output ('Writing archive %s successful.' % filename)
1154 def make_inventory(inventory, subdir):
1155 document = getDOMImplementation().createDocument(
1156 None, INVENTORY_XML_ROOT, None)
1158 # create summary entry
1159 s = document.createElement(INVENTORY_XML_SUMMARY)
1160 user = os.getenv('SUDO_USER', os.getenv('USER'))
1162 s.setAttribute('user', user)
1163 s.setAttribute('date', time.strftime('%c'))
1164 s.setAttribute('hostname', platform.node())
1165 s.setAttribute('uname', ' '.join(platform.uname()))
1166 s.setAttribute('uptime', commands.getoutput(UPTIME))
1167 document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(s)
1169 map(lambda (k, v): inventory_entry(document, subdir, k, v),
1171 return document.toprettyxml()
1173 def inventory_entry(document, subdir, k, v):
1175 el = document.createElement(INVENTORY_XML_ELEMENT)
1176 el.setAttribute('capability', v['cap'])
1177 el.setAttribute('filename', os.path.join(subdir, construct_filename(k, v)))
1178 el.setAttribute('md5sum', md5sum(v))
1179 document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(el)
1186 if d.has_key('filename'):
1187 f = open(d['filename'])
1189 while len(data) > 0:
1193 elif d.has_key('output'):
1194 m.update(d['output'].getvalue())
1195 return m.hexdigest()
1198 def construct_filename(k, v):
1199 if v.has_key('filename'):
1200 if v['filename'][0] == '/':
1201 return v['filename'][1:]
1203 return v['filename']
1204 s = k.replace(' ', '-')
1205 s = s.replace('--', '-')
1206 s = s.replace('/', '%')
1207 if s.find('.') == -1:
1213 def update_capabilities():
1214 update_cap_size(CAP_HOST_CRASHDUMP_LOGS,
1215 size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE))
1216 update_cap_size(CAP_HOST_CRASHDUMP_DUMPS,
1217 size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE,
1219 update_cap_size(CAP_XAPI_DEBUG, size_of_dir(XAPI_DEBUG_DIR))
1220 update_cap_size(CAP_XENSERVER_LOGS, size_of_all(XENSERVER_LOGS))
1223 def update_cap_size(cap, size):
1224 update_cap(cap, MIN_SIZE, size)
1225 update_cap(cap, MAX_SIZE, size)
1226 update_cap(cap, CHECKED, size > 0)
1229 def update_cap(cap, k, v):
1233 caps[cap] = tuple(l)
1236 def size_of_dir(d, pattern = None, negate = False):
1237 if os.path.isdir(d):
1238 return size_of_all([os.path.join(d, fn) for fn in os.listdir(d)],
1244 def size_of_all(files, pattern = None, negate = False):
1245 return sum([size_of(f, pattern, negate) for f in files])
1248 def matches(f, pattern, negate):
1250 return not matches(f, pattern, False)
1252 return pattern is None or pattern.match(f)
1255 def size_of(f, pattern, negate):
1256 if os.path.isfile(f) and matches(f, pattern, negate):
1257 return os.stat(f)[6]
1259 return size_of_dir(f, pattern, negate)
1262 def print_capabilities():
1263 document = getDOMImplementation().createDocument(
1264 "ns", CAP_XML_ROOT, None)
1265 map(lambda key: capability(document, key), caps.keys())
1266 print document.toprettyxml()
1268 def capability(document, key):
1270 el = document.createElement(CAP_XML_ELEMENT)
1271 el.setAttribute('key', c[KEY])
1272 el.setAttribute('pii', c[PII])
1273 el.setAttribute('min-size', str(c[MIN_SIZE]))
1274 el.setAttribute('max-size', str(c[MAX_SIZE]))
1275 el.setAttribute('min-time', str(c[MIN_TIME]))
1276 el.setAttribute('max-time', str(c[MAX_TIME]))
1277 el.setAttribute('content-type', c[MIME])
1278 el.setAttribute('default-checked', c[CHECKED] and 'yes' or 'no')
1279 document.getElementsByTagName(CAP_XML_ROOT)[0].appendChild(el)
1283 format = '%%-%ds: %%s' % max(map(len, [k for k, _ in d.items()]))
1284 return '\n'.join([format % i for i in d.items()]) + '\n'
1288 yn = raw_input(prompt)
1290 return len(yn) == 0 or yn.lower()[0] == 'y'
1293 partition_re = re.compile(r'(.*[0-9]+$)|(^xvd)')
1296 command = [OVS_DPCTL, "dump-dps"]
1297 proc = Popen(command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null)
1298 (dps, err) = proc.communicate()
1299 return dps.splitlines()
1305 f = open('/proc/partitions')
1308 for line in f.readlines():
1309 (major, minor, blocks, name) = line.split()
1310 if int(major) < 254 and not partition_re.match(name):
1320 def __init__(self, command, max_time, inst=None, filter=None):
1321 self.command = command
1322 self.max_time = max_time
1324 self.running = False
1326 self.timed_out = False
1328 self.timeout = int(time.time()) + self.max_time
1329 self.filter = filter
1335 self.timed_out = False
1337 if ProcOutput.debug:
1338 output_ts("Starting '%s'" % ' '.join(self.command))
1339 self.proc = Popen(self.command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null)
1340 old = fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_GETFD)
1341 fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
1345 output_ts("'%s' failed" % ' '.join(self.command))
1346 self.running = False
1349 def terminate(self):
1352 os.kill(self.proc.pid, SIGTERM)
1356 self.running = False
1357 self.status = SIGTERM
1359 def read_line(self):
1361 line = self.proc.stdout.readline()
1364 self.status = self.proc.wait()
1366 self.running = False
1369 line = self.filter(line)
1371 self.inst.write(line)
1373 def run_procs(procs):
1381 active_procs.append(p)
1382 pipes.append(p.proc.stdout)
1384 elif p.status == None and not p.failed and not p.timed_out:
1387 active_procs.append(p)
1388 pipes.append(p.proc.stdout)
1395 (i, o, x) = select(pipes, [], [], 1.0)
1396 now = int(time.time())
1398 # handle process output
1399 for p in active_procs:
1400 if p.proc.stdout in i:
1404 if p.running and now > p.timeout:
1405 output_ts("'%s' timed out" % ' '.join(p.command))
1407 p.inst.write("\n** timeout **\n")
1415 for d in [p for p in os.listdir('/proc') if p.isdigit()]:
1417 if os.path.basename(os.readlink('/proc/%s/exe' % d)) == name:
1425 def readKeyValueFile(filename, allowed_keys = None, strip_quotes = True, assert_quotes = True):
1426 """ Reads a KEY=Value style file (e.g. xensource-inventory). Returns a
1427 dictionary of key/values in the file. Not designed for use with large files
1428 as the file is read entirely into memory."""
1430 f = open(filename, "r")
1431 lines = [x.strip("\n") for x in f.readlines()]
1434 # remove lines contain
1436 lines = filter(lambda x: True in [x.startswith(y) for y in allowed_keys],
1439 defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ]
1444 assert x.startswith("'") and x.endswith("'")
1446 defs = [ (a, quotestrip(b)) for (a,b) in defs ]
1451 class StringIOmtime(StringIO.StringIO):
1452 def __init__(self, buf = ''):
1453 StringIO.StringIO.__init__(self, buf)
1454 self.mtime = time.time()
1457 StringIO.StringIO.write(self, s)
1458 self.mtime = time.time()
1461 if __name__ == "__main__":
1464 except KeyboardInterrupt:
1465 print "\nInterrupted."