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'
124 OVS_VSWITCH_DBCACHE = '/etc/ovs-vswitch.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 = '/root/vswitch/bin/ovs-dpctl'
200 OVS_OFCTL = '/root/vswitch/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', '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']]])
723 cmd_output(CAP_VSWITCH_STATUS, [OVS_DPCTL, 'show'])
724 tree_output(CAP_VSWITCH_STATUS, VSWITCH_CORE_DIR)
726 cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'show', d])
727 cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'status', d])
728 cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'dump-flows', d])
729 cmd_output(CAP_VSWITCH_STATUS, [OVS_DPCTL, 'dump-flows', d])
731 cmd_output(CAP_WLB, [XE, 'pool-retrieve-wlb-diagnostics'])
733 tree_output(CAP_X11_LOGS, X11_LOGS_DIR, X11_LOGS_RE)
734 tree_output(CAP_X11_AUTH, X11_AUTH_DIR, X11_AUTH_RE)
736 tree_output(CAP_XAPI_DEBUG, XAPI_DEBUG_DIR)
738 func_output(CAP_XAPI_SUBPROCESS, 'xapi_subprocesses', dump_xapi_subprocess_info)
740 file_output(CAP_XENSERVER_CONFIG, [INITIAL_INVENTORY])
741 file_output(CAP_XENSERVER_CONFIG, [POOL_CONF, PTOKEN, XAPI_CONF, XAPI_SSL_CONF, STATIC_VDIS,
742 XENSOURCE_INVENTORY, VENDORKERNEL_INVENTORY])
743 cmd_output(CAP_XENSERVER_CONFIG, [LS, '-lR', '/opt/xensource'])
744 cmd_output(CAP_XENSERVER_CONFIG, [BIN_STATIC_VDIS, 'list'])
745 tree_output(CAP_XENSERVER_CONFIG, OEM_CONFIG_DIR, OEM_CONFIG_FILES_RE)
747 func_output(CAP_XENSERVER_DATABASES, 'xapi-db.xml', dump_filtered_xapi_db)
748 cmd_output(CAP_XENSERVER_DATABASES, [XENSTORE_LS])
749 file_output(CAP_XENSERVER_DATABASES, [DB_CONF, DB_CONF_RIO, DB_DEFAULT_FIELDS, DB_SCHEMA_SQL])
750 tree_output(CAP_XENSERVER_DATABASES, OEM_CONFIG_DIR, OEM_DB_FILES_RE)
751 file_output(CAP_XENSERVER_DATABASES, [XENSTORED_DB, XENSTORED_DB + '.bak'])
752 cmd_output(CAP_XENSERVER_DATABASES, [XE, 'pool-dump-database', 'file-name='],
753 label="xapi-db-dumped.xml", filter=filter_db_pii)
754 cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'watches'])
755 cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'quotas'])
757 cmd_output(CAP_XENSERVER_DOMAINS, [LIST_DOMAINS])
759 tree_output(CAP_XENSERVER_INSTALL, VAR_LOG_DIR + 'installer')
760 file_output(CAP_XENSERVER_INSTALL,
761 [ VAR_LOG_DIR + x for x in
762 [ 'firstboot-SR-commands-log',
763 'upgrade-commands-log', 'generate-iscsi-iqn-log']] +
764 [ '/root/' + x for x in
765 [ 'blockdevs-log', 'cmdline-log', 'devcontents-log',
766 'dmesg-log', 'install-log', 'lspci-log', 'modules-log',
767 'pci-log', 'processes-log', 'tty-log', 'uname-log',
769 tree_output(CAP_XENSERVER_INSTALL, INSTALLED_REPOS_DIR)
770 tree_output(CAP_XENSERVER_INSTALL, PATCH_APPLIED_DIR)
772 file_output(CAP_XENSERVER_LOGS, [LOG_CONF])
773 file_output(CAP_XENSERVER_LOGS, XENSERVER_LOGS)
774 tree_output(CAP_XENSERVER_LOGS, OEM_CONFIG_DIR, OEM_XENSERVER_LOGS_RE)
778 data = xc.readconsolering()
779 xc.send_debug_keys('q')
783 xc = xen.lowlevel.xc.xc()
785 func_output(CAP_XEN_INFO, 'xen-dmesg', lambda x: xen_dmesg(xc))
786 func_output(CAP_XEN_INFO, 'physinfo', lambda x: prettyDict(xc.physinfo()))
787 func_output(CAP_XEN_INFO, 'xeninfo', lambda x: prettyDict(xc.xeninfo()))
790 file_output(CAP_XEN_INFO, [PROC_XEN_BALLOON])
792 cmd_output(CAP_XHA_LIVESET, [HA_QUERY_LIVESET])
794 file_output(CAP_YUM, [YUM_LOG])
795 tree_output(CAP_YUM, YUM_REPOS_DIR)
796 cmd_output(CAP_YUM, [RPM, '-qa'])
798 # permit the user to filter out data
799 for k in sorted(data.keys()):
800 if not ANSWER_YES_TO_ALL and not yes("Include '%s'? [Y/n]: " % k):
803 # collect selected data now
804 output_ts('Running commands to collect data')
807 subdir = os.getenv('XENRT_BUGTOOL_BASENAME')
809 subdir = os.path.basename(subdir)
810 if subdir == '..' or subdir == '.':
813 subdir = "bug-report-%s" % time.strftime("%Y%m%d%H%M%S")
816 data['inventory.xml'] = {'cap': None, 'output': StringIOmtime(make_inventory(data, subdir))}
819 if output_fd == -1 and not os.path.exists(BUG_DIR):
826 output_ts('Creating output file')
828 if output_type.startswith('tar'):
829 make_tar(subdir, output_type, output_fd)
836 print >>sys.stderr, "Category sizes (max, actual):\n"
837 for c in caps.keys():
838 print >>sys.stderr, " %s (%d, %d)" % (c, caps[c][MAX_SIZE],
842 def generate_tapdisk_logs():
843 for pid in pidof('tapdisk'):
845 os.kill(pid, SIGUSR1)
846 output_ts("Including logs for tapdisk process %d" % pid)
849 # give processes a second to write their logs
851 file_output(CAP_TAPDISK_LOGS, ['/tmp/tapdisk.log.%d' % pid for pid in pidof('tapdisk')])
853 def clean_tapdisk_logs():
854 for filename in [f for f in os.listdir('/tmp') if f.startswith('tapdisk.log.')]:
856 os.remove(os.path.join('tmp', filename))
860 def dump_xapi_subprocess_info(cap):
861 """Check which fds are open by xapi and its subprocesses to diagnose faults like CA-10543.
862 Returns a string containing a pretty-printed pstree-like structure. """
863 pids = filter(lambda x: x.isdigit(), os.listdir("/proc"))
864 def readlines(filename):
867 f = open(filename, "r")
868 lines = f.readlines()
874 all = readlines("/proc/" + pid + "/cmdline")
878 return all[0].replace('\x00', ' ')
880 for i in readlines("/proc/" + pid + "/status"):
881 if i.startswith("PPid:"):
885 result = { "cmdline": cmdline(pid) }
886 child_pids = filter(lambda x:parent(x) == pid, pids)
888 for child in child_pids:
889 children[child] = pstree(child)
890 result['children'] = children
892 for fd in os.listdir("/proc/" + pid + "/fd"):
894 fds[fd] = os.readlink("/proc/" + pid + "/fd/" + fd)
899 xapis = filter(lambda x: cmdline(x).startswith("/opt/xensource/bin/xapi"), pids)
900 xapis = filter(lambda x: parent(x) == "1", xapis)
903 result[xapi] = pstree(xapi)
904 pp = pprint.PrettyPrinter(indent=4)
905 return pp.pformat(result)
907 def dump_xapi_rrds(cap):
908 socket.setdefaulttimeout(5)
909 session = XenAPI.xapi_local()
910 session.xenapi.login_with_password('', '')
911 this_host = session.xenapi.session.get_this_host(session._session)
912 # better way to find pool master?
913 pool = session.xenapi.pool.get_all_records().values()[0]
914 i_am_master = (this_host == pool['master'])
916 for vm in session.xenapi.VM.get_all_records().values():
917 if vm['is_a_template']:
919 if vm['resident_on'] == this_host or (i_am_master and vm['power_state'] in ['Suspended', 'Halted']):
920 rrd = urllib.urlopen('http://localhost/vm_rrd?session_id=%s&uuid=%s' % (session._session, vm['uuid']))
922 (i, o, x) = select([rrd], [], [], 5.0)
924 data['xapi_rrd-%s' % vm['uuid']] = {'cap': cap,
925 'output': StringIOmtime(rrd.read())}
930 rrd = urllib.urlopen('http://localhost/host_rrd?session_id=%s' % session._session)
937 session.xenapi.session.logout()
940 def filter_db_pii(str):
941 str = re.sub(r'(password_transformed" ")[^ ]+(")', r'\1REMOVED\2', str)
942 str = re.sub(r'(wlb_password=")[^"]+(")', r'\1REMOVED\2', str)
945 def dump_filtered_xapi_db(cap):
949 # determine db format
950 c = open(DB_CONF, 'r')
953 l = line.rstrip('\n')
954 if l.startswith('['):
956 if l.startswith('format:'):
966 if format == 'sqlite':
967 pipe = Popen([XAPI_DB_PROCESS, '-xmltostdout'], bufsize=1, stdin=dev_null,
968 stdout=PIPE, stderr=dev_null)
971 ih = open(db_file, 'r')
983 remain = remain[p+1:]
984 output += filter_db_pii(str)
995 def dump_scsi_hosts(cap):
997 l = os.listdir('/sys/class/scsi_host')
1003 f = open('/sys/class/scsi_host/%s/proc_name' % h)
1004 procname = f.readline().strip("\n")
1010 f = open('/sys/class/scsi_host/%s/model_name' % h)
1011 modelname = f.readline().strip("\n")
1016 output += "%s:\n" %h
1017 output += " %s%s\n" % (procname, modelname and (" -> %s" % modelname) or '')
1022 socket.setdefaulttimeout(5)
1023 session = XenAPI.xapi_local()
1024 session.xenapi.login_with_password('', '')
1025 this_host = session.xenapi.session.get_this_host(session._session)
1026 # better way to find pool master?
1027 pool = session.xenapi.pool.get_all_records().values()[0]
1028 i_am_master = (this_host == pool['master'])
1030 output = StringIO.StringIO()
1033 def rotate_string(x, n):
1035 for a in range(0, 256):
1036 transtbl = transtbl + chr(a)
1037 transtbl = transtbl[n:] + transtbl[0:n]
1038 return x.translate(transtbl)
1040 def _untransform_string(str, remove_trailing_nulls=False):
1041 """De-obfuscate string. To cope with an obfuscation bug in Rio, the argument
1042 remove_trailing_nulls should be set to True"""
1043 tmp = base64.decodestring(str)
1044 if remove_trailing_nulls:
1045 tmp = tmp.rstrip('\x00')
1046 return rotate_string(tmp, -13)
1048 for pbd in session.xenapi.PBD.get_all_records().values():
1049 if pbd.has_key('device_config') and pbd['device_config'].has_key('target'):
1050 sr = session.xenapi.SR.get_record(pbd['SR'])
1051 if sr.has_key('type') and sr['type'] == 'cslg':
1052 if sr['shared'] and pbd['host'] != this_host and not i_am_master:
1055 dev_cfg = pbd['device_config']
1056 server = "server=%s" % socket.gethostbyname(dev_cfg['target'])
1057 if dev_cfg.has_key('port'):
1058 server += ':' + dev_cfg['port']
1059 if dev_cfg.has_key('username'):
1060 server += ',' + dev_cfg['username']
1061 if dev_cfg.has_key('password_transformed'):
1062 server += ',' + _untransform_string(dev_cfg['password_transformed'])
1063 procs.append(ProcOutput([CSL, server, 'srv-log-get'], caps[cap][MAX_TIME], output))
1065 session.xenapi.session.logout()
1069 return output.getvalue()
1071 def multipathd_topology(cap):
1072 pipe = Popen([MULTIPATHD, '-k'], bufsize=1, stdin=PIPE,
1073 stdout=PIPE, stderr=dev_null)
1074 stdout, stderr = pipe.communicate('show topology')
1078 def make_tar(subdir, suffix, output_fd):
1079 global SILENT_MODE, data
1082 if suffix == 'tar.bz2':
1084 filename = "%s/%s.%s" % (BUG_DIR, subdir, suffix)
1087 tf = tarfile.open(filename, mode)
1089 tf = tarfile.open(None, 'w', os.fdopen(output_fd, 'a'))
1092 for (k, v) in data.items():
1094 tar_filename = os.path.join(subdir, construct_filename(k, v))
1095 ti = tarfile.TarInfo(tar_filename)
1100 if v.has_key('output'):
1101 ti.mtime = v['output'].mtime
1102 ti.size = len(v['output'].getvalue())
1104 tf.addfile(ti, v['output'])
1105 elif v.has_key('filename'):
1106 s = os.stat(v['filename'])
1107 ti.mtime = s.st_mtime
1109 tf.addfile(ti, file(v['filename']))
1116 output ('Writing tarball %s successful.' % filename)
1121 def make_zip(subdir):
1122 global SILENT_MODE, data
1124 filename = "%s/%s.zip" % (BUG_DIR, subdir)
1125 zf = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED)
1128 for (k, v) in data.items():
1130 dest = os.path.join(subdir, construct_filename(k, v))
1132 if v.has_key('output'):
1133 zf.writestr(dest, v['output'].getvalue())
1135 if os.stat(v['filename']).st_size < 50:
1136 compress_type = zipfile.ZIP_STORED
1138 compress_type = zipfile.ZIP_DEFLATED
1139 zf.write(v['filename'], dest, compress_type)
1145 output ('Writing archive %s successful.' % filename)
1150 def make_inventory(inventory, subdir):
1151 document = getDOMImplementation().createDocument(
1152 None, INVENTORY_XML_ROOT, None)
1154 # create summary entry
1155 s = document.createElement(INVENTORY_XML_SUMMARY)
1156 user = os.getenv('SUDO_USER', os.getenv('USER'))
1158 s.setAttribute('user', user)
1159 s.setAttribute('date', time.strftime('%c'))
1160 s.setAttribute('hostname', platform.node())
1161 s.setAttribute('uname', ' '.join(platform.uname()))
1162 s.setAttribute('uptime', commands.getoutput(UPTIME))
1163 document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(s)
1165 map(lambda (k, v): inventory_entry(document, subdir, k, v),
1167 return document.toprettyxml()
1169 def inventory_entry(document, subdir, k, v):
1171 el = document.createElement(INVENTORY_XML_ELEMENT)
1172 el.setAttribute('capability', v['cap'])
1173 el.setAttribute('filename', os.path.join(subdir, construct_filename(k, v)))
1174 el.setAttribute('md5sum', md5sum(v))
1175 document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(el)
1182 if d.has_key('filename'):
1183 f = open(d['filename'])
1185 while len(data) > 0:
1189 elif d.has_key('output'):
1190 m.update(d['output'].getvalue())
1191 return m.hexdigest()
1194 def construct_filename(k, v):
1195 if v.has_key('filename'):
1196 if v['filename'][0] == '/':
1197 return v['filename'][1:]
1199 return v['filename']
1200 s = k.replace(' ', '-')
1201 s = s.replace('--', '-')
1202 s = s.replace('/', '%')
1203 if s.find('.') == -1:
1209 def update_capabilities():
1210 update_cap_size(CAP_HOST_CRASHDUMP_LOGS,
1211 size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE))
1212 update_cap_size(CAP_HOST_CRASHDUMP_DUMPS,
1213 size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE,
1215 update_cap_size(CAP_XAPI_DEBUG, size_of_dir(XAPI_DEBUG_DIR))
1216 update_cap_size(CAP_XENSERVER_LOGS, size_of_all(XENSERVER_LOGS))
1219 def update_cap_size(cap, size):
1220 update_cap(cap, MIN_SIZE, size)
1221 update_cap(cap, MAX_SIZE, size)
1222 update_cap(cap, CHECKED, size > 0)
1225 def update_cap(cap, k, v):
1229 caps[cap] = tuple(l)
1232 def size_of_dir(d, pattern = None, negate = False):
1233 if os.path.isdir(d):
1234 return size_of_all([os.path.join(d, fn) for fn in os.listdir(d)],
1240 def size_of_all(files, pattern = None, negate = False):
1241 return sum([size_of(f, pattern, negate) for f in files])
1244 def matches(f, pattern, negate):
1246 return not matches(f, pattern, False)
1248 return pattern is None or pattern.match(f)
1251 def size_of(f, pattern, negate):
1252 if os.path.isfile(f) and matches(f, pattern, negate):
1253 return os.stat(f)[6]
1255 return size_of_dir(f, pattern, negate)
1258 def print_capabilities():
1259 document = getDOMImplementation().createDocument(
1260 "ns", CAP_XML_ROOT, None)
1261 map(lambda key: capability(document, key), caps.keys())
1262 print document.toprettyxml()
1264 def capability(document, key):
1266 el = document.createElement(CAP_XML_ELEMENT)
1267 el.setAttribute('key', c[KEY])
1268 el.setAttribute('pii', c[PII])
1269 el.setAttribute('min-size', str(c[MIN_SIZE]))
1270 el.setAttribute('max-size', str(c[MAX_SIZE]))
1271 el.setAttribute('min-time', str(c[MIN_TIME]))
1272 el.setAttribute('max-time', str(c[MAX_TIME]))
1273 el.setAttribute('content-type', c[MIME])
1274 el.setAttribute('default-checked', c[CHECKED] and 'yes' or 'no')
1275 document.getElementsByTagName(CAP_XML_ROOT)[0].appendChild(el)
1279 format = '%%-%ds: %%s' % max(map(len, [k for k, _ in d.items()]))
1280 return '\n'.join([format % i for i in d.items()]) + '\n'
1284 yn = raw_input(prompt)
1286 return len(yn) == 0 or yn.lower()[0] == 'y'
1289 partition_re = re.compile(r'(.*[0-9]+$)|(^xvd)')
1292 command = [OVS_DPCTL, "dump-dps"]
1293 proc = Popen(command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null)
1294 (dps, err) = proc.communicate()
1295 return dps.splitlines()
1301 f = open('/proc/partitions')
1304 for line in f.readlines():
1305 (major, minor, blocks, name) = line.split()
1306 if int(major) < 254 and not partition_re.match(name):
1316 def __init__(self, command, max_time, inst=None, filter=None):
1317 self.command = command
1318 self.max_time = max_time
1320 self.running = False
1322 self.timed_out = False
1324 self.timeout = int(time.time()) + self.max_time
1325 self.filter = filter
1331 self.timed_out = False
1333 if ProcOutput.debug:
1334 output_ts("Starting '%s'" % ' '.join(self.command))
1335 self.proc = Popen(self.command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null)
1336 old = fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_GETFD)
1337 fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
1341 output_ts("'%s' failed" % ' '.join(self.command))
1342 self.running = False
1345 def terminate(self):
1348 os.kill(self.proc.pid, SIGTERM)
1352 self.running = False
1353 self.status = SIGTERM
1355 def read_line(self):
1357 line = self.proc.stdout.readline()
1360 self.status = self.proc.wait()
1362 self.running = False
1365 line = self.filter(line)
1367 self.inst.write(line)
1369 def run_procs(procs):
1377 active_procs.append(p)
1378 pipes.append(p.proc.stdout)
1380 elif p.status == None and not p.failed and not p.timed_out:
1383 active_procs.append(p)
1384 pipes.append(p.proc.stdout)
1391 (i, o, x) = select(pipes, [], [], 1.0)
1392 now = int(time.time())
1394 # handle process output
1395 for p in active_procs:
1396 if p.proc.stdout in i:
1400 if p.running and now > p.timeout:
1401 output_ts("'%s' timed out" % ' '.join(p.command))
1403 p.inst.write("\n** timeout **\n")
1411 for d in [p for p in os.listdir('/proc') if p.isdigit()]:
1413 if os.path.basename(os.readlink('/proc/%s/exe' % d)) == name:
1421 def readKeyValueFile(filename, allowed_keys = None, strip_quotes = True, assert_quotes = True):
1422 """ Reads a KEY=Value style file (e.g. xensource-inventory). Returns a
1423 dictionary of key/values in the file. Not designed for use with large files
1424 as the file is read entirely into memory."""
1426 f = open(filename, "r")
1427 lines = [x.strip("\n") for x in f.readlines()]
1430 # remove lines contain
1432 lines = filter(lambda x: True in [x.startswith(y) for y in allowed_keys],
1435 defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ]
1440 assert x.startswith("'") and x.endswith("'")
1442 defs = [ (a, quotestrip(b)) for (a,b) in defs ]
1447 class StringIOmtime(StringIO.StringIO):
1448 def __init__(self, buf = ''):
1449 StringIO.StringIO.__init__(self, buf)
1450 self.mtime = time.time()
1453 StringIO.StringIO.write(self, s)
1454 self.mtime = time.time()
1457 if __name__ == "__main__":
1460 except KeyboardInterrupt:
1461 print "\nInterrupted."