Files
s390-tools/scripts/dbginfo.sh
Sebastian Ott b9e47e356b dbginfo: gather nvme related data
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.vnet.ibm.com>
2018-02-16 10:38:08 +01:00

1156 lines
30 KiB
Bash
Executable File

#!/bin/sh
#
# dbginfo.sh - Tool to collect runtime, configuration, and trace information
#
# Copyright IBM Corp. 2002, 2017
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
#
# Switching to neutral locale
LC_ALL=C
export LC_ALL
# The general name of this script
readonly SCRIPTNAME="${0##*/}"
########################################
# print version info
print_version() {
cat <<EOF
${SCRIPTNAME}: Debug information script version %S390_TOOLS_VERSION%
Copyright IBM Corp. 2002, 2017
EOF
}
########################################
# print how to use this script
print_usage()
{
print_version
cat <<EOF
Usage: ${SCRIPTNAME} [OPTIONS]
This script collects runtime, configuration and trace information about
your Linux on System z installation for debugging purposes.
It also traces information about z/VM if the Linux runs under z/VM.
The collected information is written to a TAR archive named
/tmp/DBGINFO-[date]-[time]-[hostname]-[processorid].tgz
where [date] and [time] are the date and time when debug data is collected.
[hostname] indicates the hostname of the system the data was collected from.
The [processorid] is taken from the processor 0 and indicates the processor
identification.
Options:
-d|--directory specify the directory where the data collection
stores the temporary data and the final archive.
-h|--help print this help
-v|--version print version information
Please report bugs to: linux390@de.ibm.com
EOF
}
######################################
# Verification to run as root
#
if test "$(/usr/bin/id -u 2>/dev/null)" -ne 0; then
echo "${SCRIPTNAME}: Error: You must be user root to run \"${SCRIPTNAME}\"!"
exit 1
fi
#######################################
# Parsing the command line
#
paramWORKDIR_BASE="/tmp/"
while [ ${#} -gt 0 ]; do
case ${1} in
--help|-h)
print_usage
exit 0
;;
--version|-v)
print_version
exit 0
;;
--directory|-d)
paramWORKDIR_BASE=${2}
shift
;;
-*|--*|*)
echo
echo "${SCRIPTNAME}: invalid option \"${1}\""
echo "Try '${SCRIPTNAME} --help' for more information"
echo
exit 1
;;
esac
shift
done
if test -z "${paramWORKDIR_BASE}"; then
echo "${SCRIPTNAME}: Error: No directory specified for data collection!"
echo
exit 1
fi
if test ! -d "${paramWORKDIR_BASE}"; then
echo "${SCRIPTNAME}: Error: The specified directory \"${paramWORKDIR_BASE}\" does not exist!"
echo
exit 1
fi
########################################
# Global used variables
#
# The base working directory
readonly WORKDIR_BASE="$(echo "${paramWORKDIR_BASE}" | sed -e 's#/$##')/"
# The terminal
readonly TERMINAL="$(tty 2>/dev/null)"
# The hostname of the system
readonly SYSTEMHOSTNAME="$(hostname -s 2>/dev/null)"
# The kernel release version as delivered from uname -r
readonly KERNEL_RELEASE_VERSION="$(uname -r 2>/dev/null)"
# The processor ID for the first processor
readonly PROCESSORID="$(grep -E ".*processor 0:.*" /proc/cpuinfo | \
sed 's/.*identification[[:space:]]*\=[[:space:]]*\([[:alnum:]]*\).*/\1/g')"
# The processor version for the first processor
readonly PROCESSORVERSION="$(grep -E ".*processor 0:.*" /proc/cpuinfo | \
sed 's/.*version[[:space:]]*\=[[:space:]]*\([[:alnum:]]*\).*/\1/g')"
# The current date
readonly DATETIME="$(date +%Y-%m-%d-%H-%M-%S 2>/dev/null)"
# The current working directory for the actual script execution
if test -z "${PROCESSORID}"; then
readonly WORKDIR_CURRENT="DBGINFO-${DATETIME}-${SYSTEMHOSTNAME:-localhost}"
else
readonly WORKDIR_CURRENT="DBGINFO-${DATETIME}-${SYSTEMHOSTNAME:-localhost}-${PROCESSORID}"
fi
# The current path where the collected information is put together
readonly WORKPATH="${WORKDIR_BASE}${WORKDIR_CURRENT}/"
# The current TAR archive that finally includes all collected information
readonly WORKARCHIVE="${WORKDIR_BASE}${WORKDIR_CURRENT}.tgz"
# The log file of activities from this script execution
readonly LOGFILE="${WORKPATH}dbginfo.log"
# The file to indicate that another instance of the script is already running
readonly LOCKFILE="/tmp/${SCRIPTNAME}.lock"
# File that includes output of Linux commands
readonly OUTPUT_FILE_CMD="${WORKPATH}runtime.out"
# File that includes output of z/VM commands (if running in z/VM)
readonly OUTPUT_FILE_VMCMD="${WORKPATH}zvm_runtime.out"
# File that includes content of files from sysfs
readonly OUTPUT_FILE_SYSFS="${WORKPATH}sysfsfiles.out"
# File that includes content of OSA OAT
readonly OUTPUT_FILE_OSAOAT="${WORKPATH}osa_oat"
# File that includes the output of journalctl
readonly OUTPUT_FILE_JOURNALCTL="${WORKPATH}journalctl.out"
# File that includes the output of OpenVSwitch
readonly OUTPUT_FILE_OVS="${WORKPATH}openvswitch"
# File that includes the KVM domain xml file
readonly OUTPUT_FILE_XML="${WORKPATH}domain_xml"
# File that includes the docker inspect output
readonly OUTPUT_FILE_DOCKER="${WORKPATH}docker_inspect.out"
# File that includes nvme related information
readonly OUTPUT_FILE_NVME="${WORKPATH}nvme.out"
# Mount point of the debug file system
readonly MOUNT_POINT_DEBUGFS="/sys/kernel/debug"
# The amount of steps running the whole collections
readonly COLLECTION_COUNT=12
# The kernel version (e.g. '2' from 2.6.32 or '3' from 3.2.1)
readonly KERNEL_VERSION=$(uname -r 2>/dev/null | cut -d'.' -f1)
# The kernel major revision number (e.g. '6' from 2.6.32 or '2' from 3.2.1)
readonly KERNEL_MAJOR_REVISION=$(uname -r 2>/dev/null | cut -d'.' -f2)
# The kernel mainor revision number (e.g. '32' from 2.6.32 or '1' from 3.2.1)
readonly KERNEL_MINOR_REVISION=$(uname -r 2>/dev/null | cut -d'.' -f3 | sed 's/[^0-9].*//g')
# Is this kernel supporting sysfs - since 2.4 (0=yes, 1=no)
if test "${KERNEL_VERSION}" -lt 2 ||
( test "${KERNEL_VERSION}" -eq 2 && test "${KERNEL_MAJOR_REVISION}" -le 4 ); then
readonly LINUX_SUPPORT_SYSFS=1
else
readonly LINUX_SUPPORT_SYSFS=0
fi
# Is this kernel potentially using the /sys/kernel/debug feature - since 2.6.13 (0=yes, 1=no)
if test "${KERNEL_VERSION}" -lt 2 ||
( test "${KERNEL_VERSION}" -eq 2 &&
( test "${KERNEL_MAJOR_REVISION}" -lt 6 ||
( test "${KERNEL_MAJOR_REVISION}" -eq 6 && test "${KERNEL_MINOR_REVISION}" -lt 13 ))); then
readonly LINUX_SUPPORT_SYSFSDBF=1
else
readonly LINUX_SUPPORT_SYSFSDBF=0
fi
if test "x${PROCESSORVERSION}" = "xFF" || test "x${PROCESSORVERSION}" = "xff"; then
readonly RUNTIME_ENVIRONMENT=$(grep -E "VM00.*Control Program.*" /proc/sysinfo| sed 's/.*:[[:space:]]*\([[:graph:]]*\).*/\1/g')
else
readonly RUNTIME_ENVIRONMENT="LPAR"
fi
########################################
# Collection of proc fs entries
PROCFILES="\
/proc/buddyinfo\
/proc/cio_ignore\
/proc/cmdline\
/proc/cpuinfo\
/proc/crypto\
/proc/dasd/devices\
/proc/dasd/statistics\
/proc/devices\
/proc/diskstats\
/proc/driver/z90crypt\
/proc/interrupts\
/proc/iomem\
/proc/mdstat\
/proc/meminfo\
/proc/misc\
/proc/modules\
/proc/mounts\
/proc/net/vlan\
/proc/net/bonding\
/proc/partitions\
/proc/qeth\
/proc/qeth_perf\
/proc/qeth_ipa_takeover\
/proc/sched_debug\
/proc/schedstat\
/proc/service_levels\
/proc/slabinfo\
/proc/stat\
/proc/swaps\
/proc/sys/kernel\
/proc/sys/vm\
/proc/sysinfo\
/proc/version\
/proc/zoneinfo\
"
# Adding files to PROCFILES in case scsi devices are available
if test -e /proc/scsi; then
PROCFILES="${PROCFILES}\
$(find /proc/scsi -type f -perm /444 2>/dev/null)\
"
fi
# Adding files to PROCFILES in case we run on Kernel 2.4 or older
if test "${LINUX_SUPPORT_SYSFS}" -eq 1; then
PROCFILES="${PROCFILES}\
/proc/chpids\
/proc/chandev\
/proc/ksyms\
/proc/lvm/global\
/proc/subchannels\
"
fi
# Adding s390dbf files to PROCFILE in case we run on Kernel lower than 2.6.13
if test "${LINUX_SUPPORT_SYSFSDBF}" -eq 1; then
if test -e /proc/s390dbf; then
PROCFILES="${PROCFILES}\
$(find /proc/s390dbf -type f -not -path "*/raw" -not -path "*/flush" 2>/dev/null)\
"
fi
fi
########################################
LOGFILES="\
/var/log/anaconda.*\
/var/log/audit\
/var/log/boot*\
/var/log/cron*\
/var/log/dmesg*\
/var/log/dracut.log*\
/var/log/IBMtape.trace\
/var/log/IBMtape.errorlog\
/var/log/libvirt\
/var/log/lin_tape.trace\
/var/log/lin_tape.errorlog\
/var/log/messages*\
/var/log/syslog*\
/var/log/sa\
/var/log/yum.log\
/var/log/openvswitch/ovs-vswitchd.log\
/var/log/openvswitch/ovsdb-server.log\
/var/run/docker/libcontainerd/containerd/events.log\
/run/containerd/events.log\
"
########################################
CONFIGFILES="\
/boot/grub2/grub.cfg\
/boot/zipl/active_devices.txt\
/boot/zipl/config\
/etc/*.conf\
/etc/anacrontab\
/etc/auto.*\
/etc/cron.*\
/etc/crontab\
/etc/crypttab\
/etc/default\
/etc/depmod.d\
/etc/dracut.conf.d\
/etc/exports\
/etc/fstab\
/etc/groups\
/etc/grub.d\
/etc/hosts*\
/etc/iscsi\
/etc/inittab\
/etc/libvirt\
/etc/logrotate.d\
/etc/lvm\
/etc/modprobe.conf*\
/etc/modprobe.d\
/etc/mtab\
/etc/multipath\
/etc/network\
/etc/networks\
/etc/pam.d\
/etc/profile\
/etc/profile.d\
/etc/pki/tls/openssl.cnf\
/etc/rc.d\
/etc/rc.local\
/etc/resolv.*\
/etc/rsyslog.d\
/etc/ssl/openssl.conf\
/etc/ssl/openssl.cnf\
/etc/sysconfig\
/etc/sysctl.d\
/etc/syslog*\
/etc/systemd\
/etc/udev*\
/etc/xinet.d\
/etc/*release\
$(find /lib/modules -name modules.dep 2>/dev/null)\
/etc/docker\
/lib/systemd/system/docker.service\
/usr/lib/systemd/system/docker.service\
/etc/apparmor.d\
"
########################################
CMDS="uname -a\
:uptime\
:runlevel\
:iptables -L\
:ulimit -a\
:ps -emo pid,tid,nlwp,policy,user,tname,ni,pri,psr,sgi_p,stat,wchan,start_time,time,pcpu,pmem,vsize,size,rss,share,command\
:ps -eHo pid,tid,nlwp,policy,user,tname,ni,pri,psr,sgi_p,stat,wchan,start_time,time,pcpu,pmem,vsize,size,rss,share,command\
:ps axX\
:dmesg -s 1048576\
:last\
:lsshut\
:ifconfig -a\
:nm-tool\
:route -n\
:ip route list\
:ip route list table all\
:ip rule list\
:ip neigh list\
:ip link show\
:ip ntable\
:ip a sh\
:firewall-cmd --list-all\
:ipcs -a\
:netstat -pantu\
:netstat -s\
:dmsetup ls\
:dmsetup ls --tree\
:dmsetup table\
:dmsetup table --target multipath\
:dmsetup status\
:multipathd -k'show config'\
:multipathd -k'show maps'\
:multipathd -k'show topo'\
:multipathd -k'show paths'\
:multipathd -k'show maps stats'\
:multipathd -k'show maps status'\
:multipathd -k'show status'\
:multipathd -k'show daemon'\
:multipathd -k'show blacklist'\
:multipathd -k'show devices'\
:multipath -v6 -ll\
:multipath -d\
:multipath -t\
:lsqeth\
:lschp\
:lscss\
:lscpu -ae\
:lsmem\
:lsdasd\
:lsdasd -u\
:ziorep_config -ADM\
:lsmod\
:lsdev\
:lsscsi\
:lstape\
:lszfcp\
:lszfcp -D\
:lszfcp -V\
:icainfo\
:icastats\
:lszcrypt -VV\
:ivp.e\
:pkcsconf -mlist\
:cat /var/lib/opencryptoki/pk_config_data\
:ls -al /usr/lib64/opencryptoki/stdll\
:SPident\
:rpm -qa | sort\
:sysctl -a\
:lsof\
:mount\
:df -h\
:df -i\
:pvpath -qa\
:find /boot -print0 | sort -z | xargs -0 -n 10 ls -ld\
:find /dev -print0 | sort -z | xargs -0 -n 10 ls -ld\
:java -version\
:cat /root/.bash_history\
:env\
:journalctl --all --no-pager --since=$(date -d '5 day ago' +%Y-%m-%d) --until=now --lines=50000 \
> '${OUTPUT_FILE_JOURNALCTL}'\
:openssl engine\
:systemd-delta\
:systemctl --all --no-pager show\
:systemctl --all --no-pager list-units\
:systemctl --all --no-pager list-unit-files\
:docker info\
:docker images\
:docker network ls\
:docker ps -a\
:docker version\
:docker stats --no-stream\
:systemctl status docker.service\
"
########################################
VM_CMDS="q userid\
:q users\
:q privclass\
:q cplevel\
:q cpservice\
:q ssi\
:q cpus\
:q srm\
:q vtod\
:q timezone\
:q loaddev\
:q v osa\
:q v dasd\
:q v crypto\
:q v fcp\
:q v pav\
:q v sw\
:q v st\
:q v nic\
:q st\
:q xstore\
:q xstore user system\
:q sxspages\
:q vmlan\
:q vswitch\
:q vswitch details\
:q vswitch access\
:q vswitch active\
:q vswitch accesslist\
:q vswitch promiscuous\
:q vswitch controller\
:q port group all active details\
:q set\
:q comm\
:q controller all\
:q fcp\
:q frames\
:q lan\
:q lan all details\
:q lan all access\
:q cache\
:q nic\
:q pav\
:q proc\
:q proc topology\
:q mt\
:q qioass\
:q spaces\
:q swch all\
:q trace\
:q mdcache\
:q alloc page\
:q alloc spool\
:q dump\
:q dumpdev\
:q reorder VMUSERID\
:q quickdsp VMUSERID\
:ind load\
:ind sp\
:ind user\
"
###############################################################################
########################################
collect_cmdsout() {
local cmd
local ifs_orig
ifs_orig="${IFS}"
pr_syslog_stdout "1 of ${COLLECTION_COUNT}: Collecting command output"
IFS=:
for cmd in ${CMDS}; do
IFS=${ifs_orig} call_run_command "${cmd}" "${OUTPUT_FILE_CMD}"
done
IFS="${ifs_orig}"
pr_log_stdout " "
}
########################################
collect_vmcmdsout() {
local vm_command
local cp_command
local vm_cmds
local vm_userid
local module_loaded
local ifs_orig
local cp_buffer_size
local rc_buffer_size
module_loaded=1
ifs_orig="${IFS}"
if echo "${RUNTIME_ENVIRONMENT}" | grep -qi "z/VM" >/dev/null 2>&1; then
pr_syslog_stdout "2 of ${COLLECTION_COUNT}: Collecting z/VM command output"
if which vmcp >/dev/null 2>&1; then
cp_command="vmcp"
if ! lsmod 2>/dev/null | grep -q vmcp && modinfo vmcp >/dev/null 2>&1; then
modprobe vmcp && module_loaded=0 && sleep 2
fi
elif which hcp >/dev/null 2>&1; then
cp_command="hcp"
if ! lsmod 2>/dev/null | grep -q cpint; then
modprobe cpint && module_loaded=0 && sleep 2
fi
else
pr_log_stdout " "
pr_log_stdout "${SCRIPTNAME}: Warning: No program found to communicate to z/VM CP"
pr_log_stdout " Skipping collection of z/VM command output"
pr_log_stdout " "
return 1
fi
vm_userid=$(${cp_command} q userid 2>/dev/null | sed -ne 's/^\([^[:space:]]*\).*$/\1/p')
vm_cmds=$(echo "${VM_CMDS}" | sed "s/VMUSERID/${vm_userid}/g")
IFS=:
for vm_command in ${vm_cmds}; do
IFS="${ifs_orig}"
cp_buffer_size=2
rc_buffer_size=2
while test ${rc_buffer_size} -eq 2 && test ${cp_buffer_size} -lt 1024; do
cp_buffer_size=$(( cp_buffer_size * 2 ))
eval ${cp_command} -b ${cp_buffer_size}k "${vm_command}" >/dev/null 2>&1
rc_buffer_size=$?
done
call_run_command "${cp_command} -b ${cp_buffer_size}k ${vm_command}" "${OUTPUT_FILE_VMCMD}"
IFS=:
done
IFS=${ifs_orig}
if test ${module_loaded} -eq 0 && test "x${cp_command}" = "xhcp"; then
rmmod cpint
elif test ${module_loaded} -eq 0 && test "x${cp_command}" = "xvmcp"; then
rmmod vmcp
fi
else
pr_syslog_stdout "2 of ${COLLECTION_COUNT}: Collecting z/VM command output skipped - no z/VM environment"
fi
pr_log_stdout " "
}
########################################
collect_procfs() {
local file_name
pr_syslog_stdout "3 of ${COLLECTION_COUNT}: Collecting procfs"
for file_name in ${PROCFILES}; do
call_collect_file "${file_name}"
done
pr_log_stdout " "
}
########################################
collect_sysfs() {
local debugfs_mounted
local dir_name
local file_name
debugfs_mounted=0
# Requires kernel version newer then 2.4
if test "${LINUX_SUPPORT_SYSFS}" -eq 0; then
pr_syslog_stdout "4 of ${COLLECTION_COUNT}: Collecting sysfs"
# Requires kernel version of 2.6.13 or newer
if test "${LINUX_SUPPORT_SYSFSDBF}" -eq 0; then
if ! grep -qE "${MOUNT_POINT_DEBUGFS}.*debugfs" /proc/mounts 2>/dev/null; then
if mount -t debugfs debugfs "${MOUNT_POINT_DEBUGFS}" >/dev/null 2>&1; then
sleep 2
debugfs_mounted=1
else
pr_log_stdout "${SCRIPTNAME}: Warning: Unable to mount debugfs at \"${MOUNT_POINT_DEBUGFS}\""
fi
fi
fi
# Collect sysfs files using multiple threads (-J 1) while excluding
# files known to block on read (-x). Stop reading a file that takes
# more than 5 seconds (-T 5) such as an active ftrace buffer.
dump2tar /sys -z -o "${WORKPATH}/sysfs.tgz" -x '*/tracing/trace_pipe*' \
-x '*/tracing/per_cpu/*' --ignore-failed-read -J 1 -T 5
if [ $? -ne 0 ] ; then
echo "${SCRIPTNAME}: Warning: dump2tar failed or is unavailable - falling back to slow path"
call_run_command "find /sys -print0 | sort -z | xargs -0 -n 10 ls -ld" "${OUTPUT_FILE_SYSFS}"
find /sys -noleaf -type d 2>/dev/null | while IFS= read -r dir_name; do
mkdir -p "${WORKPATH}${dir_name}"
done
find /sys -noleaf -type f -perm /444\
-a -not -name "*trace_pipe*"\
2>/dev/null | while IFS= read -r file_name; do
echo " ${file_name}"
if ! dd if="${file_name}" status=noxfer iflag=nonblock of="${WORKPATH}${file_name}" >/dev/null 2>&1; then
echo "${SCRIPTNAME}: Warning: failed to copy \"${file_name}\""
fi
done
fi
if test ${debugfs_mounted} -eq 1; then
umount "${MOUNT_POINT_DEBUGFS}"
fi
else
pr_syslog_stdout "4 of ${COLLECTION_COUNT}: Collecting sysfs skipped. Kernel $(uname -r) must be newer than 2.4"
fi
pr_log_stdout " "
}
########################################
collect_logfiles() {
local file_name
pr_syslog_stdout "5 of ${COLLECTION_COUNT}: Collecting log files"
for file_name in ${LOGFILES}; do
call_collect_file "${file_name}"
done
pr_log_stdout " "
}
########################################
collect_configfiles() {
local file_name
pr_syslog_stdout "6 of ${COLLECTION_COUNT}: Collecting config files"
for file_name in ${CONFIGFILES}; do
call_collect_file "${file_name}"
done
pr_log_stdout " "
}
########################################
collect_osaoat() {
local network_devices
local network_device
network_devices=$(lsqeth 2>/dev/null | grep "Device name" \
| sed 's/.*:[[:space:]]\+\([^[:space:]]*\)[[:space:]]\+/\1/g')
if which qethqoat >/dev/null 2>&1; then
if test -n "${network_devices}"; then
pr_syslog_stdout "7 of ${COLLECTION_COUNT}: Collecting osa oat output"
for network_device in ${network_devices}; do
call_run_command "qethqoat ${network_device}" "${OUTPUT_FILE_OSAOAT}.out" &&
call_run_command "qethqoat -r ${network_device}" "${OUTPUT_FILE_OSAOAT}_${network_device}.raw"
done
else
pr_syslog_stdout "7 of ${COLLECTION_COUNT}: Collecting osa oat output skipped - no devices"
fi
else
pr_syslog_stdout "7 of ${COLLECTION_COUNT}: Collecting osa oat output skipped - not available"
fi
pr_log_stdout " "
}
########################################
# OpenVSwitch
collect_ovs() {
local br_list
local ovscmd
local bridge
local ovsbrcmd
local ovscmds
local ovsbrcmds
br_list=$(ovs-vsctl list-br)
ovscmds="ovs-dpctl -s show\
:ovs-vsctl -t 5 show\
:ovsdb-client dump\
"
if test -n "${br_list}"; then
pr_syslog_stdout "8 of ${COLLECTION_COUNT}: Collecting OpenVSwitch output"
IFS=:
for ovscmd in ${ovscmds}; do
IFS=${ifs_orig} call_run_command "${ovscmd}" "${OUTPUT_FILE_OVS}.out"
done
IFS="${ifs_orig}"
for bridge in ${br_list}; do
ovsbrcmds="ovs-ofctl show ${bridge}\
:ovs-ofctl dump-flows ${bridge}\
:ovs-appctl fdb/show ${bridge}\
"
IFS=:
for ovsbrcmd in ${ovsbrcmds}; do
IFS=${ifs_orig} call_run_command "${ovsbrcmd}" "${OUTPUT_FILE_OVS}.out"
done
IFS="${ifs_orig}"
done
else
pr_syslog_stdout "8 of ${COLLECTION_COUNT}: Collecting OpenVSwitch output skipped"
fi
pr_log_stdout " "
}
########################################
collect_domain_xml() {
local domain_list
local domain
domain_list=$(virsh list --all --name)
if test -n "${domain_list}"; then
pr_syslog_stdout "9 of ${COLLECTION_COUNT}: Collecting domain xml files"
for domain in ${domain_list}; do
call_run_command "virsh dumpxml ${domain}" "${OUTPUT_FILE_XML}_${domain}.xml"
done
else
pr_syslog_stdout "9 of ${COLLECTION_COUNT}: Collecting domain xml files skipped"
fi
pr_log_stdout " "
}
########################################
collect_docker() {
local item_list
local item
# call docker inspect for all containers
item_list=$(docker ps -qa)
if test -n "${item_list}"; then
pr_syslog_stdout "10a of ${COLLECTION_COUNT}: Collecting docker container output"
for item in ${item_list}; do
call_run_command "docker inspect ${item}" "${OUTPUT_FILE_DOCKER}"
done
else
pr_syslog_stdout "10a of ${COLLECTION_COUNT}: Collecting docker container output skipped"
fi
# call docker inspect for all networks
item_list=$(docker network ls -q)
if test -n "${item_list}"; then
pr_syslog_stdout "10b of ${COLLECTION_COUNT}: Collecting docker network output"
for item in ${item_list}; do
call_run_command "docker network inspect ${item}" "${OUTPUT_FILE_DOCKER}"
done
else
pr_syslog_stdout "10b of ${COLLECTION_COUNT}: Collecting docker network output skipped"
fi
pr_log_stdout " "
}
########################################
collect_nvme() {
local NVME
pr_syslog_stdout "11 of ${COLLECTION_COUNT}: Collecting nvme output"
call_run_command "nvme list" "${OUTPUT_FILE_NVME}"
for NVME in /dev/nvme[0-9]*; do
if [ -c $NVME ]; then
call_run_command "smartctl -x $NVME" "${OUTPUT_FILE_NVME}"
call_run_command "nvme fw-log $NVME" "${OUTPUT_FILE_NVME}"
call_run_command "nvme smart-log $NVME" "${OUTPUT_FILE_NVME}"
call_run_command "nvme error-log $NVME" "${OUTPUT_FILE_NVME}"
fi
done
pr_log_stdout " "
}
########################################
post_processing() {
local file_mtime
local file_mtime_epoche
local tmp_file
local file_name
pr_syslog_stdout "${COLLECTION_COUNT} of ${COLLECTION_COUNT}: Postprocessing"
find "${WORKPATH}etc/libvirt/qemu/" -maxdepth 1 -name "*.xml" 2>/dev/null | while IFS= read -r file_name; do
file_mtime_epoche=$(stat --format=%Y "${file_name}")
file_mtime=$(date +%Y%m%d%H%M.%S --date="@${file_mtime_epoche}")
tmp_file=${file_name}.$$
echo " ${file_name}"
if ! sed "s/\( \+passwd='\).*\('\)/\1********\2/g" "${file_name}" > "${tmp_file}"; then
echo "${SCRIPTNAME}: Warning: Postprocessing failed on ${file_name}"
echo
fi
mv "${tmp_file}" "${file_name}"
touch --time=mtime -t "${file_mtime}" "${file_name}"
done
find "${WORKPATH}etc/libvirt/" -name "auth.conf" 2>/dev/null | while IFS= read -r file_name; do
file_mtime_epoche=$(stat --format=%Y "${file_name}")
file_mtime=$(date +%Y%m%d%H%M.%S --date="@${file_mtime_epoche}")
tmp_file=${file_name}.$$
echo " ${file_name}"
if ! sed "s/\(password=\).*/\1********/g" "${file_name}" > "${tmp_file}"; then
echo "${SCRIPTNAME}: Warning: Postprocessing failed on ${file_name}"
echo
fi
mv "${tmp_file}" "${file_name}"
touch --time=mtime -t "${file_mtime}" "${file_name}"
done
find "${WORKPATH}" -maxdepth 1 -name "*.xml" 2>/dev/null | while IFS= read -r file_name; do
file_mtime_epoche=$(stat --format=%Y "${file_name}")
file_mtime=$(date +%Y%m%d%H%M.%S --date="@${file_mtime_epoche}")
tmp_file=${file_name}.$$
echo " ${file_name}"
if ! sed "s/\( \+passwd='\).*\('\)/\1********\2/g" "${file_name}" > "${tmp_file}"; then
echo "${SCRIPTNAME}: Warning: Postprocessing failed on ${file_name}"
echo
fi
mv "${tmp_file}" "${file_name}"
touch --time=mtime -t "${file_mtime}" "${file_name}"
done
pr_log_stdout " "
}
########################################
# Be aware that this output must be
# redirected into a separate logfile
call_run_command() {
local cmd
local logfile
local raw_cmd
cmd="${1}"
logfile="${2}"
raw_cmd=$(echo "${cmd}" | sed -ne 's/^\([^[:space:]]*\).*$/\1/p')
echo "#######################################################" >> "${logfile}"
echo "${USER}@${SYSTEMHOSTNAME:-localhost}> ${cmd}" >> "${logfile}"
# check if command exists
if ! which "${raw_cmd}" >/dev/null 2>&1; then
# check if command is a builtin
if ! command -v "${raw_cmd}" >/dev/null 2>&1; then
echo "${SCRIPTNAME}: Warning: Command \"${raw_cmd}\" not available" >> "${logfile}"
echo >> "${logfile}"
return 1
fi
fi
if ! eval "${cmd}" >> "${logfile}" 2>&1; then
echo "${SCRIPTNAME}: Warning: Command \"${cmd}\" failed" >> "${logfile}"
echo >> "${logfile}"
return 1
else
echo >> "${logfile}"
return 0
fi
}
########################################
call_collect_file() {
local directory_name
local file_name
file_name="${1}"
echo " ${file_name}"
directory_name=$(dirname "${file_name}" 2>/dev/null)
if test ! -e "${WORKPATH}${directory_name}"; then
mkdir -p "${WORKPATH}${directory_name}" 2>&1
fi
if ! cp -r --preserve=mode,timestamps -d -L --parents "${file_name}" "${WORKPATH}" 2>&1; then
return 1
else
return 0
fi
}
###############################################################################
########################################
# print that an instance is already running
print_alreadyrunning() {
print_version
cat <<EOF
Please check the system if another instance of '${SCRIPTNAME}' is already
running. If this is not the case, please remove the lock file
'${LOCKFILE}'.
EOF
}
########################################
# Setup the environment
environment_setup()
{
if test ! -e "${WORKDIR_BASE}"; then
mkdir -p "${WORKDIR_BASE}"
elif test ! -d "${WORKDIR_BASE}"; then
echo "${SCRIPTNAME}: Error: \"${WORKDIR_BASE}\" exists but this is a file!"
echo " Please make sure \"${WORKDIR_BASE}\" is a directory."
exit 1
fi
if test -e "${LOCKFILE}"; then
print_alreadyrunning
exit 1
else
touch "${LOCKFILE}"
echo "${DATETIME}" > "${LOCKFILE}"
fi
if ! mkdir "${WORKPATH}" 2>/dev/null; then
echo "${SCRIPTNAME}: Error: Target directory \"${WORKPATH}\" already exists or"
echo " \"${WORKDIR_BASE}\" does not exist!"
exit 1
fi
chmod 0700 "${WORKPATH}"
}
########################################
# create gzip-ped tar file
create_package()
{
pr_stdout "Finalizing: Creating archive with collected data"
cd "${WORKDIR_BASE}"
if ! tar -czf "${WORKARCHIVE}" "${WORKDIR_CURRENT}"; then
pr_stdout " "
pr_stdout "${SCRIPTNAME}: Error: Collection of data failed!"
pr_stdout " The creation of \"${WORKARCHIVE}\" was not successful."
pr_stdout " Please check the directory \"${WORKDIR_BASE}\""
pr_stdout " to provide enough free available space."
else
chmod 0600 "${WORKARCHIVE}"
pr_stdout " "
pr_stdout "Collected data was saved to:"
pr_stdout " >> ${WORKARCHIVE} <<"
fi
pr_stdout " "
pr_stdout "Review the collected data before sending to your service organization. "
pr_stdout " "
}
########################################
# Cleaning up the prepared/collected information
environment_cleanup()
{
if ! rm -rf "${WORKPATH}" 2>/dev/null; then
pr_stdout " "
pr_stdout "${SCRIPTNAME}: Warning: Deletion of \"${WORKPATH}\" failed"
pr_stdout " Please remove the directory manually"
pr_stdout " "
fi
if ! rm -f "${LOCKFILE}" 2>/dev/null; then
pr_stdout " "
pr_stdout "${SCRIPTNAME}: Warning: Deletion of \"${WORKDIR_BASE}${SCRIPTNAME}\" failed"
pr_stdout " Please remove the file manually"
pr_stdout " "
fi
}
########################################
# Function to perform a cleanup in case of a received signal
emergency_exit()
{
pr_stdout " "
pr_stdout "${SCRIPTNAME}: Info: Data collection has been interrupted"
pr_stdout " Cleanup of temporary collected data"
environment_cleanup
pr_stdout "${SCRIPTNAME}: Info: Emergency exit processed"
pr_stdout " "
logger -t "${SCRIPTNAME}" "Data collection interrupted"
exit
}
########################################
# Function to print to stdout when rediretion is active
pr_stdout()
{
echo "${@}" >&8
}
########################################
# Function to print to stdout and into log file when rediretion is active
pr_log_stdout()
{
echo "$@"
echo "$@" >&8
}
########################################
# Function to print to stdout and into log file when rediretion is active
pr_syslog_stdout()
{
echo "$@"
echo "$@" >&8
logger -t "${SCRIPTNAME}" "$@"
}
###############################################################################
# Running the script
environment_setup
print_version
# saving stdout/stderr and redirecting stdout/stderr into log file
exec 8>&1 9>&2 >"${LOGFILE}" 2>&1
# trap on SIGHUP=1 SIGINT=2 SIGTERM=15
trap emergency_exit SIGHUP SIGINT SIGTERM
pr_log_stdout ""
pr_log_stdout "Hardware platform = $(uname -i)"
pr_log_stdout "Kernel version = ${KERNEL_VERSION}.${KERNEL_MAJOR_REVISION}.${KERNEL_MINOR_REVISION} ($(uname -r 2>/dev/null))"
pr_log_stdout "Runtime environment = ${RUNTIME_ENVIRONMENT}"
pr_log_stdout ""
logger -t "${SCRIPTNAME}" "Starting data collection"
collect_cmdsout
collect_vmcmdsout
# Collecting the proc file system (content is specific based on kernel version)
collect_procfs
# Collecting sysfs in case we run on Kernel 2.4 or newer
collect_sysfs
collect_logfiles
collect_configfiles
collect_osaoat
collect_ovs
collect_domain_xml
collect_docker
collect_nvme
post_processing
create_package
environment_cleanup
logger -t "${SCRIPTNAME}" "Data collection completed"
exec 1>&8 2>&9 8>&- 9>&-
#EOF