2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-13 14:07:02 +00:00
Files
openvswitch/xenserver/usr_sbin_xen-bugtool
Ben Pfaff 1fa5a1050f xenserver: Update to use upstream XenServer location for dbcache.
I thought that this was going to be more difficult (see this email thread:
http://openvswitch.org/pipermail/dev_openvswitch.org/2010-January/001023.html
) but it turned out to be trivial.
2010-01-26 10:35:11 -08:00

1463 lines
50 KiB
Python
Executable File

#!/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"
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'
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-.*')
RESOLV_CONF = '/etc/resolv.conf'
MULTIPATH_CONF = '/etc/multipath.conf'
NSSWITCH_CONF = '/etc/nsswitch.conf'
NTP_CONF = '/etc/ntp.conf'
IPTABLES_CONFIG = '/etc/sysconfig/iptables-config'
HOSTS_ALLOW = '/etc/hosts.allow'
HOSTS_DENY = '/etc/hosts.deny'
DHCP_LEASE_DIR = '/var/lib/dhclient'
DELL_OMSA_LOGS = '/var/log/dell'
HP_CMA_LOG = '/var/spool/compaq/cma.log'
HP_HPASMD_LOG = '/var/spool/compaq/hpasmd.log'
VAR_LOG_DIR = '/var/log/'
VNCTERM_CORE_DIR = '/var/xen/vncterm'
VSWITCH_CORE_DIR = '/var/xen/vswitch'
OVS_VSWITCH_CONF = '/etc/ovs-vswitchd.conf'
OVS_VSWITCH_DBCACHE = '/var/xapi/network.dbcache'
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'
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', 'xenstored-access.log', 'SMlog', 'xen/xenstored-trace.log',
'xen/xen-hotplug.log', 'xen/domain-builder-ng.log'] +
[ f % n for n in range(1, 20) \
for f in ['xensource.log.%d', 'xensource.log.%d.gz','SMlog.%d', 'SMlog.%d.gz',
'xenstored-access.log.%d', 'xenstored-access.log.%d.gz', \
'xen/xenstored-access.log.%d', 'xen/xenstored-access.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'
#
# 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'
MD5SUM = '/usr/bin/md5sum'
MULTIPATHD = '/sbin/multipathd'
NETSTAT = '/bin/netstat'
OMREPORT = '/opt/dell/srvadmin/oma/bin/omreport'
OVS_DPCTL = '/usr/bin/ovs-dpctl'
OVS_OFCTL = '/usr/bin/ovs-ofctl'
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
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_VSWITCH_CONFIG = 'vswitch-config'
CAP_VSWITCH_LOGS = 'vswitch-logs'
CAP_VSWITCH_STATUS = 'vswitch-status'
CAP_WLB = 'wlb'
CAP_X11_LOGS = 'X11'
CAP_X11_AUTH = 'X11-auth'
CAP_XAPI_DEBUG = 'xapi-debug'
CAP_XAPI_SUBPROCESS = 'xapi-subprocess'
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):
caps[key] = (key, pii, min_size, max_size, min_time, max_time, mime,
checked)
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=60)
cap(CAP_DISK_INFO, PII_MAYBE, max_size=25*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=30*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)
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=80*KB,
max_time=5)
cap(CAP_LOSETUP_A, PII_MAYBE, max_size=KB, max_time=5)
cap(CAP_MULTIPATH, PII_MAYBE, max_size=10*KB,
max_time=10)
cap(CAP_NETWORK_CONFIG, PII_IF_CUSTOMIZED,
min_size=0, max_size=20*KB)
cap(CAP_NETWORK_STATUS, PII_YES, max_size=19*KB,
max_time=30)
cap(CAP_PAM, PII_NO, max_size=10*KB)
cap(CAP_PERSISTENT_STATS, PII_MAYBE, max_size=50*MB,
max_time=60)
cap(CAP_PROCESS_LIST, PII_YES, max_size=10*KB,
max_time=10)
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_VSWITCH_CONFIG, PII_YES,
min_size=0, max_size=20*MB)
cap(CAP_VSWITCH_LOGS, PII_YES, max_size=20*MB)
cap(CAP_VSWITCH_STATUS, PII_YES, max_size=19*KB,
max_time=30)
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_XENSERVER_CONFIG, PII_MAYBE, max_size=50*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=20)
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=50*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:
a = [aa for aa in args]
a[0] = os.path.basename(a[0])
if not label:
label = ' '.join(a)
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
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_VSWITCH_CONFIG, CAP_VSWITCH_LOGS, CAP_VSWITCH_STATUS, CAP_WLB,
CAP_X11_LOGS, CAP_X11_AUTH, CAP_XAPI_DEBUG, CAP_XAPI_SUBPROCESS,
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])
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)
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])
# 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)
cmd_output(CAP_LOSETUP_A, [LOSETUP, '-a'])
file_output(CAP_MULTIPATH, [MULTIPATH_CONF])
cmd_output(CAP_MULTIPATH, [DMSETUP, 'status'])
func_output(CAP_MULTIPATH, 'multipathd_topology', multipathd_topology)
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])
file_output(CAP_NETWORK_CONFIG, [NTP_CONF, IPTABLES_CONFIG, HOSTS_ALLOW, HOSTS_DENY])
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])
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_OEM, DELL_OMSA_LOGS)
file_output(CAP_OEM, [HP_CMA_LOG, HP_HPASMD_LOG])
if os.path.exists(OMREPORT):
cmd_output(CAP_OEM, [OMREPORT, 'system', 'alertlog'])
cmd_output(CAP_OEM, [OMREPORT, 'system', 'cmdlog'])
cmd_output(CAP_OEM, [OMREPORT, 'system', 'esmlog'])
cmd_output(CAP_OEM, [OMREPORT, 'system', 'postlog'])
cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'fans'])
cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'memory'])
cmd_output(CAP_OEM, [OMREPORT, 'chassis', 'temps'])
cmd_output(CAP_OEM, [OMREPORT, 'storage', 'controller'])
for i in range(0, 4):
cmd_output(CAP_OEM, [OMREPORT, 'storage', 'adisk', 'controller=%d' % i])
cmd_output(CAP_OEM, [OMREPORT, 'storage', 'vdisk', 'controller=%d' % i])
cmd_output(CAP_OEM, [FIND, '/.state', '-size', '+20k', '-exec', 'ls', '-l', '{}',';'],
label = "state+20k")
tree_output(CAP_PAM, PAM_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,wchan:25,args'], label='process-tree')
file_output(CAP_SYSTEM_LOGS,
[ VAR_LOG_DIR + x for x in
[ 'syslog', 'messages', 'monitor_memory.log', 'secure', 'debug', 'dmesg', 'boot.msg' ] +
[ f % n for n in range(1, 20) \
for f in ['messages.%d', 'messages.%d.gz', 'monitor_memory.log.%d',
'monitor_memory.log.%d.gz', 'secure.%d', 'secure.%d.gz']]])
if not os.path.exists('/var/log/dmesg') and not os.path.exists('/var/log/boot.msg'):
cmd_output(CAP_SYSTEM_LOGS, [DMESG])
cmd_output(CAP_SYSTEM_SERVICES, [CHKCONFIG, '--list'])
if CAP_TAPDISK_LOGS in entries:
generate_tapdisk_logs()
tree_output(CAP_VNCTERM, VNCTERM_CORE_DIR)
file_output(CAP_VSWITCH_CONFIG, [OVS_VSWITCH_CONF])
file_output(CAP_VSWITCH_CONFIG, [OVS_VSWITCH_DBCACHE])
file_output(CAP_VSWITCH_LOGS,
[ VAR_LOG_DIR + x for x in
[ 'ovs-brcompatd.log', 'ovs-vswitchd.log', 'vswitch-cfg-update.log', 'vswitch-xsplugin.log' ] +
[ f % n for n in range(1, 20) \
for f in ['ovs-brcompatd.log.%d', 'ovs-brcompatd.log.%d.gz',
'ovs-vswitchd.log.%d', 'ovs-vswitchd.log.%d.gz']]])
cmd_output(CAP_VSWITCH_STATUS, [OVS_DPCTL, 'show'])
tree_output(CAP_VSWITCH_STATUS, VSWITCH_CORE_DIR)
for d in dp_list():
cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'show', d])
cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'status', d])
cmd_output(CAP_VSWITCH_STATUS, [OVS_OFCTL, 'dump-flows', d])
cmd_output(CAP_VSWITCH_STATUS, [OVS_DPCTL, 'dump-flows', d])
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)
file_output(CAP_XENSERVER_CONFIG, [INITIAL_INVENTORY])
file_output(CAP_XENSERVER_CONFIG, [POOL_CONF, PTOKEN, XAPI_CONF, XAPI_SSL_CONF, STATIC_VDIS,
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)
func_output(CAP_XENSERVER_DATABASES, 'xapi-db.xml', dump_filtered_xapi_db)
cmd_output(CAP_XENSERVER_DATABASES, [XENSTORE_LS])
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])
file_output(CAP_XENSERVER_LOGS, XENSERVER_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'])
# 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 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, ['/tmp/tapdisk.log.%d' % pid for pid in pidof('tapdisk')])
def clean_tapdisk_logs():
for filename in [f for f in os.listdir('/tmp') if f.startswith('tapdisk.log.')]:
try:
os.remove(os.path.join('tmp', 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
def filter_db_pii(str):
str = re.sub(r'(password_transformed&quot; &quot;)[^ ]+(&quot;)', r'\1REMOVED\2', str)
str = re.sub(r'(wlb_password=")[^"]+(")', r'\1REMOVED\2', str)
return str
def dump_filtered_xapi_db(cap):
db_file = None
format = None
# 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 ''
remain = ''
rec = ih.read(2048)
while rec != '':
remain += rec
p = remain.find('>')
while p != -1:
str = remain[:p+1]
remain = remain[p+1:]
output += filter_db_pii(str)
p = remain.find('>')
rec = ih.read(2048)
output += remain
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 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 = []
def rotate_string(x, n):
transtbl = ""
for a in range(0, 256):
transtbl = transtbl + chr(a)
transtbl = transtbl[n:] + transtbl[0:n]
return x.translate(transtbl)
def _untransform_string(str, remove_trailing_nulls=False):
"""De-obfuscate string. To cope with an obfuscation bug in Rio, the argument
remove_trailing_nulls should be set to True"""
tmp = base64.decodestring(str)
if remove_trailing_nulls:
tmp = tmp.rstrip('\x00')
return rotate_string(tmp, -13)
for pbd in session.xenapi.PBD.get_all_records().values():
if pbd.has_key('device_config') and pbd['device_config'].has_key('target'):
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_transformed'):
server += ',' + _untransform_string(dev_cfg['password_transformed'])
procs.append(ProcOutput([CSL, server, 'srv-log-get'], caps[cap][MAX_TIME], output))
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 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())
else:
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), caps.keys())
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 dp_list():
command = [OVS_DPCTL, "dump-dps"]
proc = Popen(command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null)
(dps, err) = proc.communicate()
return dps.splitlines()
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
def __del__(self):
self.terminate()
def run(self):
self.timed_out = False
try:
if ProcOutput.debug:
output_ts("Starting '%s'" % ' '.join(self.command))
self.proc = Popen(self.command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null)
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" % ' '.join(self.command))
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)
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" % ' '.join(p.command))
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)