+++ /dev/null
-#!/usr/bin/env python
-
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of version 2.1 of the GNU Lesser General Public
-# License as published by the Free Software Foundation.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# Copyright (c) 2005, 2007 XenSource Ltd.
-
-
-#
-# To add new entries to the bugtool, you need to:
-#
-# Create a new capability. These declare the new entry to the GUI, including
-# the expected size, time to collect, privacy implications, and whether the
-# capability should be selected by default. One capability may refer to
-# multiple files, assuming that they can be reasonably grouped together, and
-# have the same privacy implications. You need:
-#
-# A new CAP_ constant.
-# A cap() invocation to declare the capability.
-#
-# You then need to add calls to main() to collect the files. These will
-# typically be calls to the helpers file_output(), tree_output(), cmd_output(),
-# or func_output().
-#
-
-import getopt
-import re
-import os
-import StringIO
-import sys
-import tarfile
-import time
-import commands
-import pprint
-from xml.dom.minidom import parse, getDOMImplementation
-import zipfile
-from subprocess import Popen, PIPE
-from select import select
-from signal import SIGTERM, SIGUSR1
-import md5
-import platform
-import fcntl
-import glob
-import urllib
-import socket
-import base64
-
-sys.path.append('/usr/lib/python')
-sys.path.append('/usr/lib64/python')
-
-import xen.lowlevel.xc
-import XenAPI
-
-OS_RELEASE = platform.release()
-
-#
-# Files & directories
-#
-
-BUG_DIR = "/var/opt/xen/bug-report"
-PLUGIN_DIR = "/etc/xensource/bugtool"
-XAPI_BLOBS = '/var/xapi/blobs'
-EXTLINUX_CONFIG = '/boot/extlinux.conf'
-GRUB_CONFIG = '/boot/grub/menu.lst'
-BOOT_KERNEL = '/boot/vmlinuz-' + OS_RELEASE
-BOOT_INITRD = '/boot/initrd-' + OS_RELEASE + '.img'
-PROC_PARTITIONS = '/proc/partitions'
-FSTAB = '/etc/fstab'
-PROC_MOUNTS = '/proc/mounts'
-ISCSI_CONF = '/etc/iscsi/iscsid.conf'
-ISCSI_INITIATOR = '/etc/iscsi/initiatorname.iscsi'
-LVM_CACHE = '/etc/lvm/cache/.cache'
-LVM_CONFIG = '/etc/lvm/lvm.conf'
-PROC_CPUINFO = '/proc/cpuinfo'
-PROC_MEMINFO = '/proc/meminfo'
-PROC_IOPORTS = '/proc/ioports'
-PROC_INTERRUPTS = '/proc/interrupts'
-PROC_SCSI = '/proc/scsi/scsi'
-FIRSTBOOT_DIR = '/etc/firstboot.d'
-PROC_VERSION = '/proc/version'
-PROC_MODULES = '/proc/modules'
-PROC_DEVICES = '/proc/devices'
-PROC_FILESYSTEMS = '/proc/filesystems'
-PROC_CMDLINE = '/proc/cmdline'
-PROC_CONFIG = '/proc/config.gz'
-PROC_USB_DEV = '/proc/bus/usb/devices'
-PROC_XEN_BALLOON = '/proc/xen/balloon'
-PROC_NET_BONDING_DIR = '/proc/net/bonding'
-PROC_NET_VLAN_DIR = '/proc/net/vlan'
-PROC_NET_SOFTNET_STAT = '/proc/net/softnet_stat'
-PROC_DRIVER_CCISS_DIR = '/proc/driver/cciss'
-MODPROBE_CONF = '/etc/modprobe.conf'
-MODPROBE_DIR = '/etc/modprobe.d'
-BOOT_TIME_CPUS = '/etc/xensource/boot_time_cpus'
-BOOT_TIME_MEMORY = '/etc/xensource/boot_time_memory'
-SYSCONFIG_HWCONF = '/etc/sysconfig/hwconf'
-SYSCONFIG_NETWORK = '/etc/sysconfig/network'
-SYSCONFIG_NETWORK_SCRIPTS = '/etc/sysconfig/network-scripts'
-IFCFG_RE = re.compile(r'^.*/ifcfg-.*')
-ROUTE_RE = re.compile(r'^.*/route-.*')
-NETWORK_DBCACHE = '/var/xapi/network.dbcache'
-RESOLV_CONF = '/etc/resolv.conf'
-MPP_CONF = '/etc/mpp.conf'
-MULTIPATH_CONF = '/etc/multipath.conf'
-NSSWITCH_CONF = '/etc/nsswitch.conf'
-NTP_CONF = '/etc/ntp.conf'
-IPTABLES_CONFIG = '/etc/sysconfig/iptables-config'
-HOSTS = '/etc/hosts'
-HOSTS_ALLOW = '/etc/hosts.allow'
-HOSTS_DENY = '/etc/hosts.deny'
-DHCP_LEASE_DIR = '/var/lib/dhclient'
-OPENVSWITCH_CORE_DIR = '/var/xen/openvswitch'
-OPENVSWITCH_CONF = '/etc/ovs-vswitchd.conf'
-OPENVSWITCH_CONF_DB = '/etc/openvswitch/conf.db'
-OPENVSWITCH_VSWITCHD_PID = '/var/run/openvswitch/ovs-vswitchd.pid'
-VAR_LOG_DIR = '/var/log/'
-VNCTERM_CORE_DIR = '/var/xen/vncterm'
-XENSOURCE_INVENTORY = '/etc/xensource-inventory'
-OEM_CONFIG_DIR = '/var/xsconfig'
-OEM_CONFIG_FILES_RE = re.compile(r'^.*xensource-inventory$')
-OEM_DB_FILES_RE = re.compile(r'^.*state\.db')
-INITIAL_INVENTORY = '/opt/xensource/etc/initial-inventory'
-VENDORKERNEL_INVENTORY = '/etc/vendorkernel-inventory'
-STATIC_VDIS = '/etc/xensource/static-vdis'
-POOL_CONF = '/etc/xensource/pool.conf'
-NETWORK_CONF = '/etc/xensource/network.conf'
-PTOKEN = '/etc/xensource/ptoken'
-XAPI_CONF = '/etc/xensource/xapi.conf'
-XAPI_SSL_CONF = '/etc/xensource/xapi-ssl.conf'
-DB_CONF = '/etc/xensource/db.conf'
-DB_CONF_RIO = '/etc/xensource/db.conf.rio'
-DB_DEFAULT_FIELDS = '/etc/xensource/db-default-fields'
-DB_SCHEMA_SQL = '/etc/xensource/db_schema.sql'
-XENSTORED_DB = '/var/lib/xenstored/tdb'
-HOST_CRASHDUMPS_DIR = '/var/crash'
-HOST_CRASHDUMP_LOGS_RE = re.compile(r'^.*\.log$')
-X11_LOGS_DIR = VAR_LOG_DIR
-X11_LOGS_RE = re.compile(r'.*/Xorg\..*$')
-X11_AUTH_DIR = '/root/'
-X11_AUTH_RE = re.compile(r'.*/\.((Xauthority)|(serverauth\.[0-9]*))$')
-XAPI_DEBUG_DIR = '/var/xapi/debug'
-LOG_CONF = '/etc/xensource/log.conf'
-INSTALLED_REPOS_DIR = '/etc/xensource/installed-repos'
-PATCH_APPLIED_DIR = '/var/patch/applied'
-XENSERVER_LOGS = \
- [ VAR_LOG_DIR + x for x in
- ['xensource.log', 'audit.log', 'xenstored-access.log', 'SMlog', 'VMPRlog', 'xen/xenstored-trace.log',
- 'xen/xen-hotplug.log', 'xen/domain-builder-ng.log', 'squeezed.log',
- 'openvswitch/ovs-vswitchd.log', 'openvswitch/ovsdb-server.log' ] +
- [ f % n for n in range(1, 20) \
- for f in ['xensource.log.%d', 'xensource.log.%d.gz','SMlog.%d', 'SMlog.%d.gz', 'VMPRlog.%d', 'VMPRlog.%d.gz',
- 'audit.log.%d', 'audit.log.%d.gz', 'xenstored-access.log.%d', 'xenstored-access.log.%d.gz', \
- 'xen/xenstored-access.log.%d', 'xen/xenstored-access.log.%d.gz', 'squeezed.log.%d', \
- 'openvswitch/ovs-vswitchd.log.%d', 'openvswitch/ovs-vswitchd.log.%d.gz', \
- 'openvswitch/ovsdb-server.log.%d', 'openvswitch/ovsdb-server.log.%d.gz']]] \
- + glob.glob('/tmp/qemu.[0-9]*')
-OEM_XENSERVER_LOGS_RE = re.compile(r'^.*xensource\.log$')
-XHA_LOG = '/var/log/xha.log'
-XHAD_CONF = '/etc/xensource/xhad.conf'
-YUM_LOG = '/var/log/yum.log'
-YUM_REPOS_DIR = '/etc/yum.repos.d'
-PAM_DIR = '/etc/pam.d'
-FIST_RE = re.compile(r'.*/fist_')
-LICENSE_LOGS = \
- [ VAR_LOG_DIR + x for x in
- ['v6d.log'] +
- [ f % n for n in range(1, 20) \
- for f in ['v6d.log.%d', 'v6d.log.%d.gz' ]]]
-LWIDENTITY_JOIN_LOG = '/tmp/lwidentity.join.log'
-HOSTS_LWIDENTITY_ORIG = '/etc/hosts.lwidentity.orig'
-KRB5_CONF = '/etc/krb5.conf'
-LIKEWISE_DIR = '/var/lib/likewise'
-XENGUEST_LOG = '/tmp/xenguest.log'
-
-#
-# External programs
-#
-
-ARP = '/sbin/arp'
-BIOSDEVNAME = '/sbin/biosdevname'
-BRCTL = '/usr/sbin/brctl'
-CAT = '/bin/cat'
-CHKCONFIG = '/sbin/chkconfig'
-CSL = '/opt/Citrix/StorageLink/bin/csl'
-DF = '/bin/df'
-DMESG = '/bin/dmesg'
-DMIDECODE = '/usr/sbin/dmidecode'
-DMSETUP = '/sbin/dmsetup'
-ETHTOOL = '/sbin/ethtool'
-FDISK = '/sbin/fdisk'
-FIND = '/usr/bin/find'
-HA_QUERY_LIVESET = '/opt/xensource/debug/debug_ha_query_liveset'
-HDPARM = '/sbin/hdparm'
-IFCONFIG = '/sbin/ifconfig'
-IPTABLES = '/sbin/iptables'
-ISCSIADM = '/sbin/iscsiadm'
-LIST_DOMAINS = '/opt/xensource/bin/list_domains'
-LOSETUP = '/sbin/losetup'
-LS = '/bin/ls'
-LSPCI = '/sbin/lspci'
-LVS = '/usr/sbin/lvs'
-LVDISPLAY = '/usr/sbin/lvdisplay'
-MD5SUM = '/usr/bin/md5sum'
-MODINFO = '/sbin/modinfo'
-MPPUTIL = '/usr/sbin/mppUtil'
-MULTIPATHD = '/sbin/multipathd'
-NETSTAT = '/bin/netstat'
-OVS_DPCTL = '/usr/bin/ovs-dpctl'
-OVS_OFCTL = '/usr/bin/ovs-ofctl'
-OVS_VSCTL = '/usr/bin/ovs-vsctl'
-OVS_APPCTL = '/usr/bin/ovs-appctl'
-PS = '/bin/ps'
-PVS = '/usr/sbin/pvs'
-ROUTE = '/sbin/route'
-RPM = '/bin/rpm'
-SG_MAP = '/usr/bin/sg_map'
-SQLITE = '/usr/bin/sqlite3'
-BIN_STATIC_VDIS = '/opt/xensource/bin/static-vdis'
-SYSCTL = '/sbin/sysctl'
-TC = '/sbin/tc'
-UPTIME = '/usr/bin/uptime'
-VGS = '/usr/sbin/vgs'
-VGSCAN = '/sbin/vgscan'
-XAPI_DB_PROCESS = '/opt/xensource/bin/xapi-db-process'
-XE = '/opt/xensource/bin/xe'
-XS = '/opt/xensource/debug/xs'
-XENSTORE_LS = '/usr/bin/xenstore-ls'
-ZCAT = '/bin/zcat'
-
-#
-# PII -- Personally identifiable information. Of particular concern are
-# things that would identify customers, or their network topology.
-# Passwords are never to be included in any bug report, regardless of any PII
-# declaration.
-#
-# NO -- No PII will be in these entries.
-# YES -- PII will likely or certainly be in these entries.
-# MAYBE -- The user may wish to audit these entries for PII.
-# IF_CUSTOMIZED -- If the files are unmodified, then they will contain no PII,
-# but since we encourage customers to edit these files, PII may have been
-# introduced by the customer. This is used in particular for the networking
-# scripts in dom0.
-#
-
-PII_NO = 'no'
-PII_YES = 'yes'
-PII_MAYBE = 'maybe'
-PII_IF_CUSTOMIZED = 'if_customized'
-KEY = 0
-PII = 1
-MIN_SIZE = 2
-MAX_SIZE = 3
-MIN_TIME = 4
-MAX_TIME = 5
-MIME = 6
-CHECKED = 7
-HIDDEN = 8
-
-MIME_DATA = 'application/data'
-MIME_TEXT = 'text/plain'
-
-INVENTORY_XML_ROOT = "system-status-inventory"
-INVENTORY_XML_SUMMARY = 'system-summary'
-INVENTORY_XML_ELEMENT = 'inventory-entry'
-CAP_XML_ROOT = "system-status-capabilities"
-CAP_XML_ELEMENT = 'capability'
-
-
-CAP_BLOBS = 'blobs'
-CAP_BOOT_LOADER = 'boot-loader'
-CAP_CVSM = 'CVSM'
-CAP_DISK_INFO = 'disk-info'
-CAP_FIRSTBOOT = 'firstboot'
-CAP_HARDWARE_INFO = 'hardware-info'
-CAP_HDPARM_T = 'hdparm-t'
-CAP_HIGH_AVAILABILITY = 'high-availability'
-CAP_HOST_CRASHDUMP_DUMPS = 'host-crashdump-dumps'
-CAP_HOST_CRASHDUMP_LOGS = 'host-crashdump-logs'
-CAP_KERNEL_INFO = 'kernel-info'
-CAP_LOSETUP_A = 'loopback-devices'
-CAP_MULTIPATH = 'multipath'
-CAP_NETWORK_CONFIG = 'network-config'
-CAP_NETWORK_STATUS = 'network-status'
-CAP_OEM = 'oem'
-CAP_PAM = 'pam'
-CAP_PROCESS_LIST = 'process-list'
-CAP_PERSISTENT_STATS = 'persistent-stats'
-CAP_SYSTEM_LOGS = 'system-logs'
-CAP_SYSTEM_SERVICES = 'system-services'
-CAP_TAPDISK_LOGS = 'tapdisk-logs'
-CAP_VNCTERM = 'vncterm'
-CAP_WLB = 'wlb'
-CAP_X11_LOGS = 'X11'
-CAP_X11_AUTH = 'X11-auth'
-CAP_XAPI_DEBUG = 'xapi-debug'
-CAP_XAPI_SUBPROCESS = 'xapi-subprocess'
-CAP_XENRT = 'xenrt'
-CAP_XENSERVER_CONFIG = 'xenserver-config'
-CAP_XENSERVER_DOMAINS = 'xenserver-domains'
-CAP_XENSERVER_DATABASES = 'xenserver-databases'
-CAP_XENSERVER_INSTALL = 'xenserver-install'
-CAP_XENSERVER_LOGS = 'xenserver-logs'
-CAP_XEN_INFO = 'xen-info'
-CAP_XHA_LIVESET = 'xha-liveset'
-CAP_YUM = 'yum'
-
-KB = 1024
-MB = 1024 * 1024
-
-caps = {}
-cap_sizes = {}
-unlimited_data = False
-dbg = False
-
-def cap(key, pii=PII_MAYBE, min_size=-1, max_size=-1, min_time=-1,
- max_time=-1, mime=MIME_TEXT, checked=True, hidden=False):
- if os.getenv('XEN_RT') and max_time > 0:
- max_time *= 5
- caps[key] = (key, pii, min_size, max_size, min_time, max_time, mime,
- checked, hidden)
- cap_sizes[key] = 0
-
-
-cap(CAP_BLOBS, PII_NO, max_size=5*MB)
-cap(CAP_BOOT_LOADER, PII_NO, max_size=3*KB,
- max_time=5)
-cap(CAP_CVSM, PII_NO, max_size=3*MB,
- max_time=120)
-cap(CAP_DISK_INFO, PII_MAYBE, max_size=50*KB,
- max_time=20)
-cap(CAP_FIRSTBOOT, PII_YES, min_size=60*KB, max_size=80*KB)
-cap(CAP_HARDWARE_INFO, PII_MAYBE, max_size=50*KB,
- max_time=20)
-cap(CAP_HDPARM_T, PII_NO, min_size=0, max_size=5*KB,
- min_time=20, max_time=90, checked=False, hidden=True)
-cap(CAP_HIGH_AVAILABILITY, PII_MAYBE, max_size=5*MB)
-cap(CAP_HOST_CRASHDUMP_DUMPS,PII_YES, checked = False)
-cap(CAP_HOST_CRASHDUMP_LOGS, PII_NO)
-cap(CAP_KERNEL_INFO, PII_MAYBE, max_size=120*KB,
- max_time=5)
-cap(CAP_LOSETUP_A, PII_MAYBE, max_size=KB, max_time=5)
-cap(CAP_MULTIPATH, PII_MAYBE, max_size=20*KB,
- max_time=10)
-cap(CAP_NETWORK_CONFIG, PII_IF_CUSTOMIZED,
- min_size=0, max_size=40*KB)
-cap(CAP_NETWORK_STATUS, PII_YES, max_size=19*KB,
- max_time=30)
-cap(CAP_PAM, PII_NO, max_size=50*KB)
-cap(CAP_PERSISTENT_STATS, PII_MAYBE, max_size=50*MB,
- max_time=60)
-cap(CAP_PROCESS_LIST, PII_YES, max_size=30*KB,
- max_time=20)
-cap(CAP_SYSTEM_LOGS, PII_MAYBE, max_size=50*MB,
- max_time=5)
-cap(CAP_SYSTEM_SERVICES, PII_NO, max_size=5*KB,
- max_time=20)
-cap(CAP_TAPDISK_LOGS, PII_NO, max_size=64*KB)
-cap(CAP_VNCTERM, PII_MAYBE, checked = False)
-cap(CAP_WLB, PII_NO, max_size=3*MB,
- max_time=20)
-cap(CAP_X11_LOGS, PII_NO, max_size=100*KB)
-cap(CAP_X11_AUTH, PII_NO, max_size=100*KB)
-cap(CAP_XAPI_DEBUG, PII_MAYBE, max_size=10*MB)
-cap(CAP_XAPI_SUBPROCESS, PII_NO, max_size=5*KB,
- max_time=10)
-cap(CAP_XENRT, PII_NO, min_size=0, max_size=500*MB,
- checked=False, hidden=True)
-cap(CAP_XENSERVER_CONFIG, PII_MAYBE, max_size=80*KB,
- max_time=5)
-cap(CAP_XENSERVER_DOMAINS, PII_NO, max_size=1*KB,
- max_time=5)
-cap(CAP_XENSERVER_DATABASES, PII_YES, min_size=500*KB,max_size=2*MB,
- max_time=40)
-cap(CAP_XENSERVER_INSTALL, PII_MAYBE, min_size=10*KB, max_size=300*KB)
-cap(CAP_XENSERVER_LOGS, PII_MAYBE, min_size=0, max_size=70*MB)
-cap(CAP_XEN_INFO, PII_MAYBE, max_size=20*KB,
- max_time=10)
-cap(CAP_XHA_LIVESET, PII_MAYBE, max_size=10*KB,
- max_time=10)
-cap(CAP_YUM, PII_IF_CUSTOMIZED, max_size=10*KB,
- max_time=30)
-
-ANSWER_YES_TO_ALL = False
-SILENT_MODE = False
-entries = None
-data = {}
-dev_null = open('/dev/null', 'r+')
-
-def output(x):
- global SILENT_MODE
- if not SILENT_MODE:
- print x
-
-def output_ts(x):
- output("[%s] %s" % (time.strftime("%x %X %Z"), x))
-
-def cmd_output(cap, args, label = None, filter = None):
- if cap in entries:
- if not label:
- if isinstance(args, list):
- a = [aa for aa in args]
- a[0] = os.path.basename(a[0])
- label = ' '.join(a)
- else:
- label = args
- data[label] = {'cap': cap, 'cmd_args': args, 'filter': filter}
-
-def file_output(cap, path_list):
- if cap in entries:
- for p in path_list:
- if os.path.exists(p):
- if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
- cap_sizes[cap] < caps[cap][MAX_SIZE]:
- data[p] = {'cap': cap, 'filename': p}
- try:
- s = os.stat(p)
- cap_sizes[cap] += s.st_size
- except:
- pass
- else:
- output("Omitting %s, size constraint of %s exceeded" % (p, cap))
-
-def tree_output(cap, path, pattern = None, negate = False):
- if cap in entries:
- if os.path.exists(path):
- for f in os.listdir(path):
- fn = os.path.join(path, f)
- if os.path.isfile(fn) and matches(fn, pattern, negate):
- file_output(cap, [fn])
- elif os.path.isdir(fn):
- tree_output(cap, fn, pattern, negate)
-
-def func_output(cap, label, func):
- if cap in entries:
- t = str(func).split()
- data[label] = {'cap': cap, 'func': func}
-
-def collect_data():
- process_lists = {}
-
- for (k, v) in data.items():
- cap = v['cap']
- if v.has_key('cmd_args'):
- v['output'] = StringIOmtime()
- if not process_lists.has_key(cap):
- process_lists[cap] = []
- process_lists[cap].append(ProcOutput(v['cmd_args'], caps[cap][MAX_TIME], v['output'], v['filter']))
- elif v.has_key('filename') and v['filename'].startswith('/proc/'):
- # proc files must be read into memory
- try:
- f = open(v['filename'], 'r')
- s = f.read()
- f.close()
- if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
- cap_sizes[cap] < caps[cap][MAX_SIZE]:
- v['output'] = StringIOmtime(s)
- cap_sizes[cap] += len(s)
- else:
- output("Omitting %s, size constraint of %s exceeded" % (v['filename'], cap))
- except:
- pass
- elif v.has_key('func'):
- try:
- s = v['func'](cap)
- except Exception, e:
- s = str(e)
- if unlimited_data or caps[cap][MAX_SIZE] == -1 or \
- cap_sizes[cap] < caps[cap][MAX_SIZE]:
- v['output'] = StringIOmtime(s)
- cap_sizes[cap] += len(s)
- else:
- output("Omitting %s, size constraint of %s exceeded" % (k, cap))
-
- run_procs(process_lists.values())
-
-
-def main(argv = None):
- global ANSWER_YES_TO_ALL, SILENT_MODE
- global entries, data, dbg
-
- # we need access to privileged files, exit if we are not running as root
- if os.getuid() != 0:
- print >>sys.stderr, "Error: xen-bugtool must be run as root"
- return 1
-
- output_type = 'tar.bz2'
- output_fd = -1
-
- if argv is None:
- argv = sys.argv
-
- try:
- (options, params) = getopt.gnu_getopt(
- argv, 'sy', ['capabilities', 'silent', 'yestoall', 'entries=',
- 'output=', 'outfd=', 'all', 'unlimited', 'debug'])
- except getopt.GetoptError, opterr:
- print >>sys.stderr, opterr
- return 2
-
- try:
- load_plugins(True)
- except:
- pass
-
- inventory = readKeyValueFile(XENSOURCE_INVENTORY)
- if inventory.has_key('OEM_BUILD_NUMBER'):
- cap(CAP_OEM, PII_MAYBE, max_size=5*MB,
- max_time=90)
-
- if os.getenv('XEN_RT'):
- entries = [CAP_BLOBS, CAP_BOOT_LOADER, CAP_CVSM, CAP_DISK_INFO, CAP_FIRSTBOOT, CAP_HARDWARE_INFO,
- CAP_HOST_CRASHDUMP_DUMPS, CAP_HOST_CRASHDUMP_LOGS, CAP_KERNEL_INFO, CAP_LOSETUP_A,
- CAP_NETWORK_CONFIG, CAP_NETWORK_STATUS, CAP_PROCESS_LIST, CAP_HIGH_AVAILABILITY,
- CAP_PAM, CAP_PERSISTENT_STATS, CAP_MULTIPATH,
- CAP_SYSTEM_LOGS, CAP_SYSTEM_SERVICES, CAP_TAPDISK_LOGS,
- CAP_VNCTERM, CAP_WLB, CAP_X11_LOGS, CAP_X11_AUTH, CAP_XAPI_DEBUG, CAP_XAPI_SUBPROCESS,
- CAP_XENRT, CAP_XENSERVER_CONFIG, CAP_XENSERVER_DOMAINS, CAP_XENSERVER_DATABASES,
- CAP_XENSERVER_INSTALL, CAP_XENSERVER_LOGS, CAP_XEN_INFO, CAP_XHA_LIVESET, CAP_YUM]
- else:
- entries = [e for e in caps.keys() if caps[e][CHECKED]]
-
- for (k, v) in options:
- if k == '--capabilities':
- update_capabilities()
- print_capabilities()
- return 0
-
- if k == '--output':
- if v in ['tar', 'tar.bz2', 'zip']:
- output_type = v
- else:
- print >>sys.stderr, "Invalid output format '%s'" % v
- return 2
-
- # "-s" or "--silent" means suppress output (except for the final
- # output filename at the end)
- if k in ['-s', '--silent']:
- SILENT_MODE = True
-
- if k == '--entries' and v != '':
- entries = v.split(',')
-
- # If the user runs the script with "-y" or "--yestoall" we don't ask
- # all the really annoying questions.
- if k in ['-y', '--yestoall']:
- ANSWER_YES_TO_ALL = True
-
- if k == '--outfd':
- output_fd = int(v)
- try:
- old = fcntl.fcntl(output_fd, fcntl.F_GETFD)
- fcntl.fcntl(output_fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
- except:
- print >>sys.stderr, "Invalid output file descriptor", output_fd
- return 2
-
- elif k == '--all':
- entries = caps.keys()
- elif k == '--unlimited':
- unlimited_data = True
- elif k == '--debug':
- dbg = True
- ProcOutput.debug = True
-
- if len(params) != 1:
- print >>sys.stderr, "Invalid additional arguments", str(params)
- return 2
-
- if output_fd != -1 and output_type != 'tar':
- print >>sys.stderr, "Option '--outfd' only valid with '--output=tar'"
- return 2
-
- if ANSWER_YES_TO_ALL:
- output("Warning: '--yestoall' argument provided, will not prompt for individual files.")
-
- output('''
-This application will collate the Xen dmesg output, details of the
-hardware configuration of your machine, information about the build of
-Xen that you are using, plus, if you allow it, various logs.
-
-The collated information will be saved as a .%s for archiving or
-sending to a Technical Support Representative.
-
-The logs may contain private information, and if you are at all
-worried about that, you should exit now, or you should explicitly
-exclude those logs from the archive.
-
-''' % output_type)
-
- # assemble potential data
- tree_output(CAP_BLOBS, XAPI_BLOBS)
-
- file_output(CAP_BOOT_LOADER, [GRUB_CONFIG, EXTLINUX_CONFIG])
- cmd_output(CAP_BOOT_LOADER, [LS, '-lR', '/boot'])
- cmd_output(CAP_BOOT_LOADER, [MD5SUM, BOOT_KERNEL, BOOT_INITRD], label='vmlinuz-initrd.md5sum')
-
- func_output(CAP_CVSM, 'csl_logs', csl_logs)
-
- cmd_output(CAP_DISK_INFO, [FDISK, '-l'])
- file_output(CAP_DISK_INFO, [PROC_PARTITIONS, PROC_MOUNTS])
- file_output(CAP_DISK_INFO, [FSTAB, ISCSI_CONF, ISCSI_INITIATOR])
- cmd_output(CAP_DISK_INFO, [DF, '-alT'])
- cmd_output(CAP_DISK_INFO, [DF, '-alTi'])
- for d in disk_list():
- cmd_output(CAP_DISK_INFO, [HDPARM, '-I', '/dev/%s' % d])
- if len(pidof('iscsid')) != 0:
- cmd_output(CAP_DISK_INFO, [ISCSIADM, '-m', 'node'])
- cmd_output(CAP_DISK_INFO, [VGSCAN])
- cmd_output(CAP_DISK_INFO, [PVS])
- cmd_output(CAP_DISK_INFO, [VGS])
- cmd_output(CAP_DISK_INFO, [LVS])
- file_output(CAP_DISK_INFO, [LVM_CACHE, LVM_CONFIG])
- cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_host'])
- cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_disk'])
- cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/fc_transport'])
- cmd_output(CAP_DISK_INFO, [SG_MAP, '-x'])
- func_output(CAP_DISK_INFO, 'scsi-hosts', dump_scsi_hosts)
- tree_output(CAP_DISK_INFO, PROC_DRIVER_CCISS_DIR)
- cmd_output(CAP_DISK_INFO, [LVDISPLAY, '--map'])
-
- tree_output(CAP_FIRSTBOOT, FIRSTBOOT_DIR)
-
- file_output(CAP_HARDWARE_INFO, [PROC_CPUINFO, PROC_MEMINFO, PROC_IOPORTS, PROC_INTERRUPTS])
- cmd_output(CAP_HARDWARE_INFO, [DMIDECODE])
- cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-n'])
- cmd_output(CAP_HARDWARE_INFO, [LSPCI, '-vv'])
- file_output(CAP_HARDWARE_INFO, [PROC_USB_DEV, PROC_SCSI])
- file_output(CAP_HARDWARE_INFO, [BOOT_TIME_CPUS, BOOT_TIME_MEMORY])
- file_output(CAP_HARDWARE_INFO, [SYSCONFIG_HWCONF])
- cmd_output(CAP_HARDWARE_INFO, [LS, '-lR', '/dev'])
- # FIXME IDE?
-
- for d in disk_list():
- cmd_output(CAP_HDPARM_T, [HDPARM, '-tT', '/dev/%s' % d])
-
- file_output(CAP_HIGH_AVAILABILITY, [XHAD_CONF, XHA_LOG])
-
- tree_output(CAP_HOST_CRASHDUMP_DUMPS, HOST_CRASHDUMPS_DIR,
- HOST_CRASHDUMP_LOGS_RE, True)
- tree_output(CAP_HOST_CRASHDUMP_LOGS, HOST_CRASHDUMPS_DIR,
- HOST_CRASHDUMP_LOGS_RE, False)
-
- file_output(CAP_KERNEL_INFO, [PROC_VERSION, PROC_MODULES, PROC_DEVICES,
- PROC_FILESYSTEMS, PROC_CMDLINE])
- cmd_output(CAP_KERNEL_INFO, [ZCAT, PROC_CONFIG], label='config')
- cmd_output(CAP_KERNEL_INFO, [SYSCTL, '-A'])
- file_output(CAP_KERNEL_INFO, [MODPROBE_CONF])
- tree_output(CAP_KERNEL_INFO, MODPROBE_DIR)
- func_output(CAP_KERNEL_INFO, 'modinfo', module_info)
-
- cmd_output(CAP_LOSETUP_A, [LOSETUP, '-a'])
-
- file_output(CAP_MULTIPATH, [MULTIPATH_CONF, MPP_CONF])
- cmd_output(CAP_MULTIPATH, [DMSETUP, 'table'])
- func_output(CAP_MULTIPATH, 'multipathd_topology', multipathd_topology)
- cmd_output(CAP_MULTIPATH, [MPPUTIL, '-a'])
- if CAP_MULTIPATH in entries:
- dump_rdac_groups(CAP_MULTIPATH)
-
- file_output(CAP_NETWORK_CONFIG, [NETWORK_CONF])
- file_output(CAP_NETWORK_CONFIG, [NETWORK_DBCACHE])
- tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, IFCFG_RE)
- tree_output(CAP_NETWORK_CONFIG, SYSCONFIG_NETWORK_SCRIPTS, ROUTE_RE)
- file_output(CAP_NETWORK_CONFIG, [SYSCONFIG_NETWORK, RESOLV_CONF, NSSWITCH_CONF, HOSTS])
- file_output(CAP_NETWORK_CONFIG, [NTP_CONF, IPTABLES_CONFIG, HOSTS_ALLOW, HOSTS_DENY])
- file_output(CAP_NETWORK_CONFIG, [OPENVSWITCH_CONF, OPENVSWITCH_CONF_DB])
-
- cmd_output(CAP_NETWORK_STATUS, [IFCONFIG, '-a'])
- cmd_output(CAP_NETWORK_STATUS, [ROUTE, '-n'])
- cmd_output(CAP_NETWORK_STATUS, [ARP, '-n'])
- cmd_output(CAP_NETWORK_STATUS, [NETSTAT, '-an'])
- tree_output(CAP_NETWORK_STATUS, DHCP_LEASE_DIR)
- cmd_output(CAP_NETWORK_STATUS, [IPTABLES, '-nL'])
- cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'show'])
- cmd_output(CAP_NETWORK_STATUS, [BIOSDEVNAME, '-d'])
- for p in os.listdir('/sys/class/net/'):
- if os.path.isdir('/sys/class/net/%s/bridge' % p):
- cmd_output(CAP_NETWORK_STATUS, [BRCTL, 'showmacs', p])
- else:
- try:
- f = open('/sys/class/net/%s/type' % p, 'r')
- t = f.readline()
- f.close()
- if int(t) == 1:
- # ARPHRD_ETHER
- cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, p])
- cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-S', p])
- cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-k', p])
- cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-i', p])
- cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-c', p])
- cmd_output(CAP_NETWORK_STATUS,
- [TC, '-s', '-d', 'class', 'show', 'dev', p])
- except:
- pass
- tree_output(CAP_NETWORK_STATUS, PROC_NET_BONDING_DIR)
- tree_output(CAP_NETWORK_STATUS, PROC_NET_VLAN_DIR)
- cmd_output(CAP_NETWORK_STATUS, [TC, '-s', 'qdisc'])
- file_output(CAP_NETWORK_STATUS, [PROC_NET_SOFTNET_STAT])
- tree_output(CAP_NETWORK_STATUS, OPENVSWITCH_CORE_DIR)
- if os.path.exists(OPENVSWITCH_VSWITCHD_PID):
- cmd_output(CAP_NETWORK_STATUS, [OVS_DPCTL, 'show'])
- for d in dp_list():
- cmd_output(CAP_NETWORK_STATUS, [OVS_OFCTL, 'show', d])
- cmd_output(CAP_NETWORK_STATUS, [OVS_OFCTL, 'status', d])
- cmd_output(CAP_NETWORK_STATUS, [OVS_OFCTL, 'dump-flows', d])
- cmd_output(CAP_NETWORK_STATUS, [OVS_DPCTL, 'dump-flows', d])
- try:
- vspidfile = open(OPENVSWITCH_VSWITCHD_PID)
- vspid = int(vspidfile.readline().strip())
- vspidfile.close()
- for b in bond_list(vspid):
- cmd_output(CAP_NETWORK_STATUS,
- [OVS_APPCTL, '-t', '/var/run/ovs-vswitchd.%s.ctl' % vspid, '-e' 'bond/show %s' % b],
- 'ovs-appctl-bond-show-%s.out' % b)
- except e:
- pass
-
- tree_output(CAP_PAM, PAM_DIR)
- file_output(CAP_PAM, [KRB5_CONF])
- tree_output(CAP_PAM, LIKEWISE_DIR)
-
- func_output(CAP_PERSISTENT_STATS, 'xapi_rrd-host', dump_xapi_rrds)
-
- cmd_output(CAP_PROCESS_LIST, [PS, 'wwwaxf', '-eo', 'pid,tty,stat,time,nice,psr,pcpu,pmem,nwchan,wchan:25,args'], label='process-tree')
- func_output(CAP_PROCESS_LIST, 'fd_usage', fd_usage)
-
- file_output(CAP_SYSTEM_LOGS,
- [ VAR_LOG_DIR + x for x in
- [ 'crit.log', 'kern.log', 'daemon.log', 'user.log', 'syslog', 'messages',
- 'monitor_memory.log', 'secure', 'debug', 'dmesg', 'boot.msg', 'blktap.log' ] +
- [ f % n for n in range(1, 20) \
- for f in ['crit.log.%d', 'crit.log.%d.gz',
- 'kern.log.%d', 'kern.log.%d.gz',
- 'daemon.log.%d', 'daemon.log.%d.gz',
- 'user.log.%d', 'user.log.%d.gz',
- 'messages.%d', 'messages.%d.gz',
- 'monitor_memory.log.%d', 'monitor_memory.log.%d.gz',
- 'secure.%d', 'secure.%d.gz',
- 'blktap.log.%d']]])
- if not os.path.exists('/var/log/dmesg') and not os.path.exists('/var/log/boot.msg'):
- cmd_output(CAP_SYSTEM_LOGS, [DMESG])
- file_output(CAP_SYSTEM_LOGS, [LWIDENTITY_JOIN_LOG, HOSTS_LWIDENTITY_ORIG])
-
- cmd_output(CAP_SYSTEM_SERVICES, [CHKCONFIG, '--list'])
-
- if CAP_TAPDISK_LOGS in entries:
- generate_tapdisk_logs()
-
- tree_output(CAP_VNCTERM, VNCTERM_CORE_DIR)
-
- cmd_output(CAP_WLB, [XE, 'pool-retrieve-wlb-configuration'])
- cmd_output(CAP_WLB, [XE, 'pool-retrieve-wlb-diagnostics'])
-
- tree_output(CAP_X11_LOGS, X11_LOGS_DIR, X11_LOGS_RE)
- tree_output(CAP_X11_AUTH, X11_AUTH_DIR, X11_AUTH_RE)
-
- tree_output(CAP_XAPI_DEBUG, XAPI_DEBUG_DIR)
-
- func_output(CAP_XAPI_SUBPROCESS, 'xapi_subprocesses', dump_xapi_subprocess_info)
-
- tree_output(CAP_XENRT, '/tmp', FIST_RE)
- # CA-45540: capture QEMU core files
- tree_output(CAP_XENRT, '/var/xen/qemu')
- tree_output(CAP_XENRT, '/tmp', re.compile(r'^.*xen\.qemu-dm\.'))
-
- file_output(CAP_XENSERVER_CONFIG, [INITIAL_INVENTORY])
- file_output(CAP_XENSERVER_CONFIG, [POOL_CONF, PTOKEN, XAPI_CONF, XAPI_SSL_CONF,
- XENSOURCE_INVENTORY, VENDORKERNEL_INVENTORY])
- cmd_output(CAP_XENSERVER_CONFIG, [LS, '-lR', '/opt/xensource'])
- cmd_output(CAP_XENSERVER_CONFIG, [BIN_STATIC_VDIS, 'list'])
- tree_output(CAP_XENSERVER_CONFIG, OEM_CONFIG_DIR, OEM_CONFIG_FILES_RE)
- tree_output(CAP_XENSERVER_CONFIG, STATIC_VDIS)
- cmd_output(CAP_XENSERVER_CONFIG, [LS, '-lR', STATIC_VDIS])
-
- func_output(CAP_XENSERVER_DATABASES, 'xapi-db.xml', dump_filtered_xapi_db)
- cmd_output(CAP_XENSERVER_DATABASES, [XENSTORE_LS, '-f'])
- file_output(CAP_XENSERVER_DATABASES, [DB_CONF, DB_CONF_RIO, DB_DEFAULT_FIELDS, DB_SCHEMA_SQL])
- tree_output(CAP_XENSERVER_DATABASES, OEM_CONFIG_DIR, OEM_DB_FILES_RE)
- file_output(CAP_XENSERVER_DATABASES, [XENSTORED_DB, XENSTORED_DB + '.bak'])
- cmd_output(CAP_XENSERVER_DATABASES, [XE, 'pool-dump-database', 'file-name='],
- label="xapi-db-dumped.xml", filter=filter_db_pii)
- cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'watches'])
- cmd_output(CAP_XENSERVER_DATABASES, [XS, 'debug', 'quotas'])
-
- cmd_output(CAP_XENSERVER_DOMAINS, [LIST_DOMAINS])
-
- tree_output(CAP_XENSERVER_INSTALL, VAR_LOG_DIR + 'installer')
- file_output(CAP_XENSERVER_INSTALL,
- [ VAR_LOG_DIR + x for x in
- [ 'firstboot-SR-commands-log',
- 'upgrade-commands-log', 'generate-iscsi-iqn-log']] +
- [ '/root/' + x for x in
- [ 'blockdevs-log', 'cmdline-log', 'devcontents-log',
- 'dmesg-log', 'install-log', 'lspci-log', 'modules-log',
- 'pci-log', 'processes-log', 'tty-log', 'uname-log',
- 'vgscan-log']])
- tree_output(CAP_XENSERVER_INSTALL, INSTALLED_REPOS_DIR)
- tree_output(CAP_XENSERVER_INSTALL, PATCH_APPLIED_DIR)
-
- file_output(CAP_XENSERVER_LOGS, [LOG_CONF, XENGUEST_LOG])
- file_output(CAP_XENSERVER_LOGS, XENSERVER_LOGS)
- file_output(CAP_XENSERVER_LOGS, LICENSE_LOGS)
- tree_output(CAP_XENSERVER_LOGS, OEM_CONFIG_DIR, OEM_XENSERVER_LOGS_RE)
-
- try:
- def xen_dmesg(xc):
- data = xc.readconsolering()
- xc.send_debug_keys('q')
- time.sleep(1)
- return data
-
- xc = xen.lowlevel.xc.xc()
-
- func_output(CAP_XEN_INFO, 'xen-dmesg', lambda x: xen_dmesg(xc))
- func_output(CAP_XEN_INFO, 'physinfo', lambda x: prettyDict(xc.physinfo()))
- func_output(CAP_XEN_INFO, 'xeninfo', lambda x: prettyDict(xc.xeninfo()))
- except:
- pass
- file_output(CAP_XEN_INFO, [PROC_XEN_BALLOON])
-
- cmd_output(CAP_XHA_LIVESET, [HA_QUERY_LIVESET])
-
- file_output(CAP_YUM, [YUM_LOG])
- tree_output(CAP_YUM, YUM_REPOS_DIR)
- cmd_output(CAP_YUM, [RPM, '-qa'])
-
- try:
- load_plugins()
- except:
- pass
-
- # permit the user to filter out data
- for k in sorted(data.keys()):
- if not ANSWER_YES_TO_ALL and not yes("Include '%s'? [Y/n]: " % k):
- del data[k]
-
- # collect selected data now
- output_ts('Running commands to collect data')
- collect_data()
-
- subdir = os.getenv('XENRT_BUGTOOL_BASENAME')
- if subdir:
- subdir = os.path.basename(subdir)
- if subdir == '..' or subdir == '.':
- subdir = None
- if not subdir:
- subdir = "bug-report-%s" % time.strftime("%Y%m%d%H%M%S")
-
- # include inventory
- data['inventory.xml'] = {'cap': None, 'output': StringIOmtime(make_inventory(data, subdir))}
-
- # create archive
- if output_fd == -1 and not os.path.exists(BUG_DIR):
- try:
- os.makedirs(BUG_DIR)
- except:
- pass
-
- if output_fd == -1:
- output_ts('Creating output file')
-
- if output_type.startswith('tar'):
- make_tar(subdir, output_type, output_fd)
- else:
- make_zip(subdir)
-
- clean_tapdisk_logs()
-
- if dbg:
- print >>sys.stderr, "Category sizes (max, actual):\n"
- for c in caps.keys():
- print >>sys.stderr, " %s (%d, %d)" % (c, caps[c][MAX_SIZE],
- cap_sizes[c])
- return 0
-
-def find_tapdisk_logs():
- return glob.glob('/var/log/blktap/*.log*')
-
-def generate_tapdisk_logs():
- for pid in pidof('tapdisk'):
- try:
- os.kill(pid, SIGUSR1)
- output_ts("Including logs for tapdisk process %d" % pid)
- except :
- pass
- # give processes a second to write their logs
- time.sleep(1)
- file_output(CAP_TAPDISK_LOGS, find_tapdisk_logs())
-
-def clean_tapdisk_logs():
- for filename in find_tapdisk_logs():
- try:
- os.remove(filename)
- except :
- pass
-
-def dump_xapi_subprocess_info(cap):
- """Check which fds are open by xapi and its subprocesses to diagnose faults like CA-10543.
- Returns a string containing a pretty-printed pstree-like structure. """
- pids = filter(lambda x: x.isdigit(), os.listdir("/proc"))
- def readlines(filename):
- lines = ''
- try:
- f = open(filename, "r")
- lines = f.readlines()
- f.close()
- except:
- pass
- return lines
- def cmdline(pid):
- all = readlines("/proc/" + pid + "/cmdline")
- if all == []:
- return ""
- else:
- return all[0].replace('\x00', ' ')
- def parent(pid):
- for i in readlines("/proc/" + pid + "/status"):
- if i.startswith("PPid:"):
- return i.split()[-1]
- return None
- def pstree(pid):
- result = { "cmdline": cmdline(pid) }
- child_pids = filter(lambda x:parent(x) == pid, pids)
- children = { }
- for child in child_pids:
- children[child] = pstree(child)
- result['children'] = children
- fds = { }
- for fd in os.listdir("/proc/" + pid + "/fd"):
- try:
- fds[fd] = os.readlink("/proc/" + pid + "/fd/" + fd)
- except:
- pass
- result['fds'] = fds
- return result
- xapis = filter(lambda x: cmdline(x).startswith("/opt/xensource/bin/xapi"), pids)
- xapis = filter(lambda x: parent(x) == "1", xapis)
- result = {}
- for xapi in xapis:
- result[xapi] = pstree(xapi)
- pp = pprint.PrettyPrinter(indent=4)
- return pp.pformat(result)
-
-def dump_xapi_rrds(cap):
- socket.setdefaulttimeout(5)
- session = XenAPI.xapi_local()
- session.xenapi.login_with_password('', '')
- this_host = session.xenapi.session.get_this_host(session._session)
- # better way to find pool master?
- pool = session.xenapi.pool.get_all_records().values()[0]
- i_am_master = (this_host == pool['master'])
-
- for vm in session.xenapi.VM.get_all_records().values():
- if vm['is_a_template']:
- continue
- if vm['resident_on'] == this_host or (i_am_master and vm['power_state'] in ['Suspended', 'Halted']):
- rrd = urllib.urlopen('http://localhost/vm_rrd?session_id=%s&uuid=%s' % (session._session, vm['uuid']))
- try:
- (i, o, x) = select([rrd], [], [], 5.0)
- if len(i) == 1:
- data['xapi_rrd-%s' % vm['uuid']] = {'cap': cap,
- 'output': StringIOmtime(rrd.read())}
- finally:
- rrd.close()
-
- output = ''
- rrd = urllib.urlopen('http://localhost/host_rrd?session_id=%s' % session._session)
- try:
- for line in rrd:
- output += line
- finally:
- rrd.close()
-
- session.xenapi.session.logout()
- return output
-
-'''Filter a Xapi XML database.
-
- There is one important assumption made in this class:
- - the XML document does not contain any characters between the end of one
- tag and the beginning of the next, ie every > is immediately followed by
- a <
-'''
-class DBFilter:
- def __init__(self):
- self.result = ''
- self.rest = ''
- self.state = {}
-
- def filter_secrets(self, s):
- if 'in_secret_table' not in self.state:
- self.state['in_secret_table'] = False
-
- # this logic doesn't deal with <table name="secret" /> properly!!!
- if s.startswith('<table ') and 'name="secret"' in s:
- self.state['in_secret_table'] = True
- elif s.startswith('</table>'):
- self.state['in_secret_table'] = False
-
- if self.state['in_secret_table'] and s.startswith("<row"): # match only on DB rows
- s = re.sub(r'(value=")[^"]+(")', r'\1REMOVED\2', s)
- return s
-
- def feed(self, s):
- rem = self.rest + s
- p = rem.find('>')
- while p != -1:
- s = rem[:p+1]
- rem = rem[p+1:]
- self.result += self.filter_secrets(s)
- p = rem.find('>')
- self.rest = rem
-
- def output(self):
- r = self.result + self.filter_secrets(self.rest)
- self.result, self.rest = '', ''
- self.state = {}
- return r
-
-def filter_db_pii(s, state):
- dbfilter = DBFilter()
- dbfilter.feed(s)
- return dbfilter.output()
-
-def dump_filtered_xapi_db(cap):
- db_file = None
- format = None
- state = {}
-
- # determine db format
- c = open(DB_CONF, 'r')
- try:
- for line in c:
- l = line.rstrip('\n')
- if l.startswith('['):
- db_file = l[1:-1]
- if l.startswith('format:'):
- format = l[7:]
- break
- finally:
- c.close()
-
- pipe = None
- ih = None
- output = ''
-
- if format == 'sqlite':
- pipe = Popen([XAPI_DB_PROCESS, '-xmltostdout'], bufsize=1, stdin=dev_null,
- stdout=PIPE, stderr=dev_null)
- ih = pipe.stdout
- elif db_file:
- ih = open(db_file, 'r')
-
- if not ih:
- return ''
-
- dbfilter = DBFilter()
- rec = ih.read(2048)
- while rec != '':
- dbfilter.feed(rec)
- rec = ih.read(2048)
- output = dbfilter.output()
-
- if pipe:
- pipe.wait()
- else:
- ih.close()
- return output
-
-def dump_scsi_hosts(cap):
- output = ''
- l = os.listdir('/sys/class/scsi_host')
- l.sort()
-
- for h in l:
- procname = ''
- try:
- f = open('/sys/class/scsi_host/%s/proc_name' % h)
- procname = f.readline().strip("\n")
- f.close()
- except:
- pass
- modelname = None
- try:
- f = open('/sys/class/scsi_host/%s/model_name' % h)
- modelname = f.readline().strip("\n")
- f.close()
- except:
- pass
-
- output += "%s:\n" %h
- output += " %s%s\n" % (procname, modelname and (" -> %s" % modelname) or '')
-
- return output
-
-def module_info(cap):
- output = StringIO.StringIO()
- modules = open(PROC_MODULES, 'r')
- procs = []
-
- for line in modules:
- module = line.split()[0]
- procs.append(ProcOutput([MODINFO, module], caps[cap][MAX_TIME], output))
- modules.close()
-
- run_procs([procs])
-
- return output.getvalue()
-
-def csl_logs(cap):
- socket.setdefaulttimeout(5)
- session = XenAPI.xapi_local()
- session.xenapi.login_with_password('', '')
- this_host = session.xenapi.session.get_this_host(session._session)
- # better way to find pool master?
- pool = session.xenapi.pool.get_all_records().values()[0]
- i_am_master = (this_host == pool['master'])
-
- output = StringIO.StringIO()
- procs = []
- csl_targets_fetched = []
-
- for pbd in session.xenapi.PBD.get_all_records().values():
- if pbd.has_key('device_config') and pbd['device_config'].has_key('target'):
- if pbd['device_config']['target'] in csl_targets_fetched:
- continue
- sr = session.xenapi.SR.get_record(pbd['SR'])
- if sr.has_key('type') and sr['type'] == 'cslg':
- if sr['shared'] and pbd['host'] != this_host and not i_am_master:
- continue
-
- dev_cfg = pbd['device_config']
- server = "server=%s" % socket.gethostbyname(dev_cfg['target'])
- if dev_cfg.has_key('port'):
- server += ':' + dev_cfg['port']
- if dev_cfg.has_key('username'):
- server += ',' + dev_cfg['username']
- if dev_cfg.has_key('password_secret'):
- sec_ref = session.xenapi.secret.get_by_uuid(dev_cfg['password_secret'])
- server += ',' + session.xenapi.secret.get_value(sec_ref)
- procs.append(ProcOutput([CSL, server, 'srv-log-get'], caps[cap][MAX_TIME], output))
- csl_targets_fetched.append(dev_cfg['target'])
-
- session.xenapi.session.logout()
-
- run_procs([procs])
-
- return output.getvalue()
-
-def multipathd_topology(cap):
- pipe = Popen([MULTIPATHD, '-k'], bufsize=1, stdin=PIPE,
- stdout=PIPE, stderr=dev_null)
- stdout, stderr = pipe.communicate('show topology')
-
- return stdout
-
-def dp_list():
- output = StringIO.StringIO()
- procs = [ProcOutput([OVS_DPCTL, 'dump-dps'], caps[CAP_NETWORK_STATUS][MAX_TIME], output)]
-
- run_procs([procs])
-
- if not procs[0].timed_out:
- return output.getvalue().splitlines()
- return []
-
-def bond_list(pid):
- output = StringIO.StringIO()
- procs = [ProcOutput([OVS_APPCTL, '-t', '/var/run/ovs-vswitchd.%s.ctl' % pid, '-e' 'bond/list'], caps[CAP_NETWORK_STATUS][MAX_TIME], output)]
-
- run_procs([procs])
-
- if not procs[0].timed_out:
- bonds = output.getvalue().splitlines()[1:]
- return [x.split('\t')[1] for x in bonds]
- return []
-
-def fd_usage(cap):
- output = ''
- fd_dict = {}
- for d in [p for p in os.listdir('/proc') if p.isdigit()]:
- try:
- fh = open('/proc/'+d+'/cmdline')
- name = fh.readline()
- num_fds = len(os.listdir(os.path.join('/proc/'+d+'/fd')))
- if num_fds > 0:
- if not num_fds in fd_dict:
- fd_dict[num_fds] = []
- fd_dict[num_fds].append(name.replace('\0', ' ').strip())
- finally:
- fh.close()
- keys = fd_dict.keys()
- keys.sort(lambda a, b: int(b) - int(a))
- for k in keys:
- output += "%s: %s\n" % (k, str(fd_dict[k]))
- return output
-
-def dump_rdac_groups(cap):
- output = StringIO.StringIO()
- procs = [ProcOutput([MPPUTIL, '-a'], caps[cap][MAX_TIME], output)]
-
- run_procs([procs])
-
- if not procs[0].timed_out:
- proc_line = 0
- for line in output.getvalue().splitlines():
- if line.startswith('ID'):
- proc_line = 2
- elif line.startswith('----'):
- proc_line -= 1
- elif proc_line > 0:
- group, _ = line.split(None, 1)
- cmd_output(cap, [MPPUTIL, '-g', group])
-
-def load_plugins(just_capabilities = False):
- def getText(nodelist):
- rc = ""
- for node in nodelist:
- if node.nodeType == node.TEXT_NODE:
- rc += node.data
- return rc.encode()
-
- def getBoolAttr(el, attr, default = False):
- ret = default
- val = el.getAttribute(attr).lower()
- if val in ['true', 'false', 'yes', 'no']:
- ret = val in ['true', 'yes']
- return ret
-
- for dir in [d for d in os.listdir(PLUGIN_DIR) if os.path.isdir(os.path.join(PLUGIN_DIR, d))]:
- if not caps.has_key(dir):
- if not os.path.exists("%s/%s.xml" % (PLUGIN_DIR, dir)):
- continue
- xmldoc = parse("%s/%s.xml" % (PLUGIN_DIR, dir))
- assert xmldoc.documentElement.tagName == "capability"
-
- pii, min_size, max_size, min_time, max_time, mime = \
- PII_MAYBE, -1,-1,-1,-1, MIME_TEXT
-
- if xmldoc.documentElement.getAttribute("pii") in [PII_NO, PII_YES, PII_MAYBE, PII_IF_CUSTOMIZED]:
- pii = xmldoc.documentElement.getAttribute("pii")
- if xmldoc.documentElement.getAttribute("min_size") != '':
- min_size = long(xmldoc.documentElement.getAttribute("min_size"))
- if xmldoc.documentElement.getAttribute("max_size") != '':
- max_size = long(xmldoc.documentElement.getAttribute("max_size"))
- if xmldoc.documentElement.getAttribute("min_time") != '':
- min_time = int(xmldoc.documentElement.getAttribute("min_time"))
- if xmldoc.documentElement.getAttribute("max_time") != '':
- max_time = int(xmldoc.documentElement.getAttribute("max_time"))
- if xmldoc.documentElement.getAttribute("mime") in [MIME_DATA, MIME_TEXT]:
- mime = xmldoc.documentElement.getAttribute("mime")
- checked = getBoolAttr(xmldoc.documentElement, 'checked', True)
- hidden = getBoolAttr(xmldoc.documentElement, 'hidden', False)
-
- cap(dir, pii, min_size, max_size, min_time, max_time, mime, checked, hidden)
-
- if just_capabilities:
- continue
-
- plugdir = os.path.join(PLUGIN_DIR, dir)
- for file in [f for f in os.listdir(plugdir) if f.endswith('.xml')]:
- xmldoc = parse(os.path.join(plugdir, file))
- assert xmldoc.documentElement.tagName == "collect"
-
- for el in xmldoc.documentElement.getElementsByTagName("*"):
- if el.tagName == "files":
- file_output(dir, getText(el.childNodes).split())
- elif el.tagName == "directory":
- pattern = el.getAttribute("pattern")
- if pattern == '': pattern = None
- negate = getBoolAttr(el, 'negate')
- tree_output(dir, getText(el.childNodes), pattern and re.compile(pattern) or None, negate)
- elif el.tagName == "command":
- label = el.getAttribute("label")
- if label == '': label = None
- cmd_output(dir, getText(el.childNodes), label)
-
-def make_tar(subdir, suffix, output_fd):
- global SILENT_MODE, data
-
- mode = 'w'
- if suffix == 'tar.bz2':
- mode = 'w:bz2'
- filename = "%s/%s.%s" % (BUG_DIR, subdir, suffix)
-
- if output_fd == -1:
- tf = tarfile.open(filename, mode)
- else:
- tf = tarfile.open(None, 'w', os.fdopen(output_fd, 'a'))
-
- try:
- for (k, v) in data.items():
- try:
- tar_filename = os.path.join(subdir, construct_filename(k, v))
- ti = tarfile.TarInfo(tar_filename)
-
- ti.uname = 'root'
- ti.gname = 'root'
-
- if v.has_key('output'):
- ti.mtime = v['output'].mtime
- ti.size = len(v['output'].getvalue())
- v['output'].seek(0)
- tf.addfile(ti, v['output'])
- elif v.has_key('filename'):
- s = os.stat(v['filename'])
- ti.mtime = s.st_mtime
- ti.size = s.st_size
- tf.addfile(ti, file(v['filename']))
- except:
- pass
- finally:
- tf.close()
-
- if output_fd == -1:
- output ('Writing tarball %s successful.' % filename)
- if SILENT_MODE:
- print filename
-
-
-def make_zip(subdir):
- global SILENT_MODE, data
-
- filename = "%s/%s.zip" % (BUG_DIR, subdir)
- zf = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED)
-
- try:
- for (k, v) in data.items():
- try:
- dest = os.path.join(subdir, construct_filename(k, v))
-
- if v.has_key('output'):
- zf.writestr(dest, v['output'].getvalue())
- elif v.has_key('filename'):
- if os.stat(v['filename']).st_size < 50:
- compress_type = zipfile.ZIP_STORED
- else:
- compress_type = zipfile.ZIP_DEFLATED
- zf.write(v['filename'], dest, compress_type)
- except:
- pass
- finally:
- zf.close()
-
- output ('Writing archive %s successful.' % filename)
- if SILENT_MODE:
- print filename
-
-
-def make_inventory(inventory, subdir):
- document = getDOMImplementation().createDocument(
- None, INVENTORY_XML_ROOT, None)
-
- # create summary entry
- s = document.createElement(INVENTORY_XML_SUMMARY)
- user = os.getenv('SUDO_USER', os.getenv('USER'))
- if user:
- s.setAttribute('user', user)
- s.setAttribute('date', time.strftime('%c'))
- s.setAttribute('hostname', platform.node())
- s.setAttribute('uname', ' '.join(platform.uname()))
- s.setAttribute('uptime', commands.getoutput(UPTIME))
- document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(s)
-
- map(lambda (k, v): inventory_entry(document, subdir, k, v),
- inventory.items())
- return document.toprettyxml()
-
-def inventory_entry(document, subdir, k, v):
- try:
- el = document.createElement(INVENTORY_XML_ELEMENT)
- el.setAttribute('capability', v['cap'])
- el.setAttribute('filename', os.path.join(subdir, construct_filename(k, v)))
- el.setAttribute('md5sum', md5sum(v))
- document.getElementsByTagName(INVENTORY_XML_ROOT)[0].appendChild(el)
- except:
- pass
-
-
-def md5sum(d):
- m = md5.new()
- if d.has_key('filename'):
- f = open(d['filename'])
- data = f.read(1024)
- while len(data) > 0:
- m.update(data)
- data = f.read(1024)
- f.close()
- elif d.has_key('output'):
- m.update(d['output'].getvalue())
- return m.hexdigest()
-
-
-def construct_filename(k, v):
- if v.has_key('filename'):
- if v['filename'][0] == '/':
- return v['filename'][1:]
- else:
- return v['filename']
- s = k.replace(' ', '-')
- s = s.replace('--', '-')
- s = s.replace('/', '%')
- if s.find('.') == -1:
- s += '.out'
-
- return s
-
-
-def update_capabilities():
- update_cap_size(CAP_HOST_CRASHDUMP_LOGS,
- size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE))
- update_cap_size(CAP_HOST_CRASHDUMP_DUMPS,
- size_of_dir(HOST_CRASHDUMPS_DIR, HOST_CRASHDUMP_LOGS_RE,
- True))
- update_cap_size(CAP_XAPI_DEBUG, size_of_dir(XAPI_DEBUG_DIR))
- update_cap_size(CAP_XENSERVER_LOGS, size_of_all(XENSERVER_LOGS))
-
-
-def update_cap_size(cap, size):
- update_cap(cap, MIN_SIZE, size)
- update_cap(cap, MAX_SIZE, size)
- update_cap(cap, CHECKED, size > 0)
-
-
-def update_cap(cap, k, v):
- global caps
- l = list(caps[cap])
- l[k] = v
- caps[cap] = tuple(l)
-
-
-def size_of_dir(d, pattern = None, negate = False):
- if os.path.isdir(d):
- return size_of_all([os.path.join(d, fn) for fn in os.listdir(d)],
- pattern, negate)
- else:
- return 0
-
-
-def size_of_all(files, pattern = None, negate = False):
- return sum([size_of(f, pattern, negate) for f in files])
-
-
-def matches(f, pattern, negate):
- if negate:
- return not matches(f, pattern, False)
- else:
- return pattern is None or pattern.match(f)
-
-
-def size_of(f, pattern, negate):
- if os.path.isfile(f) and matches(f, pattern, negate):
- return os.stat(f)[6]
- else:
- return size_of_dir(f, pattern, negate)
-
-
-def print_capabilities():
- document = getDOMImplementation().createDocument(
- "ns", CAP_XML_ROOT, None)
- map(lambda key: capability(document, key), [k for k in caps.keys() if not caps[k][HIDDEN]])
- print document.toprettyxml()
-
-def capability(document, key):
- c = caps[key]
- el = document.createElement(CAP_XML_ELEMENT)
- el.setAttribute('key', c[KEY])
- el.setAttribute('pii', c[PII])
- el.setAttribute('min-size', str(c[MIN_SIZE]))
- el.setAttribute('max-size', str(c[MAX_SIZE]))
- el.setAttribute('min-time', str(c[MIN_TIME]))
- el.setAttribute('max-time', str(c[MAX_TIME]))
- el.setAttribute('content-type', c[MIME])
- el.setAttribute('default-checked', c[CHECKED] and 'yes' or 'no')
- document.getElementsByTagName(CAP_XML_ROOT)[0].appendChild(el)
-
-
-def prettyDict(d):
- format = '%%-%ds: %%s' % max(map(len, [k for k, _ in d.items()]))
- return '\n'.join([format % i for i in d.items()]) + '\n'
-
-
-def yes(prompt):
- yn = raw_input(prompt)
-
- return len(yn) == 0 or yn.lower()[0] == 'y'
-
-
-partition_re = re.compile(r'(.*[0-9]+$)|(^xvd)')
-
-def disk_list():
- disks = []
- try:
- f = open('/proc/partitions')
- f.readline()
- f.readline()
- for line in f.readlines():
- (major, minor, blocks, name) = line.split()
- if int(major) < 254 and not partition_re.match(name):
- disks.append(name)
- f.close()
- except:
- pass
- return disks
-
-
-class ProcOutput:
- debug = False
-
- def __init__(self, command, max_time, inst=None, filter=None):
- self.command = command
- self.max_time = max_time
- self.inst = inst
- self.running = False
- self.status = None
- self.timed_out = False
- self.failed = False
- self.timeout = int(time.time()) + self.max_time
- self.filter = filter
- self.filter_state = {}
-
- def __del__(self):
- self.terminate()
-
- def cmdAsStr(self):
- return isinstance(self.command, list) and ' '.join(self.command) or self.command
-
- def run(self):
- self.timed_out = False
- try:
- if ProcOutput.debug:
- output_ts("Starting '%s'" % self.cmdAsStr())
- self.proc = Popen(self.command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null, shell=isinstance(self.command, str))
- old = fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_GETFD)
- fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
- self.running = True
- self.failed = False
- except:
- output_ts("'%s' failed" % self.cmdAsStr())
- self.running = False
- self.failed = True
-
- def terminate(self):
- if self.running:
- try:
- os.kill(self.proc.pid, SIGTERM)
- except:
- pass
- self.proc = None
- self.running = False
- self.status = SIGTERM
-
- def read_line(self):
- assert self.running
- line = self.proc.stdout.readline()
- if line == '':
- # process exited
- self.status = self.proc.wait()
- self.proc = None
- self.running = False
- else:
- if self.filter:
- line = self.filter(line, self.filter_state)
- if self.inst:
- self.inst.write(line)
-
-def run_procs(procs):
- while True:
- pipes = []
- active_procs = []
-
- for pp in procs:
- for p in pp:
- if p.running:
- active_procs.append(p)
- pipes.append(p.proc.stdout)
- break
- elif p.status == None and not p.failed and not p.timed_out:
- p.run()
- if p.running:
- active_procs.append(p)
- pipes.append(p.proc.stdout)
- break
-
- if len(pipes) == 0:
- # all finished
- break
-
- (i, o, x) = select(pipes, [], [], 1.0)
- now = int(time.time())
-
- # handle process output
- for p in active_procs:
- if p.proc.stdout in i:
- p.read_line()
-
- # handle timeout
- if p.running and now > p.timeout:
- output_ts("'%s' timed out" % p.cmdAsStr())
- if p.inst:
- p.inst.write("\n** timeout **\n")
- p.timed_out = True
- p.terminate()
-
-
-def pidof(name):
- pids = []
-
- for d in [p for p in os.listdir('/proc') if p.isdigit()]:
- try:
- if os.path.basename(os.readlink('/proc/%s/exe' % d)) == name:
- pids.append(int(d))
- except:
- pass
-
- return pids
-
-
-def readKeyValueFile(filename, allowed_keys = None, strip_quotes = True, assert_quotes = True):
- """ Reads a KEY=Value style file (e.g. xensource-inventory). Returns a
- dictionary of key/values in the file. Not designed for use with large files
- as the file is read entirely into memory."""
-
- f = open(filename, "r")
- lines = [x.strip("\n") for x in f.readlines()]
- f.close()
-
- # remove lines contain
- if allowed_keys:
- lines = filter(lambda x: True in [x.startswith(y) for y in allowed_keys],
- lines)
-
- defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ]
-
- if strip_quotes:
- def quotestrip(x):
- if assert_quotes:
- assert x.startswith("'") and x.endswith("'")
- return x.strip("'")
- defs = [ (a, quotestrip(b)) for (a,b) in defs ]
-
- return dict(defs)
-
-
-class StringIOmtime(StringIO.StringIO):
- def __init__(self, buf = ''):
- StringIO.StringIO.__init__(self, buf)
- self.mtime = time.time()
-
- def write(self, s):
- StringIO.StringIO.write(self, s)
- self.mtime = time.time()
-
-
-if __name__ == "__main__":
- try:
- sys.exit(main())
- except KeyboardInterrupt:
- print "\nInterrupted."
- sys.exit(3)