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_STATUS = 'vswitch-status'
284 CAP_X11_AUTH = 'X11-auth'
285 CAP_XAPI_DEBUG = 'xapi-debug'
286 CAP_XAPI_SUBPROCESS = 'xapi-subprocess'
287 CAP_XENSERVER_CONFIG = 'xenserver-config'
288 CAP_XENSERVER_DOMAINS = 'xenserver-domains'
289 CAP_XENSERVER_DATABASES = 'xenserver-databases'
290 CAP_XENSERVER_INSTALL = 'xenserver-install'
291 CAP_XENSERVER_LOGS = 'xenserver-logs'
292 CAP_XEN_INFO = 'xen-info'
293 CAP_XHA_LIVESET = 'xha-liveset'
301 unlimited_data = False
304 def cap(key, pii=PII_MAYBE, min_size=-1, max_size=-1, min_time=-1,
305 max_time=-1, mime=MIME_TEXT, checked=True):
306 caps[key] = (key, pii, min_size, max_size, min_time, max_time, mime,
311 cap(CAP_BLOBS, PII_NO, max_size=5*MB)
312 cap(CAP_BOOT_LOADER, PII_NO, max_size=3*KB,
314 cap(CAP_CVSM, PII_NO, max_size=3*MB,
316 cap(CAP_DISK_INFO, PII_MAYBE, max_size=25*KB,
318 cap(CAP_FIRSTBOOT, PII_YES, min_size=60*KB, max_size=80*KB)
319 cap(CAP_HARDWARE_INFO, PII_MAYBE, max_size=30*KB,
321 cap(CAP_HDPARM_T, PII_NO, min_size=0, max_size=5*KB,
322 min_time=20, max_time=90, checked=False)
323 cap(CAP_HIGH_AVAILABILITY, PII_MAYBE, max_size=5*MB)
324 cap(CAP_HOST_CRASHDUMP_DUMPS,PII_YES, checked = False)
325 cap(CAP_HOST_CRASHDUMP_LOGS, PII_NO)
326 cap(CAP_KERNEL_INFO, PII_MAYBE, max_size=80*KB,
328 cap(CAP_LOSETUP_A, PII_MAYBE, max_size=KB, max_time=5)
329 cap(CAP_MULTIPATH, PII_MAYBE, max_size=10*KB,
331 cap(CAP_NETWORK_CONFIG, PII_IF_CUSTOMIZED,
332 min_size=0, max_size=20*KB)
333 cap(CAP_NETWORK_STATUS, PII_YES, max_size=19*KB,
335 cap(CAP_PAM, PII_NO, max_size=10*KB)
336 cap(CAP_PERSISTENT_STATS, PII_MAYBE, max_size=50*MB,
338 cap(CAP_PROCESS_LIST, PII_YES, max_size=10*KB,
340 cap(CAP_SYSTEM_LOGS, PII_MAYBE, max_size=50*MB,
342 cap(CAP_SYSTEM_SERVICES, PII_NO, max_size=5*KB,
344 cap(CAP_TAPDISK_LOGS, PII_NO, max_size=64*KB)
345 cap(CAP_VNCTERM, PII_MAYBE, checked = False)
346 cap(CAP_VSWITCH_CONFIG, PII_YES,
347 min_size=0, max_size=20*MB)
348 cap(CAP_VSWITCH_STATUS, PII_YES, max_size=19*KB,
350 cap(CAP_WLB, PII_NO, max_size=3*MB,
352 cap(CAP_X11_LOGS, PII_NO, max_size=100*KB)
353 cap(CAP_X11_AUTH, PII_NO, max_size=100*KB)
354 cap(CAP_XAPI_DEBUG, PII_MAYBE, max_size=10*MB)
355 cap(CAP_XAPI_SUBPROCESS, PII_NO, max_size=5*KB,
357 cap(CAP_XENSERVER_CONFIG, PII_MAYBE, max_size=50*KB,
359 cap(CAP_XENSERVER_DOMAINS, PII_NO, max_size=1*KB,
361 cap(CAP_XENSERVER_DATABASES, PII_YES, min_size=500*KB,max_size=2*MB,
363 cap(CAP_XENSERVER_INSTALL, PII_MAYBE, min_size=10*KB, max_size=300*KB)
364 cap(CAP_XENSERVER_LOGS, PII_MAYBE, min_size=0, max_size=50*MB)
365 cap(CAP_XEN_INFO, PII_MAYBE, max_size=20*KB,
367 cap(CAP_XHA_LIVESET, PII_MAYBE, max_size=10*KB,
369 cap(CAP_YUM, PII_IF_CUSTOMIZED, max_size=10*KB,
372 ANSWER_YES_TO_ALL = False
376 dev_null = open('/dev/null', 'r+')
384 output("[%s] %s" % (time.strftime("%x %X %Z"), x))
386 def cmd_output(cap, args, label = None, filter = None):
388 a = [aa for aa in args]
389 a[0] = os.path.basename(a[0])
392 data[label] = {'cap': cap, 'cmd_args': args, 'filter': filter}
394 def file_output(cap, path_list):
397 if os.path.exists(p):
398 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
399 cap_sizes[cap] < caps[cap][MAX_SIZE]:
400 data[p] = {'cap': cap, 'filename': p}
403 cap_sizes[cap] += s.st_size
407 output("Omitting %s, size constraint of %s exceeded" % (p, cap))
409 def tree_output(cap, path, pattern = None, negate = False):
411 if os.path.exists(path):
412 for f in os.listdir(path):
413 fn = os.path.join(path, f)
414 if os.path.isfile(fn) and matches(fn, pattern, negate):
415 file_output(cap, [fn])
416 elif os.path.isdir(fn):
417 tree_output(cap, fn, pattern, negate)
419 def func_output(cap, label, func):
421 t = str(func).split()
422 data[label] = {'cap': cap, 'func': func}
427 for (k, v) in data.items():
429 if v.has_key('cmd_args'):
430 v['output'] = StringIOmtime()
431 if not process_lists.has_key(cap):
432 process_lists[cap] = []
433 process_lists[cap].append(ProcOutput(v['cmd_args'], caps[cap][MAX_TIME], v['output'], v['filter']))
434 elif v.has_key('filename') and v['filename'].startswith('/proc/'):
435 # proc files must be read into memory
437 f = open(v['filename'], 'r')
440 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
441 cap_sizes[cap] < caps[cap][MAX_SIZE]:
442 v['output'] = StringIOmtime(s)
443 cap_sizes[cap] += len(s)
445 output("Omitting %s, size constraint of %s exceeded" % (v['filename'], cap))
448 elif v.has_key('func'):
453 if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
454 cap_sizes[cap] < caps[cap][MAX_SIZE]:
455 v['output'] = StringIOmtime(s)
456 cap_sizes[cap] += len(s)
458 output("Omitting %s, size constraint of %s exceeded" % (k, cap))
460 run_procs(process_lists.values())
463 def main(argv = None):
464 global ANSWER_YES_TO_ALL, SILENT_MODE
465 global entries, data, dbg
467 # we need access to privileged files, exit if we are not running as root
469 print >>sys.stderr, "Error: xen-bugtool must be run as root"
472 output_type = 'tar.bz2'
479 (options, params) = getopt.gnu_getopt(
480 argv, 'sy', ['capabilities', 'silent', 'yestoall', 'entries=',
481 'output=', 'outfd=', 'all', 'unlimited', 'debug'])
482 except getopt.GetoptError, opterr:
483 print >>sys.stderr, opterr
486 inventory = readKeyValueFile(XENSOURCE_INVENTORY)
487 if inventory.has_key('OEM_BUILD_NUMBER'):
488 cap(CAP_OEM, PII_MAYBE, max_size=5*MB,
491 if os.getenv('XEN_RT'):
492 entries = [CAP_BLOBS, CAP_BOOT_LOADER, CAP_CVSM, CAP_DISK_INFO, CAP_FIRSTBOOT, CAP_HARDWARE_INFO,
493 CAP_HOST_CRASHDUMP_DUMPS, CAP_HOST_CRASHDUMP_LOGS, CAP_KERNEL_INFO, CAP_LOSETUP_A,
494 CAP_NETWORK_CONFIG, CAP_NETWORK_STATUS, CAP_PROCESS_LIST, CAP_HIGH_AVAILABILITY,
495 CAP_PAM, CAP_PERSISTENT_STATS, CAP_MULTIPATH,
496 CAP_SYSTEM_LOGS, CAP_SYSTEM_SERVICES, CAP_TAPDISK_LOGS,
497 CAP_VNCTERM, CAP_VSWITCH_CONFIG, CAP_VSWITCH_STATUS, CAP_WLB,
498 CAP_X11_LOGS, CAP_X11_AUTH, CAP_XAPI_DEBUG, CAP_XAPI_SUBPROCESS,
499 CAP_XENSERVER_CONFIG, CAP_XENSERVER_DOMAINS, CAP_XENSERVER_DATABASES,
500 CAP_XENSERVER_INSTALL, CAP_XENSERVER_LOGS, CAP_XEN_INFO, CAP_XHA_LIVESET, CAP_YUM]
502 entries = [e for e in caps.keys() if caps[e][CHECKED]]
504 for (k, v) in options:
505 if k == '--capabilities':
506 update_capabilities()
511 if v in ['tar', 'tar.bz2', 'zip']:
514 print >>sys.stderr, "Invalid output format '%s'" % v
517 # "-s" or "--silent" means suppress output (except for the final
518 # output filename at the end)
519 if k in ['-s', '--silent']:
522 if k == '--entries' and v != '':
523 entries = v.split(',')
525 # If the user runs the script with "-y" or "--yestoall" we don't ask
526 # all the really annoying questions.
527 if k in ['-y', '--yestoall']:
528 ANSWER_YES_TO_ALL = True
533 old = fcntl.fcntl(output_fd, fcntl.F_GETFD)
534 fcntl.fcntl(output_fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
536 print >>sys.stderr, "Invalid output file descriptor", output_fd
540 entries = caps.keys()
541 elif k == '--unlimited':
542 unlimited_data = True
545 ProcOutput.debug = True
548 print >>sys.stderr, "Invalid additional arguments", str(params)
551 if output_fd != -1 and output_type != 'tar':
552 print >>sys.stderr, "Option '--outfd' only valid with '--output=tar'"
555 if ANSWER_YES_TO_ALL:
556 output("Warning: '--yestoall' argument provided, will not prompt for individual files.")
559 This application will collate the Xen dmesg output, details of the
560 hardware configuration of your machine, information about the build of
561 Xen that you are using, plus, if you allow it, various logs.
563 The collated information will be saved as a .%s for archiving or
564 sending to a Technical Support Representative.
566 The logs may contain private information, and if you are at all
567 worried about that, you should exit now, or you should explicitly
568 exclude those logs from the archive.
572 # assemble potential data
573 tree_output(CAP_BLOBS, XAPI_BLOBS)
575 file_output(CAP_BOOT_LOADER, [GRUB_CONFIG, EXTLINUX_CONFIG])
576 cmd_output(CAP_BOOT_LOADER, [LS, '-lR', '/boot'])
577 cmd_output(CAP_BOOT_LOADER, [MD5SUM, BOOT_KERNEL, BOOT_INITRD], label='vmlinuz-initrd.md5sum')
579 func_output(CAP_CVSM, 'csl_logs', csl_logs)
581 cmd_output(CAP_DISK_INFO, [FDISK, '-l'])
582 file_output(CAP_DISK_INFO, [PROC_PARTITIONS, PROC_MOUNTS])
583 file_output(CAP_DISK_INFO, [FSTAB, ISCSI_CONF, ISCSI_INITIATOR])
584 cmd_output(CAP_DISK_INFO, [DF, '-alT'])
585 cmd_output(CAP_DISK_INFO, [DF, '-alTi'])
586 for d in disk_list():
587 cmd_output(CAP_DISK_INFO, [HDPARM, '-I', '/dev/%s' % d])
588 if len(pidof('iscsid')) != 0:
589 cmd_output(CAP_DISK_INFO, [ISCSIADM, '-m', 'node'])
590 cmd_output(CAP_DISK_INFO, [VGSCAN])
591 cmd_output(CAP_DISK_INFO, [PVS])
592 cmd_output(CAP_DISK_INFO, [VGS])
593 cmd_output(CAP_DISK_INFO, [LVS])
594 file_output(CAP_DISK_INFO, [LVM_CACHE])
595 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_host'])
596 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_disk'])
597 cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/fc_transport'])
598 cmd_output(CAP_DISK_INFO, [SG_MAP, '-x'])
599 func_output(CAP_DISK_INFO, 'scsi-hosts', dump_scsi_hosts)
600 tree_output(CAP_DISK_INFO, PROC_DRIVER_CCISS_DIR)
602 tree_output(CAP_FIRSTBOOT, FIRSTBOOT_DIR)
604 file_output(CAP_HARDWARE_INFO, [PROC_CPUINFO, PROC_MEMINFO, PROC_IOPORTS, PROC_INTERRUPTS])
605 cmd_output(CAP_HARDWARE_INFO, [DMIDECODE])
606 cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-n'])
607 cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-vv'])
608 file_output(CAP_HARDWARE_INFO, [PROC_USB_DEV, PROC_SCSI])
609 file_output(CAP_HARDWARE_INFO, [BOOT_TIME_CPUS, BOOT_TIME_MEMORY])
610 file_output(CAP_HARDWARE_INFO, [SYSCONFIG_HWCONF])
613 for d in disk_list():
614 cmd_output(CAP_HDPARM_T, [HDPARM, '-tT', '/dev/%s' % d])
616 file_output(CAP_HIGH_AVAILABILITY, [XHAD_CONF, XHA_LOG])
618 tree_output(CAP_HOST_CRASHDUMP_DUMPS, HOST_CRASHDUMPS_DIR,
619 HOST_CRASHDUMP_LOGS_RE, True)
620 tree_output(CAP_HOST_CRASHDUMP_LOGS, HOST_CRASHDUMPS_DIR,
621 HOST_CRASHDUMP_LOGS_RE, False)
623 file_output(CAP_KERNEL_INFO, [PROC_VERSION, PROC_MODULES, PROC_DEVICES,
624 PROC_FILESYSTEMS, PROC_CMDLINE])
625 cmd_output(CAP_KERNEL_INFO, [ZCAT, PROC_CONFIG], label='config')
626 cmd_output(CAP_KERNEL_INFO, [SYSCTL, '-A'])
627 file_output(CAP_KERNEL_INFO, [MODPROBE_CONF])
628 tree_output(CAP_KERNEL_INFO, MODPROBE_DIR)
630 cmd_output(CAP_LOSETUP_A, [LOSETUP, '-a'])
632 file_output(CAP_MULTIPATH, [MULTIPATH_CONF])
633 cmd_output(CAP_MULTIPATH, [DMSETUP, 'status'])
634 func_output(CAP_MULTIPATH, 'multipathd_topology', multipathd_topology)
636 tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, IFCFG_RE)
637 tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, ROUTE_RE)
638 file_output(CAP_NETWORK_CONFIG, [SYSCONFIG_NETWORK, RESOLV_CONF, NSSWITCH_CONF])
639 file_output(CAP_NETWORK_CONFIG, [NTP_CONF, IPTABLES_CONFIG, HOSTS_ALLOW, HOSTS_DENY])
641 cmd_output(CAP_NETWORK_STATUS, [IFCONFIG, '-a'])
642 cmd_output(CAP_NETWORK_STATUS, [ROUTE, '-n'])
643 cmd_output(CAP_NETWORK_STATUS, [ARP, '-n'])
644 cmd_output(CAP_NETWORK_STATUS, [NETSTAT, '-an'])
645 tree_output(CAP_NETWORK_STATUS, DHCP_LEASE_DIR)
646 cmd_output(CAP_NETWORK_STATUS, [IPTABLES, '-nL'])
647 cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'show'])
648 cmd_output(CAP_NETWORK_STATUS, [BIOSDEVNAME, '-d'])
649 for p in os.listdir('/sys/class/net/'):
650 if os.path.isdir('/sys/class/net/%s/bridge' % p):
651 cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'showmacs', p])
654 f = open('/sys/class/net/%s/type' % p, 'r')
659 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, p])
660 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-S', p])
661 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-k', p])
662 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-i', p])
663 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-c', p])
666 tree_output(CAP_NETWORK_STATUS, PROC_NET_BONDING_DIR)
667 tree_output(CAP_NETWORK_STATUS, PROC_NET_VLAN_DIR)
668 cmd_output(CAP_NETWORK_STATUS, [TC, '-s', 'qdisc'])
669 file_output(CAP_NETWORK_STATUS, [PROC_NET_SOFTNET_STAT])
671 tree_output(CAP_OEM, DELL_OMSA_LOGS)
672 file_output(CAP_OEM, [HP_CMA_LOG, HP_HPASMD_LOG])
673 if os.path.exists(OMREPORT):
674 cmd_output(CAP_OEM, [OMREPORT, 'system', 'alertlog'])
675 cmd_output(CAP_OEM, [OMREPORT, 'system', 'cmdlog'])
676 cmd_output(CAP_OEM, [OMREPORT, 'system', 'esmlog'])
677 cmd_output(CAP_OEM, [OMREPORT, 'system', 'postlog'])
678 cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'fans'])
679 cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'memory'])
680 cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'temps'])
681 cmd_output(CAP_OEM, [OMREPORT, 'storage', 'controller'])
682 for i in range(0, 4):
683 cmd_output(CAP_OEM, [OMREPORT, 'storage', 'adisk', 'controller=%d' % i])
684 cmd_output(CAP_OEM, [OMREPORT, 'storage', 'vdisk', 'controller=%d' % i])
685 cmd_output(CAP_OEM, [FIND, '/.state', '-size', '+20k', '-exec', 'ls', '-l', '{}',';'],
688 tree_output(CAP_PAM, PAM_DIR)
690 func_output(CAP_PERSISTENT_STATS, 'xapi_rrd-host', dump_xapi_rrds)
692 cmd_output(CAP_PROCESS_LIST, [PS, 'wwwaxf', '-eo', 'pid,tty,stat,time,nice,psr,pcpu,pmem,wchan:25,args'], label='process-tree')
694 file_output(CAP_SYSTEM_LOGS,
695 [ VAR_LOG_DIR + x for x in
696 [ 'syslog', 'messages', 'monitor_memory.log', 'secure', 'debug', 'dmesg', 'boot.msg' ] +
697 [ f % n for n in range(1, 20) \
698 for f in ['messages.%d', 'messages.%d.gz', 'monitor_memory.log.%d',
699 'monitor_memory.log.%d.gz', 'secure.%d', 'secure.%d.gz']]])
700 if not os.path.exists('/var/log/dmesg') and not os.path.exists('/var/log/boot.msg'):
701 cmd_output(CAP_SYSTEM_LOGS, [DMESG])
703 cmd_output(CAP_SYSTEM_SERVICES, [CHKCONFIG, '--list'])
705 if CAP_TAPDISK_LOGS in entries:
706 generate_tapdisk_logs()
708 tree_output(CAP_VNCTERM, VNCTERM_CORE_DIR)
710 file_output(CAP_VSWITCH_CONFIG, [OVS_VSWITCH_CONF])
712 cmd_output(CAP_VSWITCH_STATUS, [OVS_DPCTL, 'show'])
713 tree_output(CAP_VSWITCH_STATUS, VSWITCH_CORE_DIR)
715 cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'show', d])
716 cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'status', d])
717 cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'dump-flows', d])
718 cmd_output(CAP_VSWITCH_STATUS, [OVS_DPCTL, 'dump-flows', d])
720 cmd_output(CAP_WLB, [XE, 'pool-retrieve-wlb-diagnostics'])
722 tree_output(CAP_X11_LOGS, X11_LOGS_DIR, X11_LOGS_RE)
723 tree_output(CAP_X11_AUTH, X11_AUTH_DIR, X11_AUTH_RE)
725 tree_output(CAP_XAPI_DEBUG, XAPI_DEBUG_DIR)
727 func_output(CAP_XAPI_SUBPROCESS, 'xapi_subprocesses', dump_xapi_subprocess_info)
729 file_output(CAP_XENSERVER_CONFIG, [INITIAL_INVENTORY])
730 file_output(CAP_XENSERVER_CONFIG, [POOL_CONF, PTOKEN, XAPI_CONF, XAPI_SSL_CONF, STATIC_VDIS,
731 XENSOURCE_INVENTORY, VENDORKERNEL_INVENTORY])
732 cmd_output(CAP_XENSERVER_CONFIG, [LS, '-lR', '/opt/xensource'])
733 cmd_output(CAP_XENSERVER_CONFIG, [BIN_STATIC_VDIS, 'list'])
734 tree_output(CAP_XENSERVER_CONFIG, OEM_CONFIG_DIR, OEM_CONFIG_FILES_RE)
736 func_output(CAP_XENSERVER_DATABASES, 'xapi-db.xml', dump_filtered_xapi_db)
737 cmd_output(CAP_XENSERVER_DATABASES, [XENSTORE_LS])
738 file_output(CAP_XENSERVER_DATABASES, [DB_CONF, DB_CONF_RIO, DB_DEFAULT_FIELDS, DB_SCHEMA_SQL])
739 tree_output(CAP_XENSERVER_DATABASES, OEM_CONFIG_DIR, OEM_DB_FILES_RE)
740 file_output(CAP_XENSERVER_DATABASES, [XENSTORED_DB, XENSTORED_DB + '.bak'])
741 cmd_output(CAP_XENSERVER_DATABASES, [XE, 'pool-dump-database', 'file-name='],
742 label="xapi-db-dumped.xml", filter=filter_db_pii)
743 cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'watches'])
744 cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'quotas'])
746 cmd_output(CAP_XENSERVER_DOMAINS, [LIST_DOMAINS])
748 tree_output(CAP_XENSERVER_INSTALL, VAR_LOG_DIR + 'installer')
749 file_output(CAP_XENSERVER_INSTALL,
750 [ VAR_LOG_DIR + x for x in
751 [ 'firstboot-SR-commands-log',
752 'upgrade-commands-log', 'generate-iscsi-iqn-log']] +
753 [ '/root/' + x for x in
754 [ 'blockdevs-log', 'cmdline-log', 'devcontents-log',
755 'dmesg-log', 'install-log', 'lspci-log', 'modules-log',
756 'pci-log', 'processes-log', 'tty-log', 'uname-log',
758 tree_output(CAP_XENSERVER_INSTALL, INSTALLED_REPOS_DIR)
759 tree_output(CAP_XENSERVER_INSTALL, PATCH_APPLIED_DIR)
761 file_output(CAP_XENSERVER_LOGS, [LOG_CONF])
762 file_output(CAP_XENSERVER_LOGS, XENSERVER_LOGS)
763 tree_output(CAP_XENSERVER_LOGS, OEM_CONFIG_DIR, OEM_XENSERVER_LOGS_RE)
767 data = xc.readconsolering()
768 xc.send_debug_keys('q')
772 xc = xen.lowlevel.xc.xc()
774 func_output(CAP_XEN_INFO, 'xen-dmesg', lambda x: xen_dmesg(xc))
775 func_output(CAP_XEN_INFO, 'physinfo', lambda x: prettyDict(xc.physinfo()))
776 func_output(CAP_XEN_INFO, 'xeninfo', lambda x: prettyDict(xc.xeninfo()))
779 file_output(CAP_XEN_INFO, [PROC_XEN_BALLOON])
781 cmd_output(CAP_XHA_LIVESET, [HA_QUERY_LIVESET])
783 file_output(CAP_YUM, [YUM_LOG])
784 tree_output(CAP_YUM, YUM_REPOS_DIR)
785 cmd_output(CAP_YUM, [RPM, '-qa'])
787 # permit the user to filter out data
788 for k in sorted(data.keys()):
789 if not ANSWER_YES_TO_ALL and not yes("Include '%s'? [Y/n]: " % k):
792 # collect selected data now
793 output_ts('Running commands to collect data')
796 subdir = os.getenv('XENRT_BUGTOOL_BASENAME')
798 subdir = os.path.basename(subdir)
799 if subdir == '..' or subdir == '.':
802 subdir = "bug-report-%s" % time.strftime("%Y%m%d%H%M%S")
805 data['inventory.xml'] = {'cap': None, 'output': StringIOmtime(make_inventory(data, subdir))}
808 if output_fd == -1 and not os.path.exists(BUG_DIR):
815 output_ts('Creating output file')
817 if output_type.startswith('tar'):
818 make_tar(subdir, output_type, output_fd)
825 print >>sys.stderr, "Category sizes (max, actual):\n"
826 for c in caps.keys():
827 print >>sys.stderr, " %s (%d, %d)" % (c, caps[c][MAX_SIZE],
831 def generate_tapdisk_logs():
832 for pid in pidof('tapdisk'):
834 os.kill(pid, SIGUSR1)
835 output_ts("Including logs for tapdisk process %d" % pid)
838 # give processes a second to write their logs
840 file_output(CAP_TAPDISK_LOGS, ['/tmp/tapdisk.log.%d' % pid for pid in pidof('tapdisk')])
842 def clean_tapdisk_logs():
843 for filename in [f for f in os.listdir('/tmp') if f.startswith('tapdisk.log.')]:
845 os.remove(os.path.join('tmp', filename))
849 def dump_xapi_subprocess_info(cap):
850 """Check which fds are open by xapi and its subprocesses to diagnose faults like CA-10543.
851 Returns a string containing a pretty-printed pstree-like structure. """
852 pids = filter(lambda x: x.isdigit(), os.listdir("/proc"))
853 def readlines(filename):
856 f = open(filename, "r")
857 lines = f.readlines()
863 all = readlines("/proc/" + pid + "/cmdline")
867 return all[0].replace('\x00', ' ')
869 for i in readlines("/proc/" + pid + "/status"):
870 if i.startswith("PPid:"):
874 result = { "cmdline": cmdline(pid) }
875 child_pids = filter(lambda x:parent(x) == pid, pids)
877 for child in child_pids:
878 children[child] = pstree(child)
879 result['children'] = children
881 for fd in os.listdir("/proc/" + pid + "/fd"):
883 fds[fd] = os.readlink("/proc/" + pid + "/fd/" + fd)
888 xapis = filter(lambda x: cmdline(x).startswith("/opt/xensource/bin/xapi"), pids)
889 xapis = filter(lambda x: parent(x) == "1", xapis)
892 result[xapi] = pstree(xapi)
893 pp = pprint.PrettyPrinter(indent=4)
894 return pp.pformat(result)
896 def dump_xapi_rrds(cap):
897 socket.setdefaulttimeout(5)
898 session = XenAPI.xapi_local()
899 session.xenapi.login_with_password('', '')
900 this_host = session.xenapi.session.get_this_host(session._session)
901 # better way to find pool master?
902 pool = session.xenapi.pool.get_all_records().values()[0]
903 i_am_master = (this_host == pool['master'])
905 for vm in session.xenapi.VM.get_all_records().values():
906 if vm['is_a_template']:
908 if vm['resident_on'] == this_host or (i_am_master and vm['power_state'] in ['Suspended', 'Halted']):
909 rrd = urllib.urlopen('http://localhost/vm_rrd?session_id=%s&uuid=%s' % (session._session, vm['uuid']))
911 (i, o, x) = select([rrd], [], [], 5.0)
913 data['xapi_rrd-%s' % vm['uuid']] = {'cap': cap,
914 'output': StringIOmtime(rrd.read())}
919 rrd = urllib.urlopen('http://localhost/host_rrd?session_id=%s' % session._session)
926 session.xenapi.session.logout()
929 def filter_db_pii(str):
930 str = re.sub(r'(password_transformed" ")[^ ]+(")', r'\1REMOVED\2', str)
931 str = re.sub(r'(wlb_password=")[^"]+(")', r'\1REMOVED\2', str)
934 def dump_filtered_xapi_db(cap):
938 # determine db format
939 c = open(DB_CONF, 'r')
942 l = line.rstrip('\n')
943 if l.startswith('['):
945 if l.startswith('format:'):
955 if format == 'sqlite':
956 pipe = Popen([XAPI_DB_PROCESS, '-xmltostdout'], bufsize=1, stdin=dev_null,
957 stdout=PIPE, stderr=dev_null)
960 ih = open(db_file, 'r')
972 remain = remain[p+1:]
973 output += filter_db_pii(str)
984 def dump_scsi_hosts(cap):
986 l = os.listdir('/sys/class/scsi_host')
992 f = open('/sys/class/scsi_host/%s/proc_name' % h)
993 procname = f.readline().strip("\n")
999 f = open('/sys/class/scsi_host/%s/model_name' % h)
1000 modelname = f.readline().strip("\n")
1005 output += "%s:\n" %h
1006 output += " %s%s\n" % (procname, modelname and (" -> %s" % modelname) or '')
1011 socket.setdefaulttimeout(5)
1012 session = XenAPI.xapi_local()
1013 session.xenapi.login_with_password('', '')
1014 this_host = session.xenapi.session.get_this_host(session._session)
1015 # better way to find pool master?
1016 pool = session.xenapi.pool.get_all_records().values()[0]
1017 i_am_master = (this_host == pool['master'])
1019 output = StringIO.StringIO()
1022 def rotate_string(x, n):
1024 for a in range(0, 256):
1025 transtbl = transtbl + chr(a)
1026 transtbl = transtbl[n:] + transtbl[0:n]
1027 return x.translate(transtbl)
1029 def _untransform_string(str, remove_trailing_nulls=False):
1030 """De-obfuscate string. To cope with an obfuscation bug in Rio, the argument
1031 remove_trailing_nulls should be set to True"""
1032 tmp = base64.decodestring(str)
1033 if remove_trailing_nulls:
1034 tmp = tmp.rstrip('\x00')
1035 return rotate_string(tmp, -13)
1037 for pbd in session.xenapi.PBD.get_all_records().values():
1038 if pbd.has_key('device_config') and pbd['device_config'].has_key('target'):
1039 sr = session.xenapi.SR.get_record(pbd['SR'])
1040 if sr.has_key('type') and sr['type'] == 'cslg':
1041 if sr['shared'] and pbd['host'] != this_host and not i_am_master:
1044 dev_cfg = pbd['device_config']
1045 server = "server=%s" % socket.gethostbyname(dev_cfg['target'])
1046 if dev_cfg.has_key('port'):
1047 server += ':' + dev_cfg['port']
1048 if dev_cfg.has_key('username'):
1049 server += ',' + dev_cfg['username']
1050 if dev_cfg.has_key('password_transformed'):
1051 server += ',' + _untransform_string(dev_cfg['password_transformed'])
1052 procs.append(ProcOutput([CSL, server, 'srv-log-get'], caps[cap][MAX_TIME], output))
1054 session.xenapi.session.logout()
1058 return output.getvalue()
1060 def multipathd_topology(cap):
1061 pipe = Popen([MULTIPATHD, '-k'], bufsize=1, stdin=PIPE,
1062 stdout=PIPE, stderr=dev_null)
1063 stdout, stderr = pipe.communicate('show topology')
1067 def make_tar(subdir, suffix, output_fd):
1068 global SILENT_MODE, data
1071 if suffix == 'tar.bz2':
1073 filename = "%s/%s.%s" % (BUG_DIR, subdir, suffix)
1076 tf = tarfile.open(filename, mode)
1078 tf = tarfile.open(None, 'w', os.fdopen(output_fd, 'a'))
1081 for (k, v) in data.items():
1083 tar_filename = os.path.join(subdir, construct_filename(k, v))
1084 ti = tarfile.TarInfo(tar_filename)
1089 if v.has_key('output'):
1090 ti.mtime = v['output'].mtime
1091 ti.size = len(v['output'].getvalue())
1093 tf.addfile(ti, v['output'])
1094 elif v.has_key('filename'):
1095 s = os.stat(v['filename'])
1096 ti.mtime = s.st_mtime
1098 tf.addfile(ti, file(v['filename']))
1105 output ('Writing tarball %s successful.' % filename)
1110 def make_zip(subdir):
1111 global SILENT_MODE, data
1113 filename = "%s/%s.zip" % (BUG_DIR, subdir)
1114 zf = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED)
1117 for (k, v) in data.items():
1119 dest = os.path.join(subdir, construct_filename(k, v))
1121 if v.has_key('output'):
1122 zf.writestr(dest, v['output'].getvalue())
1124 if os.stat(v['filename']).st_size < 50:
1125 compress_type = zipfile.ZIP_STORED
1127 compress_type = zipfile.ZIP_DEFLATED
1128 zf.write(v['filename'], dest, compress_type)
1134 output ('Writing archive %s successful.' % filename)
1139 def make_inventory(inventory, subdir):
1140 document = getDOMImplementation().createDocument(
1141 None, INVENTORY_XML_ROOT, None)
1143 # create summary entry
1144 s = document.createElement(INVENTORY_XML_SUMMARY)
1145 user = os.getenv('SUDO_USER', os.getenv('USER'))
1147 s.setAttribute('user', user)
1148 s.setAttribute('date', time.strftime('%c'))
1149 s.setAttribute('hostname', platform.node())
1150 s.setAttribute('uname', ' '.join(platform.uname()))
1151 s.setAttribute('uptime', commands.getoutput(UPTIME))
1152 document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(s)
1154 map(lambda (k, v): inventory_entry(document, subdir, k, v),
1156 return document.toprettyxml()
1158 def inventory_entry(document, subdir, k, v):
1160 el = document.createElement(INVENTORY_XML_ELEMENT)
1161 el.setAttribute('capability', v['cap'])
1162 el.setAttribute('filename', os.path.join(subdir, construct_filename(k, v)))
1163 el.setAttribute('md5sum', md5sum(v))
1164 document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(el)
1171 if d.has_key('filename'):
1172 f = open(d['filename'])
1174 while len(data) > 0:
1178 elif d.has_key('output'):
1179 m.update(d['output'].getvalue())
1180 return m.hexdigest()
1183 def construct_filename(k, v):
1184 if v.has_key('filename'):
1185 if v['filename'][0] == '/':
1186 return v['filename'][1:]
1188 return v['filename']
1189 s = k.replace(' ', '-')
1190 s = s.replace('--', '-')
1191 s = s.replace('/', '%')
1192 if s.find('.') == -1:
1198 def update_capabilities():
1199 update_cap_size(CAP_HOST_CRASHDUMP_LOGS,
1200 size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE))
1201 update_cap_size(CAP_HOST_CRASHDUMP_DUMPS,
1202 size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE,
1204 update_cap_size(CAP_XAPI_DEBUG, size_of_dir(XAPI_DEBUG_DIR))
1205 update_cap_size(CAP_XENSERVER_LOGS, size_of_all(XENSERVER_LOGS))
1208 def update_cap_size(cap, size):
1209 update_cap(cap, MIN_SIZE, size)
1210 update_cap(cap, MAX_SIZE, size)
1211 update_cap(cap, CHECKED, size > 0)
1214 def update_cap(cap, k, v):
1218 caps[cap] = tuple(l)
1221 def size_of_dir(d, pattern = None, negate = False):
1222 if os.path.isdir(d):
1223 return size_of_all([os.path.join(d, fn) for fn in os.listdir(d)],
1229 def size_of_all(files, pattern = None, negate = False):
1230 return sum([size_of(f, pattern, negate) for f in files])
1233 def matches(f, pattern, negate):
1235 return not matches(f, pattern, False)
1237 return pattern is None or pattern.match(f)
1240 def size_of(f, pattern, negate):
1241 if os.path.isfile(f) and matches(f, pattern, negate):
1242 return os.stat(f)[6]
1244 return size_of_dir(f, pattern, negate)
1247 def print_capabilities():
1248 document = getDOMImplementation().createDocument(
1249 "ns", CAP_XML_ROOT, None)
1250 map(lambda key: capability(document, key), caps.keys())
1251 print document.toprettyxml()
1253 def capability(document, key):
1255 el = document.createElement(CAP_XML_ELEMENT)
1256 el.setAttribute('key', c[KEY])
1257 el.setAttribute('pii', c[PII])
1258 el.setAttribute('min-size', str(c[MIN_SIZE]))
1259 el.setAttribute('max-size', str(c[MAX_SIZE]))
1260 el.setAttribute('min-time', str(c[MIN_TIME]))
1261 el.setAttribute('max-time', str(c[MAX_TIME]))
1262 el.setAttribute('content-type', c[MIME])
1263 el.setAttribute('default-checked', c[CHECKED] and 'yes' or 'no')
1264 document.getElementsByTagName(CAP_XML_ROOT)[0].appendChild(el)
1268 format = '%%-%ds: %%s' % max(map(len, [k for k, _ in d.items()]))
1269 return '\n'.join([format % i for i in d.items()]) + '\n'
1273 yn = raw_input(prompt)
1275 return len(yn) == 0 or yn.lower()[0] == 'y'
1278 partition_re = re.compile(r'(.*[0-9]+$)|(^xvd)')
1281 command = [OVS_DPCTL, "dump-dps"]
1282 proc = Popen(command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null)
1283 (dps, err) = proc.communicate()
1284 return dps.splitlines()
1290 f = open('/proc/partitions')
1293 for line in f.readlines():
1294 (major, minor, blocks, name) = line.split()
1295 if int(major) < 254 and not partition_re.match(name):
1305 def __init__(self, command, max_time, inst=None, filter=None):
1306 self.command = command
1307 self.max_time = max_time
1309 self.running = False
1311 self.timed_out = False
1313 self.timeout = int(time.time()) + self.max_time
1314 self.filter = filter
1320 self.timed_out = False
1322 if ProcOutput.debug:
1323 output_ts("Starting '%s'" % ' '.join(self.command))
1324 self.proc = Popen(self.command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null)
1325 old = fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_GETFD)
1326 fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
1330 output_ts("'%s' failed" % ' '.join(self.command))
1331 self.running = False
1334 def terminate(self):
1337 os.kill(self.proc.pid, SIGTERM)
1341 self.running = False
1342 self.status = SIGTERM
1344 def read_line(self):
1346 line = self.proc.stdout.readline()
1349 self.status = self.proc.wait()
1351 self.running = False
1354 line = self.filter(line)
1356 self.inst.write(line)
1358 def run_procs(procs):
1366 active_procs.append(p)
1367 pipes.append(p.proc.stdout)
1369 elif p.status == None and not p.failed and not p.timed_out:
1372 active_procs.append(p)
1373 pipes.append(p.proc.stdout)
1380 (i, o, x) = select(pipes, [], [], 1.0)
1381 now = int(time.time())
1383 # handle process output
1384 for p in active_procs:
1385 if p.proc.stdout in i:
1389 if p.running and now > p.timeout:
1390 output_ts("'%s' timed out" % ' '.join(p.command))
1392 p.inst.write("\n** timeout **\n")
1400 for d in [p for p in os.listdir('/proc') if p.isdigit()]:
1402 if os.path.basename(os.readlink('/proc/%s/exe' % d)) == name:
1410 def readKeyValueFile(filename, allowed_keys = None, strip_quotes = True, assert_quotes = True):
1411 """ Reads a KEY=Value style file (e.g. xensource-inventory). Returns a
1412 dictionary of key/values in the file. Not designed for use with large files
1413 as the file is read entirely into memory."""
1415 f = open(filename, "r")
1416 lines = [x.strip("\n") for x in f.readlines()]
1419 # remove lines contain
1421 lines = filter(lambda x: True in [x.startswith(y) for y in allowed_keys],
1424 defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ]
1429 assert x.startswith("'") and x.endswith("'")
1431 defs = [ (a, quotestrip(b)) for (a,b) in defs ]
1436 class StringIOmtime(StringIO.StringIO):
1437 def __init__(self, buf = ''):
1438 StringIO.StringIO.__init__(self, buf)
1439 self.mtime = time.time()
1442 StringIO.StringIO.write(self, s)
1443 self.mtime = time.time()
1446 if __name__ == "__main__":
1449 except KeyboardInterrupt:
1450 print "\nInterrupted."