
zypper performs some network operations when collecting the list of installed packages which slow down the overall process. We already have the per host list of repositories so we can do some maths to figure out where each package is coming from. As we see below, disabling the repositories saves us ~9s. ~$ time zypper --quiet pa -i real 0m10.607s user 0m9.024s sys 0m0.193s ~$ time zypper --disable-repositories pa -i real 0m1.043s user 0m0.833s sys 0m0.136s On a deployment with multiple containers, the 9s difference causes a lot of overhead and jobs are timing out from time to time. As such, lets just disable the repositories when collecting the list of the installed packages. Change-Id: I3e48dad0e213f6e24a2ceb4033b1a53873b6e298
280 lines
11 KiB
Bash
Executable File
280 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Copyright 2016, Rackspace US, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
# WARNING:
|
|
# This file is use by all OpenStack-Ansible roles for testing purposes.
|
|
# Any changes here will affect all OpenStack-Ansible role repositories
|
|
# with immediate effect.
|
|
|
|
# PURPOSE:
|
|
# This script collects, renames and compresses the logs produced in
|
|
# a role test if the host is in OpenStack-CI.
|
|
|
|
## Vars ----------------------------------------------------------------------
|
|
|
|
export WORKING_DIR=${WORKING_DIR:-$(pwd)}
|
|
export TESTING_HOME=${TESTING_HOME:-$HOME}
|
|
|
|
export RSYNC_CMD="rsync --archive --safe-links --ignore-errors --quiet --no-perms --no-owner --no-group"
|
|
|
|
# NOTE(cloudnull): This is a very simple list of common directories in /etc we
|
|
# wish to search for when storing gate artifacts. When adding
|
|
# things to this list please alphabetize the entries so it's
|
|
# easy for folks to find and adjust items as needed.
|
|
COMMON_ETC_LOG_NAMES="almanach \
|
|
apt \
|
|
aodh \
|
|
apache2 \
|
|
barbican \
|
|
blazar \
|
|
ceilometer \
|
|
cinder \
|
|
cloudkitty \
|
|
congress \
|
|
designate \
|
|
glance \
|
|
gnocchi \
|
|
haproxy \
|
|
heat \
|
|
horizon \
|
|
httpd \
|
|
ironic \
|
|
karbor \
|
|
keystone \
|
|
magnum \
|
|
memcached \
|
|
molteniron \
|
|
monasca \
|
|
mongodb \
|
|
my.cnf \
|
|
mysql \
|
|
netplan \
|
|
network \
|
|
nginx \
|
|
neutron \
|
|
nova \
|
|
octavia \
|
|
panko \
|
|
pip.conf \
|
|
qpid-dispatch \
|
|
rabbitmq \
|
|
rally \
|
|
repo \
|
|
resolv.conf \
|
|
rsyslog \
|
|
sahara \
|
|
searchlight \
|
|
sasl2 \
|
|
swift \
|
|
sysconfig/network-scripts \
|
|
sysconfig/network \
|
|
systemd/network \
|
|
tacker \
|
|
tempest \
|
|
trove \
|
|
watcher \
|
|
yum \
|
|
yum.repos.d \
|
|
zaqar \
|
|
zun \
|
|
zypp"
|
|
|
|
## Functions -----------------------------------------------------------------
|
|
|
|
function repo_information {
|
|
[[ "${1}" != "host" ]] && lxc_cmd="lxc-attach --name ${1} --" || lxc_cmd=""
|
|
echo "Collecting list of installed packages and enabled repositories for \"${1}\""
|
|
# Redhat package debugging
|
|
if eval sudo ${lxc_cmd} which yum &>/dev/null || eval sudo ${lxc_cmd} which dnf &>/dev/null; then
|
|
# Prefer dnf over yum for CentOS.
|
|
eval sudo ${lxc_cmd} which dnf &>/dev/null && RHT_PKG_MGR='dnf' || RHT_PKG_MGR='yum'
|
|
eval sudo ${lxc_cmd} $RHT_PKG_MGR repolist -v > "${WORKING_DIR}/logs/redhat-rpm-repolist-${1}.txt" || true
|
|
eval sudo ${lxc_cmd} $RHT_PKG_MGR list installed > "${WORKING_DIR}/logs/redhat-rpm-list-installed-${1}.txt" || true
|
|
|
|
# SUSE package debugging
|
|
elif eval sudo ${lxc_cmd} which zypper &>/dev/null; then
|
|
eval sudo ${lxc_cmd} zypper lr -d > "${WORKING_DIR}/logs/suse-zypper-repolist-${1}.txt" || true
|
|
eval sudo ${lxc_cmd} zypper --disable-repositories pa -i > "${WORKING_DIR}/logs/suse-zypper-list-installed-${1}.txt" || true
|
|
|
|
# Ubuntu package debugging
|
|
elif eval sudo ${lxc_cmd} which apt-get &> /dev/null; then
|
|
eval sudo ${lxc_cmd} apt-cache policy | grep http | awk '{print $1" "$2" "$3}' | sort -u > "${WORKING_DIR}/logs/ubuntu-apt-repolist-${1}.txt" || true
|
|
eval sudo ${lxc_cmd} apt list --installed > "${WORKING_DIR}/logs/ubuntu-apt-list-installed-${1}.txt" || true
|
|
fi
|
|
}
|
|
|
|
function store_artifacts {
|
|
# Store known artifacts only if they exist. If the target directory does
|
|
# exist, it will be created.
|
|
# USAGE: store_artifacts /src/to/artifacts /path/to/store
|
|
if sudo test -e "${1}"; then
|
|
if [[ ! -d "${2}" ]]; then
|
|
mkdir -vp "${2}"
|
|
fi
|
|
echo "Running artifact sync for \"${1}\" to \"${2}\""
|
|
sudo ${RSYNC_CMD} ${1} ${2} || true
|
|
fi
|
|
}
|
|
|
|
function store_journal_artifacts {
|
|
# Store lines from a known unit's journal as a plain-text log file.
|
|
# USAGE: store_journal_artifacts UNIT_TO_MATCH /path/to/store
|
|
if [ $? == 0 ]; then
|
|
if [[ ! -d "${2}" ]]; then
|
|
mkdir -vp "${2}"
|
|
fi
|
|
if [[ ${3:-false} != false ]]; then
|
|
if [[ -f "/var/log/journal/${3}/system.journal" ]]; then
|
|
SYSTEMD_UNITS=$(sudo journalctl --file="/var/log/journal/${3}/system.journal" \
|
|
--output=json-pretty | grep -w UNIT | sort -u | awk -F'"' '{print $4}' | grep "${1}")
|
|
for service_unit in $(echo -e "${SYSTEMD_UNITS}"); do
|
|
echo "Pulling journal for ${service_unit}"
|
|
sudo journalctl --file="/var/log/journal/${3}/system.journal" \
|
|
--since="1 hour ago" \
|
|
--unit="${service_unit}" | sudo tee "${2}/${service_unit}.journal.log" &>/dev/null
|
|
done
|
|
fi
|
|
else
|
|
SYSTEMD_UNITS=$(sudo journalctl --output=json-pretty | grep -w UNIT | sort -u | awk -F'"' '{print $4}' | grep "${1}")
|
|
for service_unit in $(echo -e "${SYSTEMD_UNITS}"); do
|
|
echo "Pulling journal for ${service_unit}"
|
|
sudo journalctl --since="1 hour ago" \
|
|
--unit="${service_unit}" | sudo tee "${2}/${service_unit}.journal.log" &>/dev/null
|
|
done
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function find_files {
|
|
find "${WORKING_DIR}/logs/" -type f \
|
|
! -name "*.gz" \
|
|
! -name '*.html' \
|
|
! -name '*.subunit' \
|
|
! -name "*.journal" \
|
|
! -name 'ansible.sqlite' | grep -v 'stackviz'
|
|
}
|
|
|
|
function rename_files {
|
|
find_files |\
|
|
while read filename; do \
|
|
mv ${filename} ${filename}.txt || echo "WARNING: Could not rename ${filename}"; \
|
|
done
|
|
}
|
|
|
|
function compress_files {
|
|
# We use 'command' to ensure that we're not executing with an alias.
|
|
GZIP_CMD="command gzip --force --best"
|
|
find_files |\
|
|
while read filename; do \
|
|
${GZIP_CMD} ${filename} || echo "WARNING: Could not gzip ${filename}"; \
|
|
done
|
|
}
|
|
|
|
## Main ----------------------------------------------------------------------
|
|
|
|
echo "#### BEGIN LOG COLLECTION ###"
|
|
|
|
mkdir -vp "${WORKING_DIR}/logs"
|
|
|
|
# Gather basic logs
|
|
store_artifacts /openstack/log/ansible-logging/ "${WORKING_DIR}/logs/ansible"
|
|
store_artifacts /openstack/log/ "${WORKING_DIR}/logs/openstack"
|
|
store_artifacts /var/log/ "${WORKING_DIR}/logs/host"
|
|
|
|
# Store the ara sqlite database in the openstack-ci expected path
|
|
store_artifacts "${TESTING_HOME}/.ara/ansible.sqlite" "${WORKING_DIR}/logs/ara-report/"
|
|
|
|
# Gather host etc artifacts
|
|
for service in ${COMMON_ETC_LOG_NAMES}; do
|
|
store_artifacts "/etc/${service}" "${WORKING_DIR}/logs/etc/host/"
|
|
store_journal_artifacts "${service}" "${WORKING_DIR}/logs/host"
|
|
done
|
|
|
|
# Gather container etc artifacts
|
|
if which lxc-ls &> /dev/null; then
|
|
for CONTAINER_NAME in $(sudo lxc-ls -1); do
|
|
CONTAINER_PID=$(sudo lxc-info -p -n ${CONTAINER_NAME} | awk '{print $2}')
|
|
ETC_DIR="/proc/${CONTAINER_PID}/root/etc"
|
|
MACHINE_ID="$(sudo cat ${ETC_DIR}/machine-id)"
|
|
LOG_DIR="/proc/${CONTAINER_PID}/root/var/log"
|
|
repo_information ${CONTAINER_NAME}
|
|
for service in ${COMMON_ETC_LOG_NAMES}; do
|
|
store_artifacts ${ETC_DIR}/${service} "${WORKING_DIR}/logs/etc/openstack/${CONTAINER_NAME}/"
|
|
store_artifacts ${LOG_DIR}/${service} "${WORKING_DIR}/logs/openstack/${CONTAINER_NAME}/"
|
|
store_journal_artifacts ${service} "${WORKING_DIR}/logs/openstack/${CONTAINER_NAME}" "${MACHINE_ID}"
|
|
done
|
|
done
|
|
fi
|
|
|
|
# NOTE(mhayden): All of the files must be world-readable so that the log
|
|
# pickup jobs will work properly. Without this, you get a "File not found"
|
|
# when trying to read the files in the job results.
|
|
# NOTE(odyssey4me): Using '--chown $(whoami) --chmod=ugo+rX' in the rsync
|
|
# CMD to achieve this would be optimal, but the CentOS version of rsync
|
|
# (3.0.x) does not support that option.
|
|
sudo chmod -R ugo+rX "${WORKING_DIR}/logs/"
|
|
sudo chown -R $(whoami) "${WORKING_DIR}/logs/"
|
|
|
|
# Rename all files gathered to have a .txt suffix so that the compressed
|
|
# files are viewable via a web browser in OpenStack-CI.
|
|
rename_files
|
|
|
|
# Figure out the correct path for ARA
|
|
# As this script is not run through tox, and the tox envs are all
|
|
# different names, we need to try and find the right path to execute
|
|
# ARA from.
|
|
ARA_CMD="$(find ${WORKING_DIR}/.tox -path "*/bin/ara" -type f | head -n 1)"
|
|
|
|
# If we could not find ARA, assume it was not installed
|
|
# and skip all the related activities.
|
|
if [[ "${ARA_CMD}" != "" ]]; then
|
|
# Generate the ARA subunit report so that the
|
|
# results reflect in OpenStack-Health
|
|
mkdir -vp "${WORKING_DIR}/logs/ara-data"
|
|
echo "Generating ARA report subunit report."
|
|
${ARA_CMD} generate subunit "${WORKING_DIR}/logs/ara-data/testrepository.subunit" || true
|
|
fi
|
|
|
|
# Get a dmesg output so we can look for kernel failures
|
|
dmesg > "${WORKING_DIR}/logs/dmesg.log.txt" || true
|
|
|
|
# Collect job environment
|
|
env > "${WORKING_DIR}/logs/environment.txt" || true
|
|
|
|
# output ram usage
|
|
free -m > "${WORKING_DIR}/logs/memory-available.txt" || true
|
|
|
|
# iptables
|
|
sudo iptables -nvL > "${WORKING_DIR}/logs/iptables.txt" || true
|
|
sudo iptables -t nat -nvL > "${WORKING_DIR}/logs/iptables-nat.txt" || true
|
|
|
|
repo_information host
|
|
|
|
# Record the active interface configs
|
|
for interface in $(ip -o link | awk -F':' '{print $2}'); do
|
|
if which ethtool &> /dev/null; then
|
|
ethtool -k ${interface} > "${WORKING_DIR}/logs/ethtool-${interface}-cfg.txt" || true
|
|
else
|
|
echo "No ethtool available" | tee -a "${WORKING_DIR}/logs/ethtool-${interface}-cfg.txt"
|
|
fi
|
|
done
|
|
|
|
# Compress the files gathered so that they do not take up too much space.
|
|
compress_files
|
|
|
|
echo "#### END LOG COLLECTION ###"
|
|
|