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 XENSOURCE_INVENTORY = '/etc/xensource-inventory'
125 OEM_CONFIG_DIR = '/var/xsconfig'
126 OEM_CONFIG_FILES_RE = re.compile(r'^.*xensource-inventory$')
127 OEM_DB_FILES_RE = re.compile(r'^.*state\.db')
128 INITIAL_INVENTORY = '/opt/xensource/etc/initial-inventory'
129 VENDORKERNEL_INVENTORY = '/etc/vendorkernel-inventory'
130 STATIC_VDIS = '/etc/xensource/static-vdis'
131 POOL_CONF = '/etc/xensource/pool.conf'
132 PTOKEN = '/etc/xensource/ptoken'
133 XAPI_CONF = '/etc/xensource/xapi.conf'
134 XAPI_SSL_CONF = '/etc/xensource/xapi-ssl.conf'
135 DB_CONF = '/etc/xensource/db.conf'
136 DB_CONF_RIO = '/etc/xensource/db.conf.rio'
137 DB_DEFAULT_FIELDS = '/etc/xensource/db-default-fields'
138 DB_SCHEMA_SQL = '/etc/xensource/db_schema.sql'
139 XENSTORED_DB = '/var/lib/xenstored/tdb'
140 HOST_CRASHDUMPS_DIR = '/var/crash'
141 HOST_CRASHDUMP_LOGS_RE = re.compile(r'^.*\.log$')
142 X11_LOGS_DIR = VAR_LOG_DIR
143 X11_LOGS_RE = re.compile(r'.*/Xorg\..*$')
144 X11_AUTH_DIR = '/root/'
145 X11_AUTH_RE = re.compile(r'.*/\.((Xauthority)|(serverauth\.[0-9]*))$')
146 XAPI_DEBUG_DIR = '/var/xapi/debug'
147 LOG_CONF = '/etc/xensource/log.conf'
148 INSTALLED_REPOS_DIR = '/etc/xensource/installed-repos'
149 PATCH_APPLIED_DIR = '/var/patch/applied'
151 [ VAR_LOG_DIR + x for x in
152 ['xensource.log', 'xenstored-access.log', 'SMlog', 'xen/xenstored-trace.log',
153 'xen/xen-hotplug.log', 'xen/domain-builder-ng.log'] +
154 [ f % n for n in range(1, 20) \
155 for f in ['xensource.log.%d', 'xensource.log.%d.gz','SMlog.%d', 'SMlog.%d.gz',
156 'xenstored-access.log.%d', 'xenstored-access.log.%d.gz', \
157 'xen/xenstored-access.log.%d', 'xen/xenstored-access.log.%d.gz' ]]] \
158 + glob.glob('/tmp/qemu.[0-9]*')
159 OEM_XENSERVER_LOGS_RE = re.compile(r'^.*xensource\.log$')
160 XHA_LOG = '/var/log/xha.log'
161 XHAD_CONF = '/etc/xensource/xhad.conf'
162 YUM_LOG = '/var/log/yum.log'
163 YUM_REPOS_DIR = '/etc/yum.repos.d'
164 PAM_DIR = '/etc/pam.d'
172 BIOSDEVNAME = '/sbin/biosdevname'
173 BRCTL = '/usr/sbin/brctl'
175 CHKCONFIG = '/sbin/chkconfig'
176 CSL = '/opt/Citrix/StorageLink/bin/csl'
179 DMIDECODE = '/usr/sbin/dmidecode'
180 DMSETUP = '/sbin/dmsetup'
181 ETHTOOL = '/sbin/ethtool'
182 FDISK = '/sbin/fdisk'
183 FIND = '/usr/bin/find'
184 HA_QUERY_LIVESET = '/opt/xensource/debug/debug_ha_query_liveset'
185 HDPARM = '/sbin/hdparm'
186 IFCONFIG = '/sbin/ifconfig'
187 IPTABLES = '/sbin/iptables'
188 ISCSIADM = '/sbin/iscsiadm'
189 LIST_DOMAINS = '/opt/xensource/bin/list_domains'
190 LOSETUP = '/sbin/losetup'
192 LSPCI = '/sbin/lspci'
193 LVS = '/usr/sbin/lvs'
194 MD5SUM = '/usr/bin/md5sum'
195 MULTIPATHD = '/sbin/multipathd'
196 NETSTAT = '/bin/netstat'
197 OMREPORT = '/opt/dell/srvadmin/oma/bin/omreport'
198 OVS_DPCTL = '/root/vswitch/bin/ovs-dpctl'
199 OVS_OFCTL = '/root/vswitch/bin/ovs-ofctl'
201 PVS = '/usr/sbin/pvs'
202 ROUTE = '/sbin/route'
204 SG_MAP = '/usr/bin/sg_map'
205 SQLITE = '/usr/bin/sqlite3'
206 BIN_STATIC_VDIS = '/opt/xensource/bin/static-vdis'
207 SYSCTL = '/sbin/sysctl'
209 UPTIME = '/usr/bin/uptime'
210 VGS = '/usr/sbin/vgs'
211 VGSCAN = '/sbin/vgscan'
212 XAPI_DB_PROCESS = '/opt/xensource/bin/xapi-db-process'
213 XE = '/opt/xensource/bin/xe'
214 XS = '/opt/xensource/debug/xs'
215 XENSTORE_LS = '/usr/bin/xenstore-ls'
219 # PII -- Personally identifiable information. Of particular concern are
220 # things that would identify customers, or their network topology.
221 # Passwords are never to be included in any bug report, regardless of any PII
224 # NO -- No PII will be in these entries.
225 # YES -- PII will likely or certainly be in these entries.
226 # MAYBE -- The user may wish to audit these entries for PII.
227 # IF_CUSTOMIZED -- If the files are unmodified, then they will contain no PII,
228 # but since we encourage customers to edit these files, PII may have been
229 # introduced by the customer. This is used in particular for the networking
236 PII_IF_CUSTOMIZED = 'if_customized'
247 MIME_DATA = 'application/data'
248 MIME_TEXT = 'text/plain'
250 INVENTORY_XML_ROOT = "system-status-inventory"
251 INVENTORY_XML_SUMMARY = 'system-summary'
252 INVENTORY_XML_ELEMENT = 'inventory-entry'
253 CAP_XML_ROOT = "system-status-capabilities"
254 CAP_XML_ELEMENT = 'capability'
258 CAP_BOOT_LOADER = 'boot-loader'
260 CAP_DISK_INFO = 'disk-info'
261 CAP_FIRSTBOOT = 'firstboot'
262 CAP_HARDWARE_INFO = 'hardware-info'
263 CAP_HDPARM_T = 'hdparm-t'
264 CAP_HIGH_AVAILABILITY = 'high-availability'
265 CAP_HOST_CRASHDUMP_DUMPS = 'host-crashdump-dumps'
266 CAP_HOST_CRASHDUMP_LOGS = 'host-crashdump-logs'
267 CAP_KERNEL_INFO = 'kernel-info'
268 CAP_LOSETUP_A = 'loopback-devices'
269 CAP_MULTIPATH = 'multipath'
270 CAP_NETWORK_CONFIG = 'network-config'
271 CAP_NETWORK_STATUS = 'network-status'
274 CAP_PROCESS_LIST = 'process-list'
275 CAP_PERSISTENT_STATS = 'persistent-stats'
276 CAP_SYSTEM_LOGS = 'system-logs'
277 CAP_SYSTEM_SERVICES = 'system-services'
278 CAP_TAPDISK_LOGS = 'tapdisk-logs'
279 CAP_VNCTERM = 'vncterm'
280 CAP_VSWITCH_CONFIG = 'vswitch-config'
281 CAP_VSWITCH_LOGS = 'vswitch-logs'
282 CAP_VSWITCH_STATUS = 'vswitch-status'
285 CAP_X11_AUTH = 'X11-auth'
286 CAP_XAPI_DEBUG = 'xapi-debug'
287 CAP_XAPI_SUBPROCESS = 'xapi-subprocess'
288 CAP_XENSERVER_CONFIG = 'xenserver-config'
289 CAP_XENSERVER_DOMAINS = 'xenserver-domains'
290 CAP_XENSERVER_DATABASES = 'xenserver-databases'
291 CAP_XENSERVER_INSTALL = 'xenserver-install'
292 CAP_XENSERVER_LOGS = 'xenserver-logs'
293 CAP_XEN_INFO = 'xen-info'
294 CAP_XHA_LIVESET = 'xha-liveset'
302 unlimited_data = False
305 def cap(key, pii=PII_MAYBE, min_size=-1, max_size=-1, min_time=-1,
306 max_time=-1, mime=MIME_TEXT, checked=True):
307 caps[key] = (key, pii, min_size, max_size, min_time, max_time, mime,
312 cap(CAP_BLOBS, PII_NO, max_size=5*MB)
313 cap(CAP_BOOT_LOADER, PII_NO, max_size=3*KB,
315 cap(CAP_CVSM, PII_NO, max_size=3*MB,
317 cap(CAP_DISK_INFO, PII_MAYBE, max_size=25*KB,
319 cap(CAP_FIRSTBOOT, PII_YES, min_size=60*KB, max_size=80*KB)
320 cap(CAP_HARDWARE_INFO, PII_MAYBE, max_size=30*KB,
322 cap(CAP_HDPARM_T, PII_NO, min_size=0, max_size=5*KB,
323 min_time=20, max_time=90, checked=False)
324 cap(CAP_HIGH_AVAILABILITY, PII_MAYBE, max_size=5*MB)
325 cap(CAP_HOST_CRASHDUMP_DUMPS,PII_YES, checked = False)
326 cap(CAP_HOST_CRASHDUMP_LOGS, PII_NO)
327 cap(CAP_KERNEL_INFO, PII_MAYBE, max_size=80*KB,
329 cap(CAP_LOSETUP_A, PII_MAYBE, max_size=KB, max_time=5)
330 cap(CAP_MULTIPATH, PII_MAYBE, max_size=10*KB,
332 cap(CAP_NETWORK_CONFIG, PII_IF_CUSTOMIZED,
333 min_size=0, max_size=20*KB)
334 cap(CAP_NETWORK_STATUS, PII_YES, max_size=19*KB,
336 cap(CAP_PAM, PII_NO, max_size=10*KB)
337 cap(CAP_PERSISTENT_STATS, PII_MAYBE, max_size=50*MB,
339 cap(CAP_PROCESS_LIST, PII_YES, max_size=10*KB,
341 cap(CAP_SYSTEM_LOGS, PII_MAYBE, max_size=50*MB,
343 cap(CAP_SYSTEM_SERVICES, PII_NO, max_size=5*KB,
345 cap(CAP_TAPDISK_LOGS, PII_NO, max_size=64*KB)
346 cap(CAP_VNCTERM, PII_MAYBE, checked = False)
347 cap(CAP_VSWITCH_CONFIG, PII_YES,
348 min_size=0, max_size=20*MB)
349 cap(CAP_VSWITCH_LOGS, PII_YES, max_size=20*MB)
350 cap(CAP_VSWITCH_STATUS, PII_YES, max_size=19*KB,
352 cap(CAP_WLB, PII_NO, max_size=3*MB,
354 cap(CAP_X11_LOGS, PII_NO, max_size=100*KB)
355 cap(CAP_X11_AUTH, PII_NO, max_size=100*KB)
356 cap(CAP_XAPI_DEBUG, PII_MAYBE, max_size=10*MB)
357 cap(CAP_XAPI_SUBPROCESS, PII_NO, max_size=5*KB,
359 cap(CAP_XENSERVER_CONFIG, PII_MAYBE, max_size=50*KB,
361 cap(CAP_XENSERVER_DOMAINS, PII_NO, max_size=1*KB,
363 cap(CAP_XENSERVER_DATABASES, PII_YES, min_size=500*KB,max_size=2*MB,
365 cap(CAP_XENSERVER_INSTALL, PII_MAYBE, min_size=10*KB, max_size=300*KB)
366 cap(CAP_XENSERVER_LOGS, PII_MAYBE, min_size=0, max_size=50*MB)
367 cap(CAP_XEN_INFO, PII_MAYBE, max_size=20*KB,
369 cap(CAP_XHA_LIVESET, PII_MAYBE, max_size=10*KB,
371 cap(CAP_YUM, PII_IF_CUSTOMIZED, max_size=10*KB,
374 ANSWER_YES_TO_ALL = False
378 dev_null = open('/dev/null', 'r+')
386 output("[%s] %s" % (time.strftime("%x %X %Z"), x))
388 def cmd_output(cap, args, label = None, filter = None):
390 a = [aa for aa in args]
391 a[0] = os.path.basename(a[0])
394 data[label] = {'cap': cap, 'cmd_args': args, 'filter': filter}
396 def file_output(cap, path_list):
399 if os.path.exists(p):
400 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
401 cap_sizes[cap] < caps[cap][MAX_SIZE]:
402 data[p] = {'cap': cap, 'filename': p}
405 cap_sizes[cap] += s.st_size
409 output("Omitting %s, size constraint of %s exceeded" % (p, cap))
411 def tree_output(cap, path, pattern = None, negate = False):
413 if os.path.exists(path):
414 for f in os.listdir(path):
415 fn = os.path.join(path, f)
416 if os.path.isfile(fn) and matches(fn, pattern, negate):
417 file_output(cap, [fn])
418 elif os.path.isdir(fn):
419 tree_output(cap, fn, pattern, negate)
421 def func_output(cap, label, func):
423 t = str(func).split()
424 data[label] = {'cap': cap, 'func': func}
429 for (k, v) in data.items():
431 if v.has_key('cmd_args'):
432 v['output'] = StringIOmtime()
433 if not process_lists.has_key(cap):
434 process_lists[cap] = []
435 process_lists[cap].append(ProcOutput(v['cmd_args'], caps[cap][MAX_TIME], v['output'], v['filter']))
436 elif v.has_key('filename') and v['filename'].startswith('/proc/'):
437 # proc files must be read into memory
439 f = open(v['filename'], 'r')
442 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
443 cap_sizes[cap] < caps[cap][MAX_SIZE]:
444 v['output'] = StringIOmtime(s)
445 cap_sizes[cap] += len(s)
447 output("Omitting %s, size constraint of %s exceeded" % (v['filename'], cap))
450 elif v.has_key('func'):
455 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
456 cap_sizes[cap] < caps[cap][MAX_SIZE]:
457 v['output'] = StringIOmtime(s)
458 cap_sizes[cap] += len(s)
460 output("Omitting %s, size constraint of %s exceeded" % (k, cap))
462 run_procs(process_lists.values())
465 def main(argv = None):
466 global ANSWER_YES_TO_ALL, SILENT_MODE
467 global entries, data, dbg
469 # we need access to privileged files, exit if we are not running as root
471 print >>sys.stderr, "Error: xen-bugtool must be run as root"
474 output_type = 'tar.bz2'
481 (options, params) = getopt.gnu_getopt(
482 argv, 'sy', ['capabilities', 'silent', 'yestoall', 'entries=',
483 'output=', 'outfd=', 'all', 'unlimited', 'debug'])
484 except getopt.GetoptError, opterr:
485 print >>sys.stderr, opterr
488 inventory = readKeyValueFile(XENSOURCE_INVENTORY)
489 if inventory.has_key('OEM_BUILD_NUMBER'):
490 cap(CAP_OEM, PII_MAYBE, max_size=5*MB,
493 if os.getenv('XEN_RT'):
494 entries = [CAP_BLOBS, CAP_BOOT_LOADER, CAP_CVSM, CAP_DISK_INFO, CAP_FIRSTBOOT, CAP_HARDWARE_INFO,
495 CAP_HOST_CRASHDUMP_DUMPS, CAP_HOST_CRASHDUMP_LOGS, CAP_KERNEL_INFO, CAP_LOSETUP_A,
496 CAP_NETWORK_CONFIG, CAP_NETWORK_STATUS, CAP_PROCESS_LIST, CAP_HIGH_AVAILABILITY,
497 CAP_PAM, CAP_PERSISTENT_STATS, CAP_MULTIPATH,
498 CAP_SYSTEM_LOGS, CAP_SYSTEM_SERVICES, CAP_TAPDISK_LOGS,
499 CAP_VNCTERM, CAP_VSWITCH_CONFIG, CAP_VSWITCH_LOGS, CAP_VSWITCH_STATUS, CAP_WLB,
500 CAP_X11_LOGS, CAP_X11_AUTH, CAP_XAPI_DEBUG, CAP_XAPI_SUBPROCESS,
501 CAP_XENSERVER_CONFIG, CAP_XENSERVER_DOMAINS, CAP_XENSERVER_DATABASES,
502 CAP_XENSERVER_INSTALL, CAP_XENSERVER_LOGS, CAP_XEN_INFO, CAP_XHA_LIVESET, CAP_YUM]
504 entries = [e for e in caps.keys() if caps[e][CHECKED]]
506 for (k, v) in options:
507 if k == '--capabilities':
508 update_capabilities()
513 if v in ['tar', 'tar.bz2', 'zip']:
516 print >>sys.stderr, "Invalid output format '%s'" % v
519 # "-s" or "--silent" means suppress output (except for the final
520 # output filename at the end)
521 if k in ['-s', '--silent']:
524 if k == '--entries' and v != '':
525 entries = v.split(',')
527 # If the user runs the script with "-y" or "--yestoall" we don't ask
528 # all the really annoying questions.
529 if k in ['-y', '--yestoall']:
530 ANSWER_YES_TO_ALL = True
535 old = fcntl.fcntl(output_fd, fcntl.F_GETFD)
536 fcntl.fcntl(output_fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
538 print >>sys.stderr, "Invalid output file descriptor", output_fd
542 entries = caps.keys()
543 elif k == '--unlimited':
544 unlimited_data = True
547 ProcOutput.debug = True
550 print >>sys.stderr, "Invalid additional arguments", str(params)
553 if output_fd != -1 and output_type != 'tar':
554 print >>sys.stderr, "Option '--outfd' only valid with '--output=tar'"
557 if ANSWER_YES_TO_ALL:
558 output("Warning: '--yestoall' argument provided, will not prompt for individual files.")
561 This application will collate the Xen dmesg output, details of the
562 hardware configuration of your machine, information about the build of
563 Xen that you are using, plus, if you allow it, various logs.
565 The collated information will be saved as a .%s for archiving or
566 sending to a Technical Support Representative.
568 The logs may contain private information, and if you are at all
569 worried about that, you should exit now, or you should explicitly
570 exclude those logs from the archive.
574 # assemble potential data
575 tree_output(CAP_BLOBS, XAPI_BLOBS)
577 file_output(CAP_BOOT_LOADER, [GRUB_CONFIG, EXTLINUX_CONFIG])
578 cmd_output(CAP_BOOT_LOADER, [LS, '-lR', '/boot'])
579 cmd_output(CAP_BOOT_LOADER, [MD5SUM, BOOT_KERNEL, BOOT_INITRD], label='vmlinuz-initrd.md5sum')
581 func_output(CAP_CVSM, 'csl_logs', csl_logs)
583 cmd_output(CAP_DISK_INFO, [FDISK, '-l'])
584 file_output(CAP_DISK_INFO, [PROC_PARTITIONS, PROC_MOUNTS])
585 file_output(CAP_DISK_INFO, [FSTAB, ISCSI_CONF, ISCSI_INITIATOR])
586 cmd_output(CAP_DISK_INFO, [DF, '-alT'])
587 cmd_output(CAP_DISK_INFO, [DF, '-alTi'])
588 for d in disk_list():
589 cmd_output(CAP_DISK_INFO, [HDPARM, '-I', '/dev/%s' % d])
590 if len(pidof('iscsid')) != 0:
591 cmd_output(CAP_DISK_INFO, [ISCSIADM, '-m', 'node'])
592 cmd_output(CAP_DISK_INFO, [VGSCAN])
593 cmd_output(CAP_DISK_INFO, [PVS])
594 cmd_output(CAP_DISK_INFO, [VGS])
595 cmd_output(CAP_DISK_INFO, [LVS])
596 file_output(CAP_DISK_INFO, [LVM_CACHE])
597 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_host'])
598 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_disk'])
599 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/fc_transport'])
600 cmd_output(CAP_DISK_INFO, [SG_MAP, '-x'])
601 func_output(CAP_DISK_INFO, 'scsi-hosts', dump_scsi_hosts)
602 tree_output(CAP_DISK_INFO, PROC_DRIVER_CCISS_DIR)
604 tree_output(CAP_FIRSTBOOT, FIRSTBOOT_DIR)
606 file_output(CAP_HARDWARE_INFO, [PROC_CPUINFO, PROC_MEMINFO, PROC_IOPORTS, PROC_INTERRUPTS])
607 cmd_output(CAP_HARDWARE_INFO, [DMIDECODE])
608 cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-n'])
609 cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-vv'])
610 file_output(CAP_HARDWARE_INFO, [PROC_USB_DEV, PROC_SCSI])
611 file_output(CAP_HARDWARE_INFO, [BOOT_TIME_CPUS, BOOT_TIME_MEMORY])
612 file_output(CAP_HARDWARE_INFO, [SYSCONFIG_HWCONF])
615 for d in disk_list():
616 cmd_output(CAP_HDPARM_T, [HDPARM, '-tT', '/dev/%s' % d])
618 file_output(CAP_HIGH_AVAILABILITY, [XHAD_CONF, XHA_LOG])
620 tree_output(CAP_HOST_CRASHDUMP_DUMPS, HOST_CRASHDUMPS_DIR,
621 HOST_CRASHDUMP_LOGS_RE, True)
622 tree_output(CAP_HOST_CRASHDUMP_LOGS, HOST_CRASHDUMPS_DIR,
623 HOST_CRASHDUMP_LOGS_RE, False)
625 file_output(CAP_KERNEL_INFO, [PROC_VERSION, PROC_MODULES, PROC_DEVICES,
626 PROC_FILESYSTEMS, PROC_CMDLINE])
627 cmd_output(CAP_KERNEL_INFO, [ZCAT, PROC_CONFIG], label='config')
628 cmd_output(CAP_KERNEL_INFO, [SYSCTL, '-A'])
629 file_output(CAP_KERNEL_INFO, [MODPROBE_CONF])
630 tree_output(CAP_KERNEL_INFO, MODPROBE_DIR)
632 cmd_output(CAP_LOSETUP_A, [LOSETUP, '-a'])
634 file_output(CAP_MULTIPATH, [MULTIPATH_CONF])
635 cmd_output(CAP_MULTIPATH, [DMSETUP, 'status'])
636 func_output(CAP_MULTIPATH, 'multipathd_topology', multipathd_topology)
638 tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, IFCFG_RE)
639 tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, ROUTE_RE)
640 file_output(CAP_NETWORK_CONFIG, [SYSCONFIG_NETWORK, RESOLV_CONF, NSSWITCH_CONF])
641 file_output(CAP_NETWORK_CONFIG, [NTP_CONF, IPTABLES_CONFIG, HOSTS_ALLOW, HOSTS_DENY])
643 cmd_output(CAP_NETWORK_STATUS, [IFCONFIG, '-a'])
644 cmd_output(CAP_NETWORK_STATUS, [ROUTE, '-n'])
645 cmd_output(CAP_NETWORK_STATUS, [ARP, '-n'])
646 cmd_output(CAP_NETWORK_STATUS, [NETSTAT, '-an'])
647 tree_output(CAP_NETWORK_STATUS, DHCP_LEASE_DIR)
648 cmd_output(CAP_NETWORK_STATUS, [IPTABLES, '-nL'])
649 cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'show'])
650 cmd_output(CAP_NETWORK_STATUS, [BIOSDEVNAME, '-d'])
651 for p in os.listdir('/sys/class/net/'):
652 if os.path.isdir('/sys/class/net/%s/bridge' % p):
653 cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'showmacs', p])
656 f = open('/sys/class/net/%s/type' % p, 'r')
661 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, p])
662 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-S', p])
663 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-k', p])
664 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-i', p])
665 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-c', p])
668 tree_output(CAP_NETWORK_STATUS, PROC_NET_BONDING_DIR)
669 tree_output(CAP_NETWORK_STATUS, PROC_NET_VLAN_DIR)
670 cmd_output(CAP_NETWORK_STATUS, [TC, '-s', 'qdisc'])
671 file_output(CAP_NETWORK_STATUS, [PROC_NET_SOFTNET_STAT])
673 tree_output(CAP_OEM, DELL_OMSA_LOGS)
674 file_output(CAP_OEM, [HP_CMA_LOG, HP_HPASMD_LOG])
675 if os.path.exists(OMREPORT):
676 cmd_output(CAP_OEM, [OMREPORT, 'system', 'alertlog'])
677 cmd_output(CAP_OEM, [OMREPORT, 'system', 'cmdlog'])
678 cmd_output(CAP_OEM, [OMREPORT, 'system', 'esmlog'])
679 cmd_output(CAP_OEM, [OMREPORT, 'system', 'postlog'])
680 cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'fans'])
681 cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'memory'])
682 cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'temps'])
683 cmd_output(CAP_OEM, [OMREPORT, 'storage', 'controller'])
684 for i in range(0, 4):
685 cmd_output(CAP_OEM, [OMREPORT, 'storage', 'adisk', 'controller=%d' % i])
686 cmd_output(CAP_OEM, [OMREPORT, 'storage', 'vdisk', 'controller=%d' % i])
687 cmd_output(CAP_OEM, [FIND, '/.state', '-size', '+20k', '-exec', 'ls', '-l', '{}',';'],
690 tree_output(CAP_PAM, PAM_DIR)
692 func_output(CAP_PERSISTENT_STATS, 'xapi_rrd-host', dump_xapi_rrds)
694 cmd_output(CAP_PROCESS_LIST, [PS, 'wwwaxf', '-eo', 'pid,tty,stat,time,nice,psr,pcpu,pmem,wchan:25,args'], label='process-tree')
696 file_output(CAP_SYSTEM_LOGS,
697 [ VAR_LOG_DIR + x for x in
698 [ 'syslog', 'messages', 'monitor_memory.log', 'secure', 'debug', 'dmesg', 'boot.msg' ] +
699 [ f % n for n in range(1, 20) \
700 for f in ['messages.%d', 'messages.%d.gz', 'monitor_memory.log.%d',
701 'monitor_memory.log.%d.gz', 'secure.%d', 'secure.%d.gz']]])
702 if not os.path.exists('/var/log/dmesg') and not os.path.exists('/var/log/boot.msg'):
703 cmd_output(CAP_SYSTEM_LOGS, [DMESG])
705 cmd_output(CAP_SYSTEM_SERVICES, [CHKCONFIG, '--list'])
707 if CAP_TAPDISK_LOGS in entries:
708 generate_tapdisk_logs()
710 tree_output(CAP_VNCTERM, VNCTERM_CORE_DIR)
712 file_output(CAP_VSWITCH_CONFIG, [OVS_VSWITCH_CONF])
714 file_output(CAP_VSWITCH_LOGS,
715 [ VAR_LOG_DIR + x for x in
716 [ 'ovs-brcompatd.log', 'ovs-vswitchd.log', 'vswitch-cfg-update.log', 'vswitch-xsplugin.log' ] +
717 [ f % n for n in range(1, 20) \
718 for f in ['ovs-brcompatd.log.%d', 'ovs-brcompatd.log.%d.gz',
719 'ovs-vswitchd.log.%d', 'ovs-vswitchd.log.%d.gz']]])
721 cmd_output(CAP_VSWITCH_STATUS, [OVS_DPCTL, 'show'])
722 tree_output(CAP_VSWITCH_STATUS, VSWITCH_CORE_DIR)
724 cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'show', d])
725 cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'status', d])
726 cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'dump-flows', d])
727 cmd_output(CAP_VSWITCH_STATUS, [OVS_DPCTL, 'dump-flows', d])
729 cmd_output(CAP_WLB, [XE, 'pool-retrieve-wlb-diagnostics'])
731 tree_output(CAP_X11_LOGS, X11_LOGS_DIR, X11_LOGS_RE)
732 tree_output(CAP_X11_AUTH, X11_AUTH_DIR, X11_AUTH_RE)
734 tree_output(CAP_XAPI_DEBUG, XAPI_DEBUG_DIR)
736 func_output(CAP_XAPI_SUBPROCESS, 'xapi_subprocesses', dump_xapi_subprocess_info)
738 file_output(CAP_XENSERVER_CONFIG, [INITIAL_INVENTORY])
739 file_output(CAP_XENSERVER_CONFIG, [POOL_CONF, PTOKEN, XAPI_CONF, XAPI_SSL_CONF, STATIC_VDIS,
740 XENSOURCE_INVENTORY, VENDORKERNEL_INVENTORY])
741 cmd_output(CAP_XENSERVER_CONFIG, [LS, '-lR', '/opt/xensource'])
742 cmd_output(CAP_XENSERVER_CONFIG, [BIN_STATIC_VDIS, 'list'])
743 tree_output(CAP_XENSERVER_CONFIG, OEM_CONFIG_DIR, OEM_CONFIG_FILES_RE)
745 func_output(CAP_XENSERVER_DATABASES, 'xapi-db.xml', dump_filtered_xapi_db)
746 cmd_output(CAP_XENSERVER_DATABASES, [XENSTORE_LS])
747 file_output(CAP_XENSERVER_DATABASES, [DB_CONF, DB_CONF_RIO, DB_DEFAULT_FIELDS, DB_SCHEMA_SQL])
748 tree_output(CAP_XENSERVER_DATABASES, OEM_CONFIG_DIR, OEM_DB_FILES_RE)
749 file_output(CAP_XENSERVER_DATABASES, [XENSTORED_DB, XENSTORED_DB + '.bak'])
750 cmd_output(CAP_XENSERVER_DATABASES, [XE, 'pool-dump-database', 'file-name='],
751 label="xapi-db-dumped.xml", filter=filter_db_pii)
752 cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'watches'])
753 cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'quotas'])
755 cmd_output(CAP_XENSERVER_DOMAINS, [LIST_DOMAINS])
757 tree_output(CAP_XENSERVER_INSTALL, VAR_LOG_DIR + 'installer')
758 file_output(CAP_XENSERVER_INSTALL,
759 [ VAR_LOG_DIR + x for x in
760 [ 'firstboot-SR-commands-log',
761 'upgrade-commands-log', 'generate-iscsi-iqn-log']] +
762 [ '/root/' + x for x in
763 [ 'blockdevs-log', 'cmdline-log', 'devcontents-log',
764 'dmesg-log', 'install-log', 'lspci-log', 'modules-log',
765 'pci-log', 'processes-log', 'tty-log', 'uname-log',
767 tree_output(CAP_XENSERVER_INSTALL, INSTALLED_REPOS_DIR)
768 tree_output(CAP_XENSERVER_INSTALL, PATCH_APPLIED_DIR)
770 file_output(CAP_XENSERVER_LOGS, [LOG_CONF])
771 file_output(CAP_XENSERVER_LOGS, XENSERVER_LOGS)
772 tree_output(CAP_XENSERVER_LOGS, OEM_CONFIG_DIR, OEM_XENSERVER_LOGS_RE)
776 data = xc.readconsolering()
777 xc.send_debug_keys('q')
781 xc = xen.lowlevel.xc.xc()
783 func_output(CAP_XEN_INFO, 'xen-dmesg', lambda x: xen_dmesg(xc))
784 func_output(CAP_XEN_INFO, 'physinfo', lambda x: prettyDict(xc.physinfo()))
785 func_output(CAP_XEN_INFO, 'xeninfo', lambda x: prettyDict(xc.xeninfo()))
788 file_output(CAP_XEN_INFO, [PROC_XEN_BALLOON])
790 cmd_output(CAP_XHA_LIVESET, [HA_QUERY_LIVESET])
792 file_output(CAP_YUM, [YUM_LOG])
793 tree_output(CAP_YUM, YUM_REPOS_DIR)
794 cmd_output(CAP_YUM, [RPM, '-qa'])
796 # permit the user to filter out data
797 for k in sorted(data.keys()):
798 if not ANSWER_YES_TO_ALL and not yes("Include '%s'? [Y/n]: " % k):
801 # collect selected data now
802 output_ts('Running commands to collect data')
805 subdir = os.getenv('XENRT_BUGTOOL_BASENAME')
807 subdir = os.path.basename(subdir)
808 if subdir == '..' or subdir == '.':
811 subdir = "bug-report-%s" % time.strftime("%Y%m%d%H%M%S")
814 data['inventory.xml'] = {'cap': None, 'output': StringIOmtime(make_inventory(data, subdir))}
817 if output_fd == -1 and not os.path.exists(BUG_DIR):
824 output_ts('Creating output file')
826 if output_type.startswith('tar'):
827 make_tar(subdir, output_type, output_fd)
834 print >>sys.stderr, "Category sizes (max, actual):\n"
835 for c in caps.keys():
836 print >>sys.stderr, " %s (%d, %d)" % (c, caps[c][MAX_SIZE],
840 def generate_tapdisk_logs():
841 for pid in pidof('tapdisk'):
843 os.kill(pid, SIGUSR1)
844 output_ts("Including logs for tapdisk process %d" % pid)
847 # give processes a second to write their logs
849 file_output(CAP_TAPDISK_LOGS, ['/tmp/tapdisk.log.%d' % pid for pid in pidof('tapdisk')])
851 def clean_tapdisk_logs():
852 for filename in [f for f in os.listdir('/tmp') if f.startswith('tapdisk.log.')]:
854 os.remove(os.path.join('tmp', filename))
858 def dump_xapi_subprocess_info(cap):
859 """Check which fds are open by xapi and its subprocesses to diagnose faults like CA-10543.
860 Returns a string containing a pretty-printed pstree-like structure. """
861 pids = filter(lambda x: x.isdigit(), os.listdir("/proc"))
862 def readlines(filename):
865 f = open(filename, "r")
866 lines = f.readlines()
872 all = readlines("/proc/" + pid + "/cmdline")
876 return all[0].replace('\x00', ' ')
878 for i in readlines("/proc/" + pid + "/status"):
879 if i.startswith("PPid:"):
883 result = { "cmdline": cmdline(pid) }
884 child_pids = filter(lambda x:parent(x) == pid, pids)
886 for child in child_pids:
887 children[child] = pstree(child)
888 result['children'] = children
890 for fd in os.listdir("/proc/" + pid + "/fd"):
892 fds[fd] = os.readlink("/proc/" + pid + "/fd/" + fd)
897 xapis = filter(lambda x: cmdline(x).startswith("/opt/xensource/bin/xapi"), pids)
898 xapis = filter(lambda x: parent(x) == "1", xapis)
901 result[xapi] = pstree(xapi)
902 pp = pprint.PrettyPrinter(indent=4)
903 return pp.pformat(result)
905 def dump_xapi_rrds(cap):
906 socket.setdefaulttimeout(5)
907 session = XenAPI.xapi_local()
908 session.xenapi.login_with_password('', '')
909 this_host = session.xenapi.session.get_this_host(session._session)
910 # better way to find pool master?
911 pool = session.xenapi.pool.get_all_records().values()[0]
912 i_am_master = (this_host == pool['master'])
914 for vm in session.xenapi.VM.get_all_records().values():
915 if vm['is_a_template']:
917 if vm['resident_on'] == this_host or (i_am_master and vm['power_state'] in ['Suspended', 'Halted']):
918 rrd = urllib.urlopen('http://localhost/vm_rrd?session_id=%s&uuid=%s' % (session._session, vm['uuid']))
920 (i, o, x) = select([rrd], [], [], 5.0)
922 data['xapi_rrd-%s' % vm['uuid']] = {'cap': cap,
923 'output': StringIOmtime(rrd.read())}
928 rrd = urllib.urlopen('http://localhost/host_rrd?session_id=%s' % session._session)
935 session.xenapi.session.logout()
938 def filter_db_pii(str):
939 str = re.sub(r'(password_transformed" ")[^ ]+(")', r'\1REMOVED\2', str)
940 str = re.sub(r'(wlb_password=")[^"]+(")', r'\1REMOVED\2', str)
943 def dump_filtered_xapi_db(cap):
947 # determine db format
948 c = open(DB_CONF, 'r')
951 l = line.rstrip('\n')
952 if l.startswith('['):
954 if l.startswith('format:'):
964 if format == 'sqlite':
965 pipe = Popen([XAPI_DB_PROCESS, '-xmltostdout'], bufsize=1, stdin=dev_null,
966 stdout=PIPE, stderr=dev_null)
969 ih = open(db_file, 'r')
981 remain = remain[p+1:]
982 output += filter_db_pii(str)
993 def dump_scsi_hosts(cap):
995 l = os.listdir('/sys/class/scsi_host')
1001 f = open('/sys/class/scsi_host/%s/proc_name' % h)
1002 procname = f.readline().strip("\n")
1008 f = open('/sys/class/scsi_host/%s/model_name' % h)
1009 modelname = f.readline().strip("\n")
1014 output += "%s:\n" %h
1015 output += " %s%s\n" % (procname, modelname and (" -> %s" % modelname) or '')
1020 socket.setdefaulttimeout(5)
1021 session = XenAPI.xapi_local()
1022 session.xenapi.login_with_password('', '')
1023 this_host = session.xenapi.session.get_this_host(session._session)
1024 # better way to find pool master?
1025 pool = session.xenapi.pool.get_all_records().values()[0]
1026 i_am_master = (this_host == pool['master'])
1028 output = StringIO.StringIO()
1031 def rotate_string(x, n):
1033 for a in range(0, 256):
1034 transtbl = transtbl + chr(a)
1035 transtbl = transtbl[n:] + transtbl[0:n]
1036 return x.translate(transtbl)
1038 def _untransform_string(str, remove_trailing_nulls=False):
1039 """De-obfuscate string. To cope with an obfuscation bug in Rio, the argument
1040 remove_trailing_nulls should be set to True"""
1041 tmp = base64.decodestring(str)
1042 if remove_trailing_nulls:
1043 tmp = tmp.rstrip('\x00')
1044 return rotate_string(tmp, -13)
1046 for pbd in session.xenapi.PBD.get_all_records().values():
1047 if pbd.has_key('device_config') and pbd['device_config'].has_key('target'):
1048 sr = session.xenapi.SR.get_record(pbd['SR'])
1049 if sr.has_key('type') and sr['type'] == 'cslg':
1050 if sr['shared'] and pbd['host'] != this_host and not i_am_master:
1053 dev_cfg = pbd['device_config']
1054 server = "server=%s" % socket.gethostbyname(dev_cfg['target'])
1055 if dev_cfg.has_key('port'):
1056 server += ':' + dev_cfg['port']
1057 if dev_cfg.has_key('username'):
1058 server += ',' + dev_cfg['username']
1059 if dev_cfg.has_key('password_transformed'):
1060 server += ',' + _untransform_string(dev_cfg['password_transformed'])
1061 procs.append(ProcOutput([CSL, server, 'srv-log-get'], caps[cap][MAX_TIME], output))
1063 session.xenapi.session.logout()
1067 return output.getvalue()
1069 def multipathd_topology(cap):
1070 pipe = Popen([MULTIPATHD, '-k'], bufsize=1, stdin=PIPE,
1071 stdout=PIPE, stderr=dev_null)
1072 stdout, stderr = pipe.communicate('show topology')
1076 def make_tar(subdir, suffix, output_fd):
1077 global SILENT_MODE, data
1080 if suffix == 'tar.bz2':
1082 filename = "%s/%s.%s" % (BUG_DIR, subdir, suffix)
1085 tf = tarfile.open(filename, mode)
1087 tf = tarfile.open(None, 'w', os.fdopen(output_fd, 'a'))
1090 for (k, v) in data.items():
1092 tar_filename = os.path.join(subdir, construct_filename(k, v))
1093 ti = tarfile.TarInfo(tar_filename)
1098 if v.has_key('output'):
1099 ti.mtime = v['output'].mtime
1100 ti.size = len(v['output'].getvalue())
1102 tf.addfile(ti, v['output'])
1103 elif v.has_key('filename'):
1104 s = os.stat(v['filename'])
1105 ti.mtime = s.st_mtime
1107 tf.addfile(ti, file(v['filename']))
1114 output ('Writing tarball %s successful.' % filename)
1119 def make_zip(subdir):
1120 global SILENT_MODE, data
1122 filename = "%s/%s.zip" % (BUG_DIR, subdir)
1123 zf = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED)
1126 for (k, v) in data.items():
1128 dest = os.path.join(subdir, construct_filename(k, v))
1130 if v.has_key('output'):
1131 zf.writestr(dest, v['output'].getvalue())
1133 if os.stat(v['filename']).st_size < 50:
1134 compress_type = zipfile.ZIP_STORED
1136 compress_type = zipfile.ZIP_DEFLATED
1137 zf.write(v['filename'], dest, compress_type)
1143 output ('Writing archive %s successful.' % filename)
1148 def make_inventory(inventory, subdir):
1149 document = getDOMImplementation().createDocument(
1150 None, INVENTORY_XML_ROOT, None)
1152 # create summary entry
1153 s = document.createElement(INVENTORY_XML_SUMMARY)
1154 user = os.getenv('SUDO_USER', os.getenv('USER'))
1156 s.setAttribute('user', user)
1157 s.setAttribute('date', time.strftime('%c'))
1158 s.setAttribute('hostname', platform.node())
1159 s.setAttribute('uname', ' '.join(platform.uname()))
1160 s.setAttribute('uptime', commands.getoutput(UPTIME))
1161 document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(s)
1163 map(lambda (k, v): inventory_entry(document, subdir, k, v),
1165 return document.toprettyxml()
1167 def inventory_entry(document, subdir, k, v):
1169 el = document.createElement(INVENTORY_XML_ELEMENT)
1170 el.setAttribute('capability', v['cap'])
1171 el.setAttribute('filename', os.path.join(subdir, construct_filename(k, v)))
1172 el.setAttribute('md5sum', md5sum(v))
1173 document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(el)
1180 if d.has_key('filename'):
1181 f = open(d['filename'])
1183 while len(data) > 0:
1187 elif d.has_key('output'):
1188 m.update(d['output'].getvalue())
1189 return m.hexdigest()
1192 def construct_filename(k, v):
1193 if v.has_key('filename'):
1194 if v['filename'][0] == '/':
1195 return v['filename'][1:]
1197 return v['filename']
1198 s = k.replace(' ', '-')
1199 s = s.replace('--', '-')
1200 s = s.replace('/', '%')
1201 if s.find('.') == -1:
1207 def update_capabilities():
1208 update_cap_size(CAP_HOST_CRASHDUMP_LOGS,
1209 size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE))
1210 update_cap_size(CAP_HOST_CRASHDUMP_DUMPS,
1211 size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE,
1213 update_cap_size(CAP_XAPI_DEBUG, size_of_dir(XAPI_DEBUG_DIR))
1214 update_cap_size(CAP_XENSERVER_LOGS, size_of_all(XENSERVER_LOGS))
1217 def update_cap_size(cap, size):
1218 update_cap(cap, MIN_SIZE, size)
1219 update_cap(cap, MAX_SIZE, size)
1220 update_cap(cap, CHECKED, size > 0)
1223 def update_cap(cap, k, v):
1227 caps[cap] = tuple(l)
1230 def size_of_dir(d, pattern = None, negate = False):
1231 if os.path.isdir(d):
1232 return size_of_all([os.path.join(d, fn) for fn in os.listdir(d)],
1238 def size_of_all(files, pattern = None, negate = False):
1239 return sum([size_of(f, pattern, negate) for f in files])
1242 def matches(f, pattern, negate):
1244 return not matches(f, pattern, False)
1246 return pattern is None or pattern.match(f)
1249 def size_of(f, pattern, negate):
1250 if os.path.isfile(f) and matches(f, pattern, negate):
1251 return os.stat(f)[6]
1253 return size_of_dir(f, pattern, negate)
1256 def print_capabilities():
1257 document = getDOMImplementation().createDocument(
1258 "ns", CAP_XML_ROOT, None)
1259 map(lambda key: capability(document, key), caps.keys())
1260 print document.toprettyxml()
1262 def capability(document, key):
1264 el = document.createElement(CAP_XML_ELEMENT)
1265 el.setAttribute('key', c[KEY])
1266 el.setAttribute('pii', c[PII])
1267 el.setAttribute('min-size', str(c[MIN_SIZE]))
1268 el.setAttribute('max-size', str(c[MAX_SIZE]))
1269 el.setAttribute('min-time', str(c[MIN_TIME]))
1270 el.setAttribute('max-time', str(c[MAX_TIME]))
1271 el.setAttribute('content-type', c[MIME])
1272 el.setAttribute('default-checked', c[CHECKED] and 'yes' or 'no')
1273 document.getElementsByTagName(CAP_XML_ROOT)[0].appendChild(el)
1277 format = '%%-%ds: %%s' % max(map(len, [k for k, _ in d.items()]))
1278 return '\n'.join([format % i for i in d.items()]) + '\n'
1282 yn = raw_input(prompt)
1284 return len(yn) == 0 or yn.lower()[0] == 'y'
1287 partition_re = re.compile(r'(.*[0-9]+$)|(^xvd)')
1290 command = [OVS_DPCTL, "dump-dps"]
1291 proc = Popen(command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null)
1292 (dps, err) = proc.communicate()
1293 return dps.splitlines()
1299 f = open('/proc/partitions')
1302 for line in f.readlines():
1303 (major, minor, blocks, name) = line.split()
1304 if int(major) < 254 and not partition_re.match(name):
1314 def __init__(self, command, max_time, inst=None, filter=None):
1315 self.command = command
1316 self.max_time = max_time
1318 self.running = False
1320 self.timed_out = False
1322 self.timeout = int(time.time()) + self.max_time
1323 self.filter = filter
1329 self.timed_out = False
1331 if ProcOutput.debug:
1332 output_ts("Starting '%s'" % ' '.join(self.command))
1333 self.proc = Popen(self.command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null)
1334 old = fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_GETFD)
1335 fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
1339 output_ts("'%s' failed" % ' '.join(self.command))
1340 self.running = False
1343 def terminate(self):
1346 os.kill(self.proc.pid, SIGTERM)
1350 self.running = False
1351 self.status = SIGTERM
1353 def read_line(self):
1355 line = self.proc.stdout.readline()
1358 self.status = self.proc.wait()
1360 self.running = False
1363 line = self.filter(line)
1365 self.inst.write(line)
1367 def run_procs(procs):
1375 active_procs.append(p)
1376 pipes.append(p.proc.stdout)
1378 elif p.status == None and not p.failed and not p.timed_out:
1381 active_procs.append(p)
1382 pipes.append(p.proc.stdout)
1389 (i, o, x) = select(pipes, [], [], 1.0)
1390 now = int(time.time())
1392 # handle process output
1393 for p in active_procs:
1394 if p.proc.stdout in i:
1398 if p.running and now > p.timeout:
1399 output_ts("'%s' timed out" % ' '.join(p.command))
1401 p.inst.write("\n** timeout **\n")
1409 for d in [p for p in os.listdir('/proc') if p.isdigit()]:
1411 if os.path.basename(os.readlink('/proc/%s/exe' % d)) == name:
1419 def readKeyValueFile(filename, allowed_keys = None, strip_quotes = True, assert_quotes = True):
1420 """ Reads a KEY=Value style file (e.g. xensource-inventory). Returns a
1421 dictionary of key/values in the file. Not designed for use with large files
1422 as the file is read entirely into memory."""
1424 f = open(filename, "r")
1425 lines = [x.strip("\n") for x in f.readlines()]
1428 # remove lines contain
1430 lines = filter(lambda x: True in [x.startswith(y) for y in allowed_keys],
1433 defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ]
1438 assert x.startswith("'") and x.endswith("'")
1440 defs = [ (a, quotestrip(b)) for (a,b) in defs ]
1445 class StringIOmtime(StringIO.StringIO):
1446 def __init__(self, buf = ''):
1447 StringIO.StringIO.__init__(self, buf)
1448 self.mtime = time.time()
1451 StringIO.StringIO.write(self, s)
1452 self.mtime = time.time()
1455 if __name__ == "__main__":
1458 except KeyboardInterrupt:
1459 print "\nInterrupted."