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 VSWITCH_CORE_DIR = '/var/xen/vswitch'
123 OVS_VSWITCH_CONF = '/etc/ovs-vswitchd.conf.db'
124 OVS_VSWITCH_DBCACHE = '/var/xapi/network.dbcache'
125 XENSOURCE_INVENTORY = '/etc/xensource-inventory'
126 OEM_CONFIG_DIR = '/var/xsconfig'
127 OEM_CONFIG_FILES_RE = re.compile(r'^.*xensource-inventory$')
128 OEM_DB_FILES_RE = re.compile(r'^.*state\.db')
129 INITIAL_INVENTORY = '/opt/xensource/etc/initial-inventory'
130 VENDORKERNEL_INVENTORY = '/etc/vendorkernel-inventory'
131 STATIC_VDIS = '/etc/xensource/static-vdis'
132 POOL_CONF = '/etc/xensource/pool.conf'
133 PTOKEN = '/etc/xensource/ptoken'
134 XAPI_CONF = '/etc/xensource/xapi.conf'
135 XAPI_SSL_CONF = '/etc/xensource/xapi-ssl.conf'
136 DB_CONF = '/etc/xensource/db.conf'
137 DB_CONF_RIO = '/etc/xensource/db.conf.rio'
138 DB_DEFAULT_FIELDS = '/etc/xensource/db-default-fields'
139 DB_SCHEMA_SQL = '/etc/xensource/db_schema.sql'
140 XENSTORED_DB = '/var/lib/xenstored/tdb'
141 HOST_CRASHDUMPS_DIR = '/var/crash'
142 HOST_CRASHDUMP_LOGS_RE = re.compile(r'^.*\.log$')
143 X11_LOGS_DIR = VAR_LOG_DIR
144 X11_LOGS_RE = re.compile(r'.*/Xorg\..*$')
145 X11_AUTH_DIR = '/root/'
146 X11_AUTH_RE = re.compile(r'.*/\.((Xauthority)|(serverauth\.[0-9]*))$')
147 XAPI_DEBUG_DIR = '/var/xapi/debug'
148 LOG_CONF = '/etc/xensource/log.conf'
149 INSTALLED_REPOS_DIR = '/etc/xensource/installed-repos'
150 PATCH_APPLIED_DIR = '/var/patch/applied'
152 [ VAR_LOG_DIR + x for x in
153 ['xensource.log', 'xenstored-access.log', 'SMlog', 'xen/xenstored-trace.log',
154 'xen/xen-hotplug.log', 'xen/domain-builder-ng.log'] +
155 [ f % n for n in range(1, 20) \
156 for f in ['xensource.log.%d', 'xensource.log.%d.gz','SMlog.%d', 'SMlog.%d.gz',
157 'xenstored-access.log.%d', 'xenstored-access.log.%d.gz', \
158 'xen/xenstored-access.log.%d', 'xen/xenstored-access.log.%d.gz' ]]] \
159 + glob.glob('/tmp/qemu.[0-9]*')
160 OEM_XENSERVER_LOGS_RE = re.compile(r'^.*xensource\.log$')
161 XHA_LOG = '/var/log/xha.log'
162 XHAD_CONF = '/etc/xensource/xhad.conf'
163 YUM_LOG = '/var/log/yum.log'
164 YUM_REPOS_DIR = '/etc/yum.repos.d'
165 PAM_DIR = '/etc/pam.d'
173 BIOSDEVNAME = '/sbin/biosdevname'
174 BRCTL = '/usr/sbin/brctl'
176 CHKCONFIG = '/sbin/chkconfig'
177 CSL = '/opt/Citrix/StorageLink/bin/csl'
180 DMIDECODE = '/usr/sbin/dmidecode'
181 DMSETUP = '/sbin/dmsetup'
182 ETHTOOL = '/sbin/ethtool'
183 FDISK = '/sbin/fdisk'
184 FIND = '/usr/bin/find'
185 HA_QUERY_LIVESET = '/opt/xensource/debug/debug_ha_query_liveset'
186 HDPARM = '/sbin/hdparm'
187 IFCONFIG = '/sbin/ifconfig'
188 IPTABLES = '/sbin/iptables'
189 ISCSIADM = '/sbin/iscsiadm'
190 LIST_DOMAINS = '/opt/xensource/bin/list_domains'
191 LOSETUP = '/sbin/losetup'
193 LSPCI = '/sbin/lspci'
194 LVS = '/usr/sbin/lvs'
195 MD5SUM = '/usr/bin/md5sum'
196 MULTIPATHD = '/sbin/multipathd'
197 NETSTAT = '/bin/netstat'
198 OMREPORT = '/opt/dell/srvadmin/oma/bin/omreport'
199 OVS_DPCTL = '/usr/bin/ovs-dpctl'
200 OVS_OFCTL = '/usr/bin/ovs-ofctl'
202 PVS = '/usr/sbin/pvs'
203 ROUTE = '/sbin/route'
205 SG_MAP = '/usr/bin/sg_map'
206 SQLITE = '/usr/bin/sqlite3'
207 BIN_STATIC_VDIS = '/opt/xensource/bin/static-vdis'
208 SYSCTL = '/sbin/sysctl'
210 UPTIME = '/usr/bin/uptime'
211 VGS = '/usr/sbin/vgs'
212 VGSCAN = '/sbin/vgscan'
213 XAPI_DB_PROCESS = '/opt/xensource/bin/xapi-db-process'
214 XE = '/opt/xensource/bin/xe'
215 XS = '/opt/xensource/debug/xs'
216 XENSTORE_LS = '/usr/bin/xenstore-ls'
220 # PII -- Personally identifiable information. Of particular concern are
221 # things that would identify customers, or their network topology.
222 # Passwords are never to be included in any bug report, regardless of any PII
225 # NO -- No PII will be in these entries.
226 # YES -- PII will likely or certainly be in these entries.
227 # MAYBE -- The user may wish to audit these entries for PII.
228 # IF_CUSTOMIZED -- If the files are unmodified, then they will contain no PII,
229 # but since we encourage customers to edit these files, PII may have been
230 # introduced by the customer. This is used in particular for the networking
237 PII_IF_CUSTOMIZED = 'if_customized'
248 MIME_DATA = 'application/data'
249 MIME_TEXT = 'text/plain'
251 INVENTORY_XML_ROOT = "system-status-inventory"
252 INVENTORY_XML_SUMMARY = 'system-summary'
253 INVENTORY_XML_ELEMENT = 'inventory-entry'
254 CAP_XML_ROOT = "system-status-capabilities"
255 CAP_XML_ELEMENT = 'capability'
259 CAP_BOOT_LOADER = 'boot-loader'
261 CAP_DISK_INFO = 'disk-info'
262 CAP_FIRSTBOOT = 'firstboot'
263 CAP_HARDWARE_INFO = 'hardware-info'
264 CAP_HDPARM_T = 'hdparm-t'
265 CAP_HIGH_AVAILABILITY = 'high-availability'
266 CAP_HOST_CRASHDUMP_DUMPS = 'host-crashdump-dumps'
267 CAP_HOST_CRASHDUMP_LOGS = 'host-crashdump-logs'
268 CAP_KERNEL_INFO = 'kernel-info'
269 CAP_LOSETUP_A = 'loopback-devices'
270 CAP_MULTIPATH = 'multipath'
271 CAP_NETWORK_CONFIG = 'network-config'
272 CAP_NETWORK_STATUS = 'network-status'
275 CAP_PROCESS_LIST = 'process-list'
276 CAP_PERSISTENT_STATS = 'persistent-stats'
277 CAP_SYSTEM_LOGS = 'system-logs'
278 CAP_SYSTEM_SERVICES = 'system-services'
279 CAP_TAPDISK_LOGS = 'tapdisk-logs'
280 CAP_VNCTERM = 'vncterm'
281 CAP_VSWITCH_CONFIG = 'vswitch-config'
282 CAP_VSWITCH_LOGS = 'vswitch-logs'
283 CAP_VSWITCH_STATUS = 'vswitch-status'
286 CAP_X11_AUTH = 'X11-auth'
287 CAP_XAPI_DEBUG = 'xapi-debug'
288 CAP_XAPI_SUBPROCESS = 'xapi-subprocess'
289 CAP_XENSERVER_CONFIG = 'xenserver-config'
290 CAP_XENSERVER_DOMAINS = 'xenserver-domains'
291 CAP_XENSERVER_DATABASES = 'xenserver-databases'
292 CAP_XENSERVER_INSTALL = 'xenserver-install'
293 CAP_XENSERVER_LOGS = 'xenserver-logs'
294 CAP_XEN_INFO = 'xen-info'
295 CAP_XHA_LIVESET = 'xha-liveset'
303 unlimited_data = False
306 def cap(key, pii=PII_MAYBE, min_size=-1, max_size=-1, min_time=-1,
307 max_time=-1, mime=MIME_TEXT, checked=True):
308 caps[key] = (key, pii, min_size, max_size, min_time, max_time, mime,
313 cap(CAP_BLOBS, PII_NO, max_size=5*MB)
314 cap(CAP_BOOT_LOADER, PII_NO, max_size=3*KB,
316 cap(CAP_CVSM, PII_NO, max_size=3*MB,
318 cap(CAP_DISK_INFO, PII_MAYBE, max_size=25*KB,
320 cap(CAP_FIRSTBOOT, PII_YES, min_size=60*KB, max_size=80*KB)
321 cap(CAP_HARDWARE_INFO, PII_MAYBE, max_size=30*KB,
323 cap(CAP_HDPARM_T, PII_NO, min_size=0, max_size=5*KB,
324 min_time=20, max_time=90, checked=False)
325 cap(CAP_HIGH_AVAILABILITY, PII_MAYBE, max_size=5*MB)
326 cap(CAP_HOST_CRASHDUMP_DUMPS,PII_YES, checked = False)
327 cap(CAP_HOST_CRASHDUMP_LOGS, PII_NO)
328 cap(CAP_KERNEL_INFO, PII_MAYBE, max_size=80*KB,
330 cap(CAP_LOSETUP_A, PII_MAYBE, max_size=KB, max_time=5)
331 cap(CAP_MULTIPATH, PII_MAYBE, max_size=10*KB,
333 cap(CAP_NETWORK_CONFIG, PII_IF_CUSTOMIZED,
334 min_size=0, max_size=20*KB)
335 cap(CAP_NETWORK_STATUS, PII_YES, max_size=19*KB,
337 cap(CAP_PAM, PII_NO, max_size=10*KB)
338 cap(CAP_PERSISTENT_STATS, PII_MAYBE, max_size=50*MB,
340 cap(CAP_PROCESS_LIST, PII_YES, max_size=10*KB,
342 cap(CAP_SYSTEM_LOGS, PII_MAYBE, max_size=50*MB,
344 cap(CAP_SYSTEM_SERVICES, PII_NO, max_size=5*KB,
346 cap(CAP_TAPDISK_LOGS, PII_NO, max_size=64*KB)
347 cap(CAP_VNCTERM, PII_MAYBE, checked = False)
348 cap(CAP_VSWITCH_CONFIG, PII_YES,
349 min_size=0, max_size=20*MB)
350 cap(CAP_VSWITCH_LOGS, PII_YES, max_size=20*MB)
351 cap(CAP_VSWITCH_STATUS, PII_YES, max_size=19*KB,
353 cap(CAP_WLB, PII_NO, max_size=3*MB,
355 cap(CAP_X11_LOGS, PII_NO, max_size=100*KB)
356 cap(CAP_X11_AUTH, PII_NO, max_size=100*KB)
357 cap(CAP_XAPI_DEBUG, PII_MAYBE, max_size=10*MB)
358 cap(CAP_XAPI_SUBPROCESS, PII_NO, max_size=5*KB,
360 cap(CAP_XENSERVER_CONFIG, PII_MAYBE, max_size=50*KB,
362 cap(CAP_XENSERVER_DOMAINS, PII_NO, max_size=1*KB,
364 cap(CAP_XENSERVER_DATABASES, PII_YES, min_size=500*KB,max_size=2*MB,
366 cap(CAP_XENSERVER_INSTALL, PII_MAYBE, min_size=10*KB, max_size=300*KB)
367 cap(CAP_XENSERVER_LOGS, PII_MAYBE, min_size=0, max_size=50*MB)
368 cap(CAP_XEN_INFO, PII_MAYBE, max_size=20*KB,
370 cap(CAP_XHA_LIVESET, PII_MAYBE, max_size=10*KB,
372 cap(CAP_YUM, PII_IF_CUSTOMIZED, max_size=10*KB,
375 ANSWER_YES_TO_ALL = False
379 dev_null = open('/dev/null', 'r+')
387 output("[%s] %s" % (time.strftime("%x %X %Z"), x))
389 def cmd_output(cap, args, label = None, filter = None):
391 a = [aa for aa in args]
392 a[0] = os.path.basename(a[0])
395 data[label] = {'cap': cap, 'cmd_args': args, 'filter': filter}
397 def file_output(cap, path_list):
400 if os.path.exists(p):
401 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
402 cap_sizes[cap] < caps[cap][MAX_SIZE]:
403 data[p] = {'cap': cap, 'filename': p}
406 cap_sizes[cap] += s.st_size
410 output("Omitting %s, size constraint of %s exceeded" % (p, cap))
412 def tree_output(cap, path, pattern = None, negate = False):
414 if os.path.exists(path):
415 for f in os.listdir(path):
416 fn = os.path.join(path, f)
417 if os.path.isfile(fn) and matches(fn, pattern, negate):
418 file_output(cap, [fn])
419 elif os.path.isdir(fn):
420 tree_output(cap, fn, pattern, negate)
422 def func_output(cap, label, func):
424 t = str(func).split()
425 data[label] = {'cap': cap, 'func': func}
430 for (k, v) in data.items():
432 if v.has_key('cmd_args'):
433 v['output'] = StringIOmtime()
434 if not process_lists.has_key(cap):
435 process_lists[cap] = []
436 process_lists[cap].append(ProcOutput(v['cmd_args'], caps[cap][MAX_TIME], v['output'], v['filter']))
437 elif v.has_key('filename') and v['filename'].startswith('/proc/'):
438 # proc files must be read into memory
440 f = open(v['filename'], 'r')
443 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
444 cap_sizes[cap] < caps[cap][MAX_SIZE]:
445 v['output'] = StringIOmtime(s)
446 cap_sizes[cap] += len(s)
448 output("Omitting %s, size constraint of %s exceeded" % (v['filename'], cap))
451 elif v.has_key('func'):
456 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
457 cap_sizes[cap] < caps[cap][MAX_SIZE]:
458 v['output'] = StringIOmtime(s)
459 cap_sizes[cap] += len(s)
461 output("Omitting %s, size constraint of %s exceeded" % (k, cap))
463 run_procs(process_lists.values())
466 def main(argv = None):
467 global ANSWER_YES_TO_ALL, SILENT_MODE
468 global entries, data, dbg
470 # we need access to privileged files, exit if we are not running as root
472 print >>sys.stderr, "Error: xen-bugtool must be run as root"
475 output_type = 'tar.bz2'
482 (options, params) = getopt.gnu_getopt(
483 argv, 'sy', ['capabilities', 'silent', 'yestoall', 'entries=',
484 'output=', 'outfd=', 'all', 'unlimited', 'debug'])
485 except getopt.GetoptError, opterr:
486 print >>sys.stderr, opterr
489 inventory = readKeyValueFile(XENSOURCE_INVENTORY)
490 if inventory.has_key('OEM_BUILD_NUMBER'):
491 cap(CAP_OEM, PII_MAYBE, max_size=5*MB,
494 if os.getenv('XEN_RT'):
495 entries = [CAP_BLOBS, CAP_BOOT_LOADER, CAP_CVSM, CAP_DISK_INFO, CAP_FIRSTBOOT, CAP_HARDWARE_INFO,
496 CAP_HOST_CRASHDUMP_DUMPS, CAP_HOST_CRASHDUMP_LOGS, CAP_KERNEL_INFO, CAP_LOSETUP_A,
497 CAP_NETWORK_CONFIG, CAP_NETWORK_STATUS, CAP_PROCESS_LIST, CAP_HIGH_AVAILABILITY,
498 CAP_PAM, CAP_PERSISTENT_STATS, CAP_MULTIPATH,
499 CAP_SYSTEM_LOGS, CAP_SYSTEM_SERVICES, CAP_TAPDISK_LOGS,
500 CAP_VNCTERM, CAP_VSWITCH_CONFIG, CAP_VSWITCH_LOGS, CAP_VSWITCH_STATUS, CAP_WLB,
501 CAP_X11_LOGS, CAP_X11_AUTH, CAP_XAPI_DEBUG, CAP_XAPI_SUBPROCESS,
502 CAP_XENSERVER_CONFIG, CAP_XENSERVER_DOMAINS, CAP_XENSERVER_DATABASES,
503 CAP_XENSERVER_INSTALL, CAP_XENSERVER_LOGS, CAP_XEN_INFO, CAP_XHA_LIVESET, CAP_YUM]
505 entries = [e for e in caps.keys() if caps[e][CHECKED]]
507 for (k, v) in options:
508 if k == '--capabilities':
509 update_capabilities()
514 if v in ['tar', 'tar.bz2', 'zip']:
517 print >>sys.stderr, "Invalid output format '%s'" % v
520 # "-s" or "--silent" means suppress output (except for the final
521 # output filename at the end)
522 if k in ['-s', '--silent']:
525 if k == '--entries' and v != '':
526 entries = v.split(',')
528 # If the user runs the script with "-y" or "--yestoall" we don't ask
529 # all the really annoying questions.
530 if k in ['-y', '--yestoall']:
531 ANSWER_YES_TO_ALL = True
536 old = fcntl.fcntl(output_fd, fcntl.F_GETFD)
537 fcntl.fcntl(output_fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
539 print >>sys.stderr, "Invalid output file descriptor", output_fd
543 entries = caps.keys()
544 elif k == '--unlimited':
545 unlimited_data = True
548 ProcOutput.debug = True
551 print >>sys.stderr, "Invalid additional arguments", str(params)
554 if output_fd != -1 and output_type != 'tar':
555 print >>sys.stderr, "Option '--outfd' only valid with '--output=tar'"
558 if ANSWER_YES_TO_ALL:
559 output("Warning: '--yestoall' argument provided, will not prompt for individual files.")
562 This application will collate the Xen dmesg output, details of the
563 hardware configuration of your machine, information about the build of
564 Xen that you are using, plus, if you allow it, various logs.
566 The collated information will be saved as a .%s for archiving or
567 sending to a Technical Support Representative.
569 The logs may contain private information, and if you are at all
570 worried about that, you should exit now, or you should explicitly
571 exclude those logs from the archive.
575 # assemble potential data
576 tree_output(CAP_BLOBS, XAPI_BLOBS)
578 file_output(CAP_BOOT_LOADER, [GRUB_CONFIG, EXTLINUX_CONFIG])
579 cmd_output(CAP_BOOT_LOADER, [LS, '-lR', '/boot'])
580 cmd_output(CAP_BOOT_LOADER, [MD5SUM, BOOT_KERNEL, BOOT_INITRD], label='vmlinuz-initrd.md5sum')
582 func_output(CAP_CVSM, 'csl_logs', csl_logs)
584 cmd_output(CAP_DISK_INFO, [FDISK, '-l'])
585 file_output(CAP_DISK_INFO, [PROC_PARTITIONS, PROC_MOUNTS])
586 file_output(CAP_DISK_INFO, [FSTAB, ISCSI_CONF, ISCSI_INITIATOR])
587 cmd_output(CAP_DISK_INFO, [DF, '-alT'])
588 cmd_output(CAP_DISK_INFO, [DF, '-alTi'])
589 for d in disk_list():
590 cmd_output(CAP_DISK_INFO, [HDPARM, '-I', '/dev/%s' % d])
591 if len(pidof('iscsid')) != 0:
592 cmd_output(CAP_DISK_INFO, [ISCSIADM, '-m', 'node'])
593 cmd_output(CAP_DISK_INFO, [VGSCAN])
594 cmd_output(CAP_DISK_INFO, [PVS])
595 cmd_output(CAP_DISK_INFO, [VGS])
596 cmd_output(CAP_DISK_INFO, [LVS])
597 file_output(CAP_DISK_INFO, [LVM_CACHE])
598 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_host'])
599 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_disk'])
600 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/fc_transport'])
601 cmd_output(CAP_DISK_INFO, [SG_MAP, '-x'])
602 func_output(CAP_DISK_INFO, 'scsi-hosts', dump_scsi_hosts)
603 tree_output(CAP_DISK_INFO, PROC_DRIVER_CCISS_DIR)
605 tree_output(CAP_FIRSTBOOT, FIRSTBOOT_DIR)
607 file_output(CAP_HARDWARE_INFO, [PROC_CPUINFO, PROC_MEMINFO, PROC_IOPORTS, PROC_INTERRUPTS])
608 cmd_output(CAP_HARDWARE_INFO, [DMIDECODE])
609 cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-n'])
610 cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-vv'])
611 file_output(CAP_HARDWARE_INFO, [PROC_USB_DEV, PROC_SCSI])
612 file_output(CAP_HARDWARE_INFO, [BOOT_TIME_CPUS, BOOT_TIME_MEMORY])
613 file_output(CAP_HARDWARE_INFO, [SYSCONFIG_HWCONF])
616 for d in disk_list():
617 cmd_output(CAP_HDPARM_T, [HDPARM, '-tT', '/dev/%s' % d])
619 file_output(CAP_HIGH_AVAILABILITY, [XHAD_CONF, XHA_LOG])
621 tree_output(CAP_HOST_CRASHDUMP_DUMPS, HOST_CRASHDUMPS_DIR,
622 HOST_CRASHDUMP_LOGS_RE, True)
623 tree_output(CAP_HOST_CRASHDUMP_LOGS, HOST_CRASHDUMPS_DIR,
624 HOST_CRASHDUMP_LOGS_RE, False)
626 file_output(CAP_KERNEL_INFO, [PROC_VERSION, PROC_MODULES, PROC_DEVICES,
627 PROC_FILESYSTEMS, PROC_CMDLINE])
628 cmd_output(CAP_KERNEL_INFO, [ZCAT, PROC_CONFIG], label='config')
629 cmd_output(CAP_KERNEL_INFO, [SYSCTL, '-A'])
630 file_output(CAP_KERNEL_INFO, [MODPROBE_CONF])
631 tree_output(CAP_KERNEL_INFO, MODPROBE_DIR)
633 cmd_output(CAP_LOSETUP_A, [LOSETUP, '-a'])
635 file_output(CAP_MULTIPATH, [MULTIPATH_CONF])
636 cmd_output(CAP_MULTIPATH, [DMSETUP, 'status'])
637 func_output(CAP_MULTIPATH, 'multipathd_topology', multipathd_topology)
639 tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, IFCFG_RE)
640 tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, ROUTE_RE)
641 file_output(CAP_NETWORK_CONFIG, [SYSCONFIG_NETWORK, RESOLV_CONF, NSSWITCH_CONF])
642 file_output(CAP_NETWORK_CONFIG, [NTP_CONF, IPTABLES_CONFIG, HOSTS_ALLOW, HOSTS_DENY])
644 cmd_output(CAP_NETWORK_STATUS, [IFCONFIG, '-a'])
645 cmd_output(CAP_NETWORK_STATUS, [ROUTE, '-n'])
646 cmd_output(CAP_NETWORK_STATUS, [ARP, '-n'])
647 cmd_output(CAP_NETWORK_STATUS, [NETSTAT, '-an'])
648 tree_output(CAP_NETWORK_STATUS, DHCP_LEASE_DIR)
649 cmd_output(CAP_NETWORK_STATUS, [IPTABLES, '-nL'])
650 cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'show'])
651 cmd_output(CAP_NETWORK_STATUS, [BIOSDEVNAME, '-d'])
652 for p in os.listdir('/sys/class/net/'):
653 if os.path.isdir('/sys/class/net/%s/bridge' % p):
654 cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'showmacs', p])
657 f = open('/sys/class/net/%s/type' % p, 'r')
662 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, p])
663 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-S', p])
664 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-k', p])
665 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-i', p])
666 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-c', p])
669 tree_output(CAP_NETWORK_STATUS, PROC_NET_BONDING_DIR)
670 tree_output(CAP_NETWORK_STATUS, PROC_NET_VLAN_DIR)
671 cmd_output(CAP_NETWORK_STATUS, [TC, '-s', 'qdisc'])
672 file_output(CAP_NETWORK_STATUS, [PROC_NET_SOFTNET_STAT])
674 tree_output(CAP_OEM, DELL_OMSA_LOGS)
675 file_output(CAP_OEM, [HP_CMA_LOG, HP_HPASMD_LOG])
676 if os.path.exists(OMREPORT):
677 cmd_output(CAP_OEM, [OMREPORT, 'system', 'alertlog'])
678 cmd_output(CAP_OEM, [OMREPORT, 'system', 'cmdlog'])
679 cmd_output(CAP_OEM, [OMREPORT, 'system', 'esmlog'])
680 cmd_output(CAP_OEM, [OMREPORT, 'system', 'postlog'])
681 cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'fans'])
682 cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'memory'])
683 cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'temps'])
684 cmd_output(CAP_OEM, [OMREPORT, 'storage', 'controller'])
685 for i in range(0, 4):
686 cmd_output(CAP_OEM, [OMREPORT, 'storage', 'adisk', 'controller=%d' % i])
687 cmd_output(CAP_OEM, [OMREPORT, 'storage', 'vdisk', 'controller=%d' % i])
688 cmd_output(CAP_OEM, [FIND, '/.state', '-size', '+20k', '-exec', 'ls', '-l', '{}',';'],
691 tree_output(CAP_PAM, PAM_DIR)
693 func_output(CAP_PERSISTENT_STATS, 'xapi_rrd-host', dump_xapi_rrds)
695 cmd_output(CAP_PROCESS_LIST, [PS, 'wwwaxf', '-eo', 'pid,tty,stat,time,nice,psr,pcpu,pmem,wchan:25,args'], label='process-tree')
697 file_output(CAP_SYSTEM_LOGS,
698 [ VAR_LOG_DIR + x for x in
699 [ 'syslog', 'messages', 'monitor_memory.log', 'secure', 'debug', 'dmesg', 'boot.msg' ] +
700 [ f % n for n in range(1, 20) \
701 for f in ['messages.%d', 'messages.%d.gz', 'monitor_memory.log.%d',
702 'monitor_memory.log.%d.gz', 'secure.%d', 'secure.%d.gz']]])
703 if not os.path.exists('/var/log/dmesg') and not os.path.exists('/var/log/boot.msg'):
704 cmd_output(CAP_SYSTEM_LOGS, [DMESG])
706 cmd_output(CAP_SYSTEM_SERVICES, [CHKCONFIG, '--list'])
708 if CAP_TAPDISK_LOGS in entries:
709 generate_tapdisk_logs()
711 tree_output(CAP_VNCTERM, VNCTERM_CORE_DIR)
713 file_output(CAP_VSWITCH_CONFIG, [OVS_VSWITCH_CONF])
714 file_output(CAP_VSWITCH_CONFIG, [OVS_VSWITCH_DBCACHE])
716 file_output(CAP_VSWITCH_LOGS,
717 [ VAR_LOG_DIR + x for x in
718 [ 'ovs-brcompatd.log', 'ovs-vswitchd.log', 'ovsdb-server.log', 'vswitch-cfg-update.log', 'vswitch-xsplugin.log' ] +
719 [ f % n for n in range(1, 20) \
720 for f in ['ovs-brcompatd.log.%d', 'ovs-brcompatd.log.%d.gz',
721 'ovs-vswitchd.log.%d', 'ovs-vswitchd.log.%d.gz',
722 'ovsdb-server.log.%d', 'ovsdb-server.log.%d.gz']]])
724 cmd_output(CAP_VSWITCH_STATUS, [OVS_DPCTL, 'show'])
725 tree_output(CAP_VSWITCH_STATUS, VSWITCH_CORE_DIR)
727 cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'show', d])
728 cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'status', d])
729 cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'dump-flows', d])
730 cmd_output(CAP_VSWITCH_STATUS, [OVS_DPCTL, 'dump-flows', d])
732 cmd_output(CAP_WLB, [XE, 'pool-retrieve-wlb-diagnostics'])
734 tree_output(CAP_X11_LOGS, X11_LOGS_DIR, X11_LOGS_RE)
735 tree_output(CAP_X11_AUTH, X11_AUTH_DIR, X11_AUTH_RE)
737 tree_output(CAP_XAPI_DEBUG, XAPI_DEBUG_DIR)
739 func_output(CAP_XAPI_SUBPROCESS, 'xapi_subprocesses', dump_xapi_subprocess_info)
741 file_output(CAP_XENSERVER_CONFIG, [INITIAL_INVENTORY])
742 file_output(CAP_XENSERVER_CONFIG, [POOL_CONF, PTOKEN, XAPI_CONF, XAPI_SSL_CONF, STATIC_VDIS,
743 XENSOURCE_INVENTORY, VENDORKERNEL_INVENTORY])
744 cmd_output(CAP_XENSERVER_CONFIG, [LS, '-lR', '/opt/xensource'])
745 cmd_output(CAP_XENSERVER_CONFIG, [BIN_STATIC_VDIS, 'list'])
746 tree_output(CAP_XENSERVER_CONFIG, OEM_CONFIG_DIR, OEM_CONFIG_FILES_RE)
748 func_output(CAP_XENSERVER_DATABASES, 'xapi-db.xml', dump_filtered_xapi_db)
749 cmd_output(CAP_XENSERVER_DATABASES, [XENSTORE_LS])
750 file_output(CAP_XENSERVER_DATABASES, [DB_CONF, DB_CONF_RIO, DB_DEFAULT_FIELDS, DB_SCHEMA_SQL])
751 tree_output(CAP_XENSERVER_DATABASES, OEM_CONFIG_DIR, OEM_DB_FILES_RE)
752 file_output(CAP_XENSERVER_DATABASES, [XENSTORED_DB, XENSTORED_DB + '.bak'])
753 cmd_output(CAP_XENSERVER_DATABASES, [XE, 'pool-dump-database', 'file-name='],
754 label="xapi-db-dumped.xml", filter=filter_db_pii)
755 cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'watches'])
756 cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'quotas'])
758 cmd_output(CAP_XENSERVER_DOMAINS, [LIST_DOMAINS])
760 tree_output(CAP_XENSERVER_INSTALL, VAR_LOG_DIR + 'installer')
761 file_output(CAP_XENSERVER_INSTALL,
762 [ VAR_LOG_DIR + x for x in
763 [ 'firstboot-SR-commands-log',
764 'upgrade-commands-log', 'generate-iscsi-iqn-log']] +
765 [ '/root/' + x for x in
766 [ 'blockdevs-log', 'cmdline-log', 'devcontents-log',
767 'dmesg-log', 'install-log', 'lspci-log', 'modules-log',
768 'pci-log', 'processes-log', 'tty-log', 'uname-log',
770 tree_output(CAP_XENSERVER_INSTALL, INSTALLED_REPOS_DIR)
771 tree_output(CAP_XENSERVER_INSTALL, PATCH_APPLIED_DIR)
773 file_output(CAP_XENSERVER_LOGS, [LOG_CONF])
774 file_output(CAP_XENSERVER_LOGS, XENSERVER_LOGS)
775 tree_output(CAP_XENSERVER_LOGS, OEM_CONFIG_DIR, OEM_XENSERVER_LOGS_RE)
779 data = xc.readconsolering()
780 xc.send_debug_keys('q')
784 xc = xen.lowlevel.xc.xc()
786 func_output(CAP_XEN_INFO, 'xen-dmesg', lambda x: xen_dmesg(xc))
787 func_output(CAP_XEN_INFO, 'physinfo', lambda x: prettyDict(xc.physinfo()))
788 func_output(CAP_XEN_INFO, 'xeninfo', lambda x: prettyDict(xc.xeninfo()))
791 file_output(CAP_XEN_INFO, [PROC_XEN_BALLOON])
793 cmd_output(CAP_XHA_LIVESET, [HA_QUERY_LIVESET])
795 file_output(CAP_YUM, [YUM_LOG])
796 tree_output(CAP_YUM, YUM_REPOS_DIR)
797 cmd_output(CAP_YUM, [RPM, '-qa'])
799 # permit the user to filter out data
800 for k in sorted(data.keys()):
801 if not ANSWER_YES_TO_ALL and not yes("Include '%s'? [Y/n]: " % k):
804 # collect selected data now
805 output_ts('Running commands to collect data')
808 subdir = os.getenv('XENRT_BUGTOOL_BASENAME')
810 subdir = os.path.basename(subdir)
811 if subdir == '..' or subdir == '.':
814 subdir = "bug-report-%s" % time.strftime("%Y%m%d%H%M%S")
817 data['inventory.xml'] = {'cap': None, 'output': StringIOmtime(make_inventory(data, subdir))}
820 if output_fd == -1 and not os.path.exists(BUG_DIR):
827 output_ts('Creating output file')
829 if output_type.startswith('tar'):
830 make_tar(subdir, output_type, output_fd)
837 print >>sys.stderr, "Category sizes (max, actual):\n"
838 for c in caps.keys():
839 print >>sys.stderr, " %s (%d, %d)" % (c, caps[c][MAX_SIZE],
843 def generate_tapdisk_logs():
844 for pid in pidof('tapdisk'):
846 os.kill(pid, SIGUSR1)
847 output_ts("Including logs for tapdisk process %d" % pid)
850 # give processes a second to write their logs
852 file_output(CAP_TAPDISK_LOGS, ['/tmp/tapdisk.log.%d' % pid for pid in pidof('tapdisk')])
854 def clean_tapdisk_logs():
855 for filename in [f for f in os.listdir('/tmp') if f.startswith('tapdisk.log.')]:
857 os.remove(os.path.join('tmp', filename))
861 def dump_xapi_subprocess_info(cap):
862 """Check which fds are open by xapi and its subprocesses to diagnose faults like CA-10543.
863 Returns a string containing a pretty-printed pstree-like structure. """
864 pids = filter(lambda x: x.isdigit(), os.listdir("/proc"))
865 def readlines(filename):
868 f = open(filename, "r")
869 lines = f.readlines()
875 all = readlines("/proc/" + pid + "/cmdline")
879 return all[0].replace('\x00', ' ')
881 for i in readlines("/proc/" + pid + "/status"):
882 if i.startswith("PPid:"):
886 result = { "cmdline": cmdline(pid) }
887 child_pids = filter(lambda x:parent(x) == pid, pids)
889 for child in child_pids:
890 children[child] = pstree(child)
891 result['children'] = children
893 for fd in os.listdir("/proc/" + pid + "/fd"):
895 fds[fd] = os.readlink("/proc/" + pid + "/fd/" + fd)
900 xapis = filter(lambda x: cmdline(x).startswith("/opt/xensource/bin/xapi"), pids)
901 xapis = filter(lambda x: parent(x) == "1", xapis)
904 result[xapi] = pstree(xapi)
905 pp = pprint.PrettyPrinter(indent=4)
906 return pp.pformat(result)
908 def dump_xapi_rrds(cap):
909 socket.setdefaulttimeout(5)
910 session = XenAPI.xapi_local()
911 session.xenapi.login_with_password('', '')
912 this_host = session.xenapi.session.get_this_host(session._session)
913 # better way to find pool master?
914 pool = session.xenapi.pool.get_all_records().values()[0]
915 i_am_master = (this_host == pool['master'])
917 for vm in session.xenapi.VM.get_all_records().values():
918 if vm['is_a_template']:
920 if vm['resident_on'] == this_host or (i_am_master and vm['power_state'] in ['Suspended', 'Halted']):
921 rrd = urllib.urlopen('http://localhost/vm_rrd?session_id=%s&uuid=%s' % (session._session, vm['uuid']))
923 (i, o, x) = select([rrd], [], [], 5.0)
925 data['xapi_rrd-%s' % vm['uuid']] = {'cap': cap,
926 'output': StringIOmtime(rrd.read())}
931 rrd = urllib.urlopen('http://localhost/host_rrd?session_id=%s' % session._session)
938 session.xenapi.session.logout()
941 def filter_db_pii(str):
942 str = re.sub(r'(password_transformed" ")[^ ]+(")', r'\1REMOVED\2', str)
943 str = re.sub(r'(wlb_password=")[^"]+(")', r'\1REMOVED\2', str)
946 def dump_filtered_xapi_db(cap):
950 # determine db format
951 c = open(DB_CONF, 'r')
954 l = line.rstrip('\n')
955 if l.startswith('['):
957 if l.startswith('format:'):
967 if format == 'sqlite':
968 pipe = Popen([XAPI_DB_PROCESS, '-xmltostdout'], bufsize=1, stdin=dev_null,
969 stdout=PIPE, stderr=dev_null)
972 ih = open(db_file, 'r')
984 remain = remain[p+1:]
985 output += filter_db_pii(str)
996 def dump_scsi_hosts(cap):
998 l = os.listdir('/sys/class/scsi_host')
1004 f = open('/sys/class/scsi_host/%s/proc_name' % h)
1005 procname = f.readline().strip("\n")
1011 f = open('/sys/class/scsi_host/%s/model_name' % h)
1012 modelname = f.readline().strip("\n")
1017 output += "%s:\n" %h
1018 output += " %s%s\n" % (procname, modelname and (" -> %s" % modelname) or '')
1023 socket.setdefaulttimeout(5)
1024 session = XenAPI.xapi_local()
1025 session.xenapi.login_with_password('', '')
1026 this_host = session.xenapi.session.get_this_host(session._session)
1027 # better way to find pool master?
1028 pool = session.xenapi.pool.get_all_records().values()[0]
1029 i_am_master = (this_host == pool['master'])
1031 output = StringIO.StringIO()
1034 def rotate_string(x, n):
1036 for a in range(0, 256):
1037 transtbl = transtbl + chr(a)
1038 transtbl = transtbl[n:] + transtbl[0:n]
1039 return x.translate(transtbl)
1041 def _untransform_string(str, remove_trailing_nulls=False):
1042 """De-obfuscate string. To cope with an obfuscation bug in Rio, the argument
1043 remove_trailing_nulls should be set to True"""
1044 tmp = base64.decodestring(str)
1045 if remove_trailing_nulls:
1046 tmp = tmp.rstrip('\x00')
1047 return rotate_string(tmp, -13)
1049 for pbd in session.xenapi.PBD.get_all_records().values():
1050 if pbd.has_key('device_config') and pbd['device_config'].has_key('target'):
1051 sr = session.xenapi.SR.get_record(pbd['SR'])
1052 if sr.has_key('type') and sr['type'] == 'cslg':
1053 if sr['shared'] and pbd['host'] != this_host and not i_am_master:
1056 dev_cfg = pbd['device_config']
1057 server = "server=%s" % socket.gethostbyname(dev_cfg['target'])
1058 if dev_cfg.has_key('port'):
1059 server += ':' + dev_cfg['port']
1060 if dev_cfg.has_key('username'):
1061 server += ',' + dev_cfg['username']
1062 if dev_cfg.has_key('password_transformed'):
1063 server += ',' + _untransform_string(dev_cfg['password_transformed'])
1064 procs.append(ProcOutput([CSL, server, 'srv-log-get'], caps[cap][MAX_TIME], output))
1066 session.xenapi.session.logout()
1070 return output.getvalue()
1072 def multipathd_topology(cap):
1073 pipe = Popen([MULTIPATHD, '-k'], bufsize=1, stdin=PIPE,
1074 stdout=PIPE, stderr=dev_null)
1075 stdout, stderr = pipe.communicate('show topology')
1079 def make_tar(subdir, suffix, output_fd):
1080 global SILENT_MODE, data
1083 if suffix == 'tar.bz2':
1085 filename = "%s/%s.%s" % (BUG_DIR, subdir, suffix)
1088 tf = tarfile.open(filename, mode)
1090 tf = tarfile.open(None, 'w', os.fdopen(output_fd, 'a'))
1093 for (k, v) in data.items():
1095 tar_filename = os.path.join(subdir, construct_filename(k, v))
1096 ti = tarfile.TarInfo(tar_filename)
1101 if v.has_key('output'):
1102 ti.mtime = v['output'].mtime
1103 ti.size = len(v['output'].getvalue())
1105 tf.addfile(ti, v['output'])
1106 elif v.has_key('filename'):
1107 s = os.stat(v['filename'])
1108 ti.mtime = s.st_mtime
1110 tf.addfile(ti, file(v['filename']))
1117 output ('Writing tarball %s successful.' % filename)
1122 def make_zip(subdir):
1123 global SILENT_MODE, data
1125 filename = "%s/%s.zip" % (BUG_DIR, subdir)
1126 zf = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED)
1129 for (k, v) in data.items():
1131 dest = os.path.join(subdir, construct_filename(k, v))
1133 if v.has_key('output'):
1134 zf.writestr(dest, v['output'].getvalue())
1136 if os.stat(v['filename']).st_size < 50:
1137 compress_type = zipfile.ZIP_STORED
1139 compress_type = zipfile.ZIP_DEFLATED
1140 zf.write(v['filename'], dest, compress_type)
1146 output ('Writing archive %s successful.' % filename)
1151 def make_inventory(inventory, subdir):
1152 document = getDOMImplementation().createDocument(
1153 None, INVENTORY_XML_ROOT, None)
1155 # create summary entry
1156 s = document.createElement(INVENTORY_XML_SUMMARY)
1157 user = os.getenv('SUDO_USER', os.getenv('USER'))
1159 s.setAttribute('user', user)
1160 s.setAttribute('date', time.strftime('%c'))
1161 s.setAttribute('hostname', platform.node())
1162 s.setAttribute('uname', ' '.join(platform.uname()))
1163 s.setAttribute('uptime', commands.getoutput(UPTIME))
1164 document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(s)
1166 map(lambda (k, v): inventory_entry(document, subdir, k, v),
1168 return document.toprettyxml()
1170 def inventory_entry(document, subdir, k, v):
1172 el = document.createElement(INVENTORY_XML_ELEMENT)
1173 el.setAttribute('capability', v['cap'])
1174 el.setAttribute('filename', os.path.join(subdir, construct_filename(k, v)))
1175 el.setAttribute('md5sum', md5sum(v))
1176 document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(el)
1183 if d.has_key('filename'):
1184 f = open(d['filename'])
1186 while len(data) > 0:
1190 elif d.has_key('output'):
1191 m.update(d['output'].getvalue())
1192 return m.hexdigest()
1195 def construct_filename(k, v):
1196 if v.has_key('filename'):
1197 if v['filename'][0] == '/':
1198 return v['filename'][1:]
1200 return v['filename']
1201 s = k.replace(' ', '-')
1202 s = s.replace('--', '-')
1203 s = s.replace('/', '%')
1204 if s.find('.') == -1:
1210 def update_capabilities():
1211 update_cap_size(CAP_HOST_CRASHDUMP_LOGS,
1212 size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE))
1213 update_cap_size(CAP_HOST_CRASHDUMP_DUMPS,
1214 size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE,
1216 update_cap_size(CAP_XAPI_DEBUG, size_of_dir(XAPI_DEBUG_DIR))
1217 update_cap_size(CAP_XENSERVER_LOGS, size_of_all(XENSERVER_LOGS))
1220 def update_cap_size(cap, size):
1221 update_cap(cap, MIN_SIZE, size)
1222 update_cap(cap, MAX_SIZE, size)
1223 update_cap(cap, CHECKED, size > 0)
1226 def update_cap(cap, k, v):
1230 caps[cap] = tuple(l)
1233 def size_of_dir(d, pattern = None, negate = False):
1234 if os.path.isdir(d):
1235 return size_of_all([os.path.join(d, fn) for fn in os.listdir(d)],
1241 def size_of_all(files, pattern = None, negate = False):
1242 return sum([size_of(f, pattern, negate) for f in files])
1245 def matches(f, pattern, negate):
1247 return not matches(f, pattern, False)
1249 return pattern is None or pattern.match(f)
1252 def size_of(f, pattern, negate):
1253 if os.path.isfile(f) and matches(f, pattern, negate):
1254 return os.stat(f)[6]
1256 return size_of_dir(f, pattern, negate)
1259 def print_capabilities():
1260 document = getDOMImplementation().createDocument(
1261 "ns", CAP_XML_ROOT, None)
1262 map(lambda key: capability(document, key), caps.keys())
1263 print document.toprettyxml()
1265 def capability(document, key):
1267 el = document.createElement(CAP_XML_ELEMENT)
1268 el.setAttribute('key', c[KEY])
1269 el.setAttribute('pii', c[PII])
1270 el.setAttribute('min-size', str(c[MIN_SIZE]))
1271 el.setAttribute('max-size', str(c[MAX_SIZE]))
1272 el.setAttribute('min-time', str(c[MIN_TIME]))
1273 el.setAttribute('max-time', str(c[MAX_TIME]))
1274 el.setAttribute('content-type', c[MIME])
1275 el.setAttribute('default-checked', c[CHECKED] and 'yes' or 'no')
1276 document.getElementsByTagName(CAP_XML_ROOT)[0].appendChild(el)
1280 format = '%%-%ds: %%s' % max(map(len, [k for k, _ in d.items()]))
1281 return '\n'.join([format % i for i in d.items()]) + '\n'
1285 yn = raw_input(prompt)
1287 return len(yn) == 0 or yn.lower()[0] == 'y'
1290 partition_re = re.compile(r'(.*[0-9]+$)|(^xvd)')
1293 command = [OVS_DPCTL, "dump-dps"]
1294 proc = Popen(command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null)
1295 (dps, err) = proc.communicate()
1296 return dps.splitlines()
1302 f = open('/proc/partitions')
1305 for line in f.readlines():
1306 (major, minor, blocks, name) = line.split()
1307 if int(major) < 254 and not partition_re.match(name):
1317 def __init__(self, command, max_time, inst=None, filter=None):
1318 self.command = command
1319 self.max_time = max_time
1321 self.running = False
1323 self.timed_out = False
1325 self.timeout = int(time.time()) + self.max_time
1326 self.filter = filter
1332 self.timed_out = False
1334 if ProcOutput.debug:
1335 output_ts("Starting '%s'" % ' '.join(self.command))
1336 self.proc = Popen(self.command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null)
1337 old = fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_GETFD)
1338 fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
1342 output_ts("'%s' failed" % ' '.join(self.command))
1343 self.running = False
1346 def terminate(self):
1349 os.kill(self.proc.pid, SIGTERM)
1353 self.running = False
1354 self.status = SIGTERM
1356 def read_line(self):
1358 line = self.proc.stdout.readline()
1361 self.status = self.proc.wait()
1363 self.running = False
1366 line = self.filter(line)
1368 self.inst.write(line)
1370 def run_procs(procs):
1378 active_procs.append(p)
1379 pipes.append(p.proc.stdout)
1381 elif p.status == None and not p.failed and not p.timed_out:
1384 active_procs.append(p)
1385 pipes.append(p.proc.stdout)
1392 (i, o, x) = select(pipes, [], [], 1.0)
1393 now = int(time.time())
1395 # handle process output
1396 for p in active_procs:
1397 if p.proc.stdout in i:
1401 if p.running and now > p.timeout:
1402 output_ts("'%s' timed out" % ' '.join(p.command))
1404 p.inst.write("\n** timeout **\n")
1412 for d in [p for p in os.listdir('/proc') if p.isdigit()]:
1414 if os.path.basename(os.readlink('/proc/%s/exe' % d)) == name:
1422 def readKeyValueFile(filename, allowed_keys = None, strip_quotes = True, assert_quotes = True):
1423 """ Reads a KEY=Value style file (e.g. xensource-inventory). Returns a
1424 dictionary of key/values in the file. Not designed for use with large files
1425 as the file is read entirely into memory."""
1427 f = open(filename, "r")
1428 lines = [x.strip("\n") for x in f.readlines()]
1431 # remove lines contain
1433 lines = filter(lambda x: True in [x.startswith(y) for y in allowed_keys],
1436 defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ]
1441 assert x.startswith("'") and x.endswith("'")
1443 defs = [ (a, quotestrip(b)) for (a,b) in defs ]
1448 class StringIOmtime(StringIO.StringIO):
1449 def __init__(self, buf = ''):
1450 StringIO.StringIO.__init__(self, buf)
1451 self.mtime = time.time()
1454 StringIO.StringIO.write(self, s)
1455 self.mtime = time.time()
1458 if __name__ == "__main__":
1461 except KeyboardInterrupt:
1462 print "\nInterrupted."