#!/bin/bash # Copyright (C) 2011-2013 OpenStack Foundation # # 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. SUDO="sudo" # Distro check functions function is_fedora { # note we consider CentOS 7 as fedora for now lsb_release -i 2>/dev/null | grep -iq "fedora" || \ lsb_release -i 2>/dev/null | grep -iq "CentOS" } function is_ubuntu { lsb_release -i 2>/dev/null | grep -iq "ubuntu" } function is_debian { # do not rely on lsb_release because it may be not installed by default cat /etc/*-release | grep ID 2>/dev/null | grep -iq "debian" } function uses_debs { # check if apt-get is installed, valid for debian based type "apt-get" 2>/dev/null } function function_exists { type $1 2>/dev/null | grep -q 'is a function' } function apt_get_install { # fetch the updates in a loop to ensure that we're update to # date. Only do this once per run. Give up to 5 minutes to succeed # here. if [[ -z "$APT_UPDATED" ]]; then if ! timeout 300 sh -c "while ! sudo apt-get update; do sleep 30; done"; then echo "Failed to update apt repos, we're dead now" exit 1 fi APT_UPDATED=1 fi sudo apt-get --assume-yes install $@ } function call_hook_if_defined { local hook_name=$1 local filename=${2-$WORKSPACE/devstack-gate-$hook_name.txt} local save_dir=${3-$BASE/logs/} if function_exists $hook_name; then echo "Running $hook_name" xtrace=$(set +o | grep xtrace) set -o xtrace -o pipefail tsfilter $hook_name | tee $filename local ret_val=$? $SUDO mv $filename $save_dir set +o pipefail $xtrace return $ret_val fi } # awk filter to timestamp the stream, including stderr merging function tsfilter { $@ 2>&1 | awk ' { cmd ="date +\"%Y-%m-%d %H:%M:%S.%3N | \"" cmd | getline now close("date +\"%Y-%m-%d %H:%M:%S.%3N | \"") sub(/^/, now) print fflush() }' # make sure we return the command status, not the awk status return ${PIPESTATUS[0]} } function _ping_check { local host=$1 local times=${2:-20} echo "Testing ICMP connectivit to $host" ping -c $times $host } function _http_check { local url=$1 local dl='wget --progress=bar -O /dev/null' if [[ `which curl` ]]; then dl='curl -# -o /dev/null' fi # do a pypi http fetch, to make sure that we're good for i in `seq 1 10`; do echo "HTTP check of $url - attempt #$i" $dl $url || /bin/true done } # do a few network tests to baseline how bad we are function network_sanity_check { echo "Performing network sanity check..." PIP_CONFIG_FILE=/etc/pip.conf if [[ -f $PIP_CONFIG_FILE ]]; then line=$(cat $PIP_CONFIG_FILE|grep index-url) pypi_url=${line#*=} pypi_host=$(echo $pypi_url|grep -Po '.*?//\K.*?(?=/)') _ping_check $pypi_host _http_check $pypi_url fi # rax ubuntu mirror _ping_check mirror.rackspace.com _http_check http://mirror.rackspace.com/ubuntu/dists/trusty/Release.gpg } # create the start timer for when the job began function start_timer { # first make sure the time is right, so we don't go into crazy land # later if the system decides to apply an ntp date and we jump forward # 4 hrs (which has happened) if is_fedora; then local ntp_service='ntpd' elif uses_debs; then local ntp_service='ntp' else echo "Unsupported platform, can't determine ntp service" exit 1 fi local default_ntp_server=$( grep ^server /etc/ntp.conf | head -1 | awk '{print $2}') local ntp_server=${NTP_SERVER:-$default_ntp_server} sudo service $ntp_service stop sudo /usr/sbin/ntpdate $ntp_server sudo service $ntp_service start sleep 1 START_TIME=`date +%s` } function remaining_time { local now=`date +%s` local elapsed=$(((now - START_TIME) / 60)) REMAINING_TIME=$((DEVSTACK_GATE_TIMEOUT - elapsed - 5)) echo "Job timeout set to: $REMAINING_TIME minutes" if [ ${REMAINING_TIME} -le 0 ]; then echo "Already timed out." exit 1 fi } # indent the output of a command 4 spaces, useful for distinguishing # the output of a command from the command itself function indent { $@ | (while read; do echo " $REPLY"; done) } # Attempt to fetch a git ref for a project, if that ref is not empty function git_fetch_at_ref { local project=$1 local ref=$2 if [ "$ref" != "" ]; then git fetch $ZUUL_URL/$project $ref return $? else # return failing return 1 fi } function git_checkout { local project=$1 local branch=$2 local reset_branch=$branch if [[ "$branch" != "FETCH_HEAD" ]]; then reset_branch="remotes/origin/$branch" fi git checkout $branch git reset --hard $reset_branch if ! git clean -x -f -d -q ; then sleep 1 git clean -x -f -d -q fi } function git_has_branch { local project=$1 # Project is here for test mocks local branch=$2 if git branch -a |grep remotes/origin/$branch>/dev/null; then return 0 else return 1 fi } function git_prune { git_timed remote prune origin } function git_remote_update { git_timed remote update } # git can sometimes get itself infinitely stuck with transient network # errors or other issues with the remote end. This wraps git in a # timeout/retry loop and is intended to watch over non-local git # processes that might hang. Run for up to 5 minutes before killing. # If first SIGTERM does not kill the process wait a minute then SIGKILL. # If the git operation fails try again for up to a total of 3 attempts. # usage: git_timed function git_timed { local max_attempts=3 local count=0 until timeout -k 1m 5m git "$@"; do count=$(($count + 1)) echo "git $@ failed." if [ $count -eq $max_attempts ]; then echo "Max attempts reached for git $@; giving up." exit 1 fi local sleep_time=$((30 + $RANDOM % 60)) echo "sleep $sleep_time before retrying." sleep $sleep_time done } function git_remote_set_url { git remote set-url $1 $2 } function git_clone_and_cd { local project=$1 local short_project=$2 local git_base=${GIT_BASE:-https://git.openstack.org} if [[ ! -e $short_project ]]; then echo " Need to clone $short_project" git clone $git_base/$project fi cd $short_project } function fix_etc_hosts { # HPcloud stopped adding the hostname to /etc/hosts with their # precise images. HOSTNAME=`/bin/hostname` if ! grep $HOSTNAME /etc/hosts >/dev/null; then echo "Need to add hostname to /etc/hosts" sudo bash -c 'echo "127.0.1.1 $HOSTNAME" >>/etc/hosts' fi } function fix_disk_layout { # HPCloud and Rackspace performance nodes provide no swap, but do # have ephemeral disks we can use. HPCloud also doesn't have # enough space on / for two devstack installs, so we partition the # disk and mount it on /opt, syncing the previous contents of /opt # over. if [ `grep SwapTotal /proc/meminfo | awk '{ print $2; }'` -eq 0 ]; then if [ -b /dev/xvde ]; then DEV='/dev/xvde' else EPHEMERAL_DEV=$(blkid -L ephemeral0 || true) if [ -n "$EPHEMERAL_DEV" -a -b "$EPHEMERAL_DEV" ]; then DEV=$EPHEMERAL_DEV fi fi if [ -n "$DEV" ]; then local swap=${DEV}1 local lvmvol=${DEV}2 local optdev=${DEV}3 if mount | grep ${DEV} > /dev/null; then echo "*** ${DEV} appears to already be mounted" echo "*** ${DEV} unmounting and reformating" sudo umount ${DEV} fi sudo parted ${DEV} --script -- mklabel msdos sudo parted ${DEV} --script -- mkpart primary linux-swap 1 8192 sudo parted ${DEV} --script -- mkpart primary ext2 8192 32768 sudo parted ${DEV} --script -- mkpart primary ext2 32768 -1 sudo mkswap $swap sudo vgcreate stack-volumes-lvmdriver-1 $lvmvol sudo mkfs.ext4 $optdev sudo swapon $swap sudo mount $optdev /mnt sudo find /opt/ -mindepth 1 -maxdepth 1 -exec mv {} /mnt/ \; sudo umount /mnt sudo mount $optdev /opt fi fi # dump vm settings for reference (Ubuntu 12 era procps can get # confused with certain proc trigger nodes that are write-only and # return a EPERM; ignore this) sudo sysctl vm || true # ensure a standard level of swappiness. Some platforms # (rax+centos7) come with swappiness of 0 (presumably because the # vm doesn't come with swap setup ... but we just did that above), # which depending on the kernel version can lead to the OOM killer # kicking in on some processes despite swap being available; # particularly things like mysql which have very high ratio of # anonymous-memory to file-backed mappings. # make sure reload of sysctl doesn't reset this sudo sed -i '/vm.swappiness/d' /etc/sysctl.conf # This sets swappiness low; we really don't want to be relying on # cloud I/O based swap during our runs sudo sysctl -w vm.swappiness=10 } # Set up a project in accordance with the future state proposed by # Zuul. # # Arguments: # project: The full name of the project to set up # branch: The branch to check out # # The branch argument should be the desired branch to check out. If # you have no other opinions, then you should supply ZUUL_BRANCH here. # This is generally the branch corresponding with the change being # tested. # # If you would like to check out a branch other than what ZUUL has # selected, for example in order to check out the old or new branches # for grenade, or an alternate branch to test client library # compatibility, then supply that as the argument instead. This # function will try to check out the following (in order): # # The zuul ref for the project specific OVERRIDE_$PROJECT_PROJECT_BRANCH if specified # The zuul ref for the indicated branch # The zuul ref for the master branch # The tip of the project specific OVERRIDE_$PROJECT_PROJECT_BRANCH if specified # The tip of the indicated branch # The tip of the master branch # function setup_project { local project=$1 local branch=$2 local short_project=`basename $project` local git_base=${GIT_BASE:-https://git.openstack.org} echo "Setting up $project @ $branch" git_clone_and_cd $project $short_project git_remote_set_url origin $git_base/$project # allow for possible project branch override local uc_project=`echo $short_project | tr [:lower:] [:upper:] | tr '-' '_' | sed 's/[^A-Z_]//'` local project_branch_var="\$OVERRIDE_${uc_project}_PROJECT_BRANCH" local project_branch=`eval echo ${project_branch_var}` if [[ "$project_branch" != "" ]]; then branch=$project_branch fi # Try the specified branch before the ZUUL_BRANCH. if [[ ! -z $ZUUL_BRANCH ]]; then OVERRIDE_ZUUL_REF=$(echo $ZUUL_REF | sed -e "s,$ZUUL_BRANCH,$branch,") else OVERRIDE_ZUUL_REF="" fi # Update git remotes git_remote_update # Ensure that we don't have stale remotes around git_prune # See if this project has this branch, if not, use master FALLBACK_ZUUL_REF="" if ! git_has_branch $project $branch; then FALLBACK_ZUUL_REF=$(echo $ZUUL_REF | sed -e "s,$branch,master,") fi # See if Zuul prepared a ref for this project if git_fetch_at_ref $project $OVERRIDE_ZUUL_REF || \ git_fetch_at_ref $project $FALLBACK_ZUUL_REF; then # It's there, so check it out. git_checkout $project FETCH_HEAD else if git_has_branch $project $branch; then git_checkout $project $branch else git_checkout $project master fi fi } function re_exec_devstack_gate { export RE_EXEC="true" echo "This build includes a change to devstack-gate; re-execing this script." exec $WORKSPACE/devstack-gate/devstack-vm-gate-wrap.sh } function setup_workspace { local base_branch=$1 local DEST=$2 local copy_cache=$3 local xtrace=$(set +o | grep xtrace) # Enabled detailed logging, since output of this function is redirected set -o xtrace if [ -z "$base_branch" ]; then echo "ERROR: setup_workspace: base_branch is an empty string!" >&2 return 1 fi fix_disk_layout sudo mkdir -p $DEST sudo chown -R jenkins:jenkins $DEST #TODO(jeblair): remove when this is no longer created by the image rm -fr ~/workspace-cache/ # The vm template update job should cache the git repos # Move them to where we expect: echo "Using branch: $base_branch" for PROJECT in $PROJECTS; do cd $DEST if [ -d /opt/git/$PROJECT ]; then # Start with a cached git repo if possible rsync -a /opt/git/${PROJECT}/ `basename $PROJECT` fi setup_project $PROJECT $base_branch done # It's important we are back at DEST for the rest of the script cd $DEST if [ -n "$copy_cache" ] ; then # The vm template update job should cache some images in ~/cache. # Move them to where devstack expects: find ~/cache/files/ -mindepth 1 -maxdepth 1 -exec cp {} $DEST/devstack/files/ \; else # The vm template update job should cache some images in ~/cache. # Move them to where devstack expects: find ~/cache/files/ -mindepth 1 -maxdepth 1 -exec mv {} $DEST/devstack/files/ \; fi # Disable detailed logging as we return to the main script $xtrace } function copy_mirror_config { # The pydistutils.cfg file is added by Puppet. Some CIs may not rely on # Puppet to do the base node installation if [ -f ~/.pydistutils.cfg ]; then sudo install -D -m0644 -o root -g root ~/.pydistutils.cfg ~root/.pydistutils.cfg sudo install -D -m0644 -o stack -g stack ~/.pydistutils.cfg ~stack/.pydistutils.cfg sudo install -D -m0644 -o tempest -g tempest ~/.pydistutils.cfg ~tempest/.pydistutils.cfg fi } function setup_host { # Enabled detailed logging, since output of this function is redirected local xtrace=$(set +o | grep xtrace) set -o xtrace echo "What's our kernel?" uname -a # capture # of cpus echo "NProc has discovered $(nproc) CPUs" cat /proc/cpuinfo # This is necessary to keep sudo from complaining fix_etc_hosts # We set some home directories under $BASE, make sure it exists. sudo mkdir -p $BASE # Start with a fresh syslog if uses_debs; then sudo stop rsyslog sudo mv /var/log/syslog /var/log/syslog-pre-devstack sudo mv /var/log/kern.log /var/log/kern_log-pre-devstack sudo touch /var/log/syslog sudo chown /var/log/syslog --ref /var/log/syslog-pre-devstack sudo chmod /var/log/syslog --ref /var/log/syslog-pre-devstack sudo chmod a+r /var/log/syslog sudo touch /var/log/kern.log sudo chown /var/log/kern.log --ref /var/log/kern_log-pre-devstack sudo chmod /var/log/kern.log --ref /var/log/kern_log-pre-devstack sudo chmod a+r /var/log/kern.log sudo start rsyslog elif is_fedora; then # save timestamp and use journalctl to dump everything since # then at the end date +"%Y-%m-%d %H:%M:%S" | sudo tee $BASE/log-start-timestamp.txt fi # Create a stack user for devstack to run as, so that we can # revoke sudo permissions from that user when appropriate. sudo useradd -U -s /bin/bash -d $BASE/new -m stack # Use 755 mode on the user dir regarless to the /etc/login.defs setting sudo chmod 755 $BASE/new TEMPFILE=`mktemp` echo "stack ALL=(root) NOPASSWD:ALL" >$TEMPFILE chmod 0440 $TEMPFILE sudo chown root:root $TEMPFILE sudo mv $TEMPFILE /etc/sudoers.d/50_stack_sh # Create user's ~/.cache directory with proper permissions, ensuring later # 'sudo pip install's do not create it owned by root. sudo mkdir -p $BASE/new/.cache sudo chown -R stack:stack $BASE/new/.cache # Create a tempest user for tempest to run as, so that we can # revoke sudo permissions from that user when appropriate. # NOTE(sdague): we should try to get the state dump to be a # neutron API call in Icehouse to remove this. sudo useradd -U -s /bin/bash -m tempest TEMPFILE=`mktemp` echo "tempest ALL=(root) NOPASSWD:/sbin/ip" >$TEMPFILE echo "tempest ALL=(root) NOPASSWD:/sbin/iptables" >>$TEMPFILE echo "tempest ALL=(root) NOPASSWD:/usr/bin/ovsdb-client" >>$TEMPFILE chmod 0440 $TEMPFILE sudo chown root:root $TEMPFILE sudo mv $TEMPFILE /etc/sudoers.d/51_tempest_sh # Future useradd calls should strongly consider also updating # ~/.pydisutils.cfg in the copy_mirror_config # function if tox/pip will be used at all. # If we will be testing OpenVZ, make sure stack is a member of the vz group if [ "$DEVSTACK_GATE_VIRT_DRIVER" == "openvz" ]; then sudo usermod -a -G vz stack fi # Ensure that all of the users have the openstack mirror config copy_mirror_config # perform network sanity check so that we can characterize the # state of the world network_sanity_check # Disable detailed logging as we return to the main script $xtrace } function archive_test_artifact { local filename=$1 sudo gzip -9 $filename sudo chown jenkins:jenkins $filename.gz sudo chmod a+r $filename.gz } function process_testr_artifacts { local project=$1 local path_prefix=${2:-new} local project_path=$BASE/$path_prefix/$project local repo_path=$project_path/.testrepository local log_path=$BASE/logs if [[ "$path_prefix" != "new" ]]; then log_path=$BASE/logs/$path_prefix fi # Check for an interrupted run first because 0 will always exist if [ -f $repo_path/tmp* ]; then # If testr timed out, collect temp file from testr sudo cp $repo_path/tmp* $log_path/testrepository.subunit archive_test_artifact $log_path/testrepository.subunit elif [ -f $repo_path/0 ]; then pushd $project_path sudo testr last --subunit > $WORKSPACE/testrepository.subunit popd sudo mv $WORKSPACE/testrepository.subunit \ $log_path/testrepository.subunit sudo python /usr/local/jenkins/slave_scripts/subunit2html.py \ $log_path/testrepository.subunit $log_path/testr_results.html archive_test_artifact $log_path/testrepository.subunit archive_test_artifact $log_path/testr_results.html fi } function cleanup_host { # TODO: clean this up to be errexit clean local errexit=$(set +o | grep errexit) set +o errexit # Enabled detailed logging, since output of this function is redirected local xtrace=$(set +o | grep xtrace) set -o xtrace cd $WORKSPACE # Sleep to give services a chance to flush their log buffers. sleep 2 # No matter what, archive logs and config files if uses_debs; then sudo cp /var/log/syslog $BASE/logs/syslog.txt sudo cp /var/log/kern.log $BASE/logs/kern_log.txt elif is_fedora; then # the journal gives us syslog() and kernel output, so is like # a concatenation of the above. sudo journalctl --no-pager \ --since="$(cat $BASE/log-start-timestamp.txt)" \ | sudo tee $BASE/logs/syslog.txt > /dev/null fi # apache logs; including wsgi stuff like horizon, keystone, etc. if uses_debs; then local apache_logs=/var/log/apache2 elif is_fedora; then local apache_logs=/var/log/httpd fi sudo cp -r ${apache_logs} $BASE/logs/apache # rabbitmq logs if [ -d /var/log/rabbitmq ]; then sudo cp -r /var/log/rabbitmq $BASE/logs fi # db logs if [ -d /var/log/postgresql ] ; then # Rename log so it doesn't have an additional '.' so it won't get # deleted sudo cp /var/log/postgresql/*log $BASE/logs/postgres.log fi if [ -f /var/log/mysql.err ] ; then sudo cp /var/log/mysql.err $BASE/logs/mysql_err.log fi if [ -f /var/log/mysql.log ] ; then sudo cp /var/log/mysql.log $BASE/logs/ fi # libvirt if [ -d /var/log/libvirt ] ; then sudo cp -r /var/log/libvirt $BASE/logs/ fi # sudo config sudo cp -r /etc/sudoers.d $BASE/logs/ sudo cp /etc/sudoers $BASE/logs/sudoers.txt # Archive config files sudo mkdir $BASE/logs/etc/ for PROJECT in $PROJECTS; do proj=`basename $PROJECT` if [ -d /etc/$proj ]; then sudo cp -r /etc/$proj $BASE/logs/etc/ fi done # Archive Apache config files sudo mkdir $BASE/logs/apache_config if uses_debs; then if [[ -d /etc/apache2/sites-enabled ]]; then sudo cp /etc/apache2/sites-enabled/* $BASE/logs/apache_config fi elif is_fedora; then if [[ -d /etc/apache2/httpd/conf.d ]]; then sudo cp /etc/httpd/conf.d/* $BASE/logs/apache_config fi fi # copy devstack log files if [ -d $BASE/old ]; then sudo mkdir -p $BASE/logs/old $BASE/logs/new # copy all log files, but note that devstack creates a shortened # symlink without timestamp (foo.log -> foo.2014-01-01-000000.log) # for each log to latest log. Thus we just copy the symlinks to # avoid excessively long file-names. find $BASE/old/screen-logs -type l -print0 | \ xargs -0 -I {} sudo cp {} $BASE/logs/old sudo cp $BASE/old/devstacklog.txt $BASE/logs/old/ sudo cp $BASE/old/devstack/localrc $BASE/logs/old/localrc.txt sudo cp $BASE/old/tempest/etc/tempest.conf $BASE/logs/old/tempest_conf.txt if -f [ $BASE/old/devstack/tempest.log ] ; then sudo cp $BASE/old/devstack/tempest.log $BASE/logs/old/verify_tempest_conf.log fi # grenade logs sudo cp $BASE/new/grenade/localrc $BASE/logs/grenade_localrc.txt # grenade pluginrc - external grenade plugins use this file to # communicate with grenade, capture for posterity if -f [ $BASE/new/grenade/pluginrc ]; then sudo cp $BASE/new/grenade/pluginrc $BASE/logs/grenade_pluginrc.txt fi # grenade logs directly and uses similar timestampped files to # devstack. So temporarily copy out & rename the latest log # files from the short-symlinks into grenade/, clean-up left # over time-stampped files and put the interesting logs back at # top-level for easy access sudo mkdir -p $BASE/logs/grenade sudo cp $BASE/logs/grenade.sh.log $BASE/logs/grenade/ sudo cp $BASE/logs/grenade.sh.log.summary \ $BASE/logs/grenade/grenade.sh.summary.log sudo rm $BASE/logs/grenade.sh.* sudo mv $BASE/logs/grenade/*.log $BASE/logs sudo rm -rf $BASE/logs/grenade if [ -f $BASE/new/grenade/javelin.log ] ; then sudo cp $BASE/new/grenade/javelin.log $BASE/logs/javelin.log fi NEWLOGTARGET=$BASE/logs/new else NEWLOGTARGET=$BASE/logs fi find $BASE/new/screen-logs -type l -print0 | \ xargs -0 -I {} sudo cp {} $NEWLOGTARGET/ sudo cp $BASE/new/devstacklog.txt $NEWLOGTARGET/ sudo cp $BASE/new/devstack/localrc $NEWLOGTARGET/localrc.txt if [ -f $BASE/new/devstack/tempest.log ]; then sudo cp $BASE/new/devstack/tempest.log $NEWLOGTARGET/verify_tempest_conf.log fi # Copy failure files if they exist if [ $(ls $BASE/status/stack/*.failure | wc -l) -gt 0 ]; then sudo mkdir -p $BASE/logs/status sudo cp $BASE/status/stack/*.failure $BASE/logs/status/ fi # Copy Ironic nodes console logs if they exist if [ -d $BASE/new/ironic-bm-logs ] ; then sudo mkdir -p $BASE/logs/ironic-bm-logs sudo cp $BASE/new/ironic-bm-logs/*.log $BASE/logs/ironic-bm-logs/ fi # Copy tempest config file sudo cp $BASE/new/tempest/etc/tempest.conf $NEWLOGTARGET/tempest_conf.txt sudo iptables-save > $WORKSPACE/iptables.txt df -h > $WORKSPACE/df.txt pip freeze > $WORKSPACE/pip-freeze.txt sudo mv $WORKSPACE/iptables.txt $WORKSPACE/df.txt \ $WORKSPACE/pip-freeze.txt $BASE/logs/ if [ `command -v dpkg` ]; then dpkg -l> $WORKSPACE/dpkg-l.txt gzip -9 dpkg-l.txt sudo mv $WORKSPACE/dpkg-l.txt.gz $BASE/logs/ fi if [ `command -v rpm` ]; then rpm -qa > $WORKSPACE/rpm-qa.txt gzip -9 rpm-qa.txt sudo mv $WORKSPACE/rpm-qa.txt.gz $BASE/logs/ fi process_testr_artifacts tempest process_testr_artifacts tempest old if [ -f $BASE/new/tempest/tempest.log ] ; then sudo cp $BASE/new/tempest/tempest.log $BASE/logs/tempest.log fi if [ -f $BASE/old/tempest/tempest.log ] ; then sudo cp $BASE/old/tempest/tempest.log $BASE/logs/old/tempest.log fi # ceph logs and config if [ -d /var/log/ceph ] ; then sudo cp -r /var/log/ceph $BASE/logs/ fi if [ -f /etc/ceph/ceph.conf ] ; then sudo cp /etc/ceph/ceph.conf $BASE/logs/ceph_conf.txt fi if [ -d /var/log/openvswitch ] ; then sudo cp -r /var/log/openvswitch $BASE/logs/ fi # Make sure jenkins can read all the logs and configs sudo chown -R jenkins:jenkins $BASE/logs/ sudo chmod a+r $BASE/logs/ $BASE/logs/etc # rename files to .txt; this is so that when displayed via # logs.openstack.org clicking results in the browser shows the # files, rather than trying to send it to another app or make you # download it, etc. # firstly, rename all .log files to .txt files for f in $(find $BASE/logs -name "*.log"); do sudo mv $f ${f/.log/.txt} done #rename all failure files to have .txt for f in $(find $BASE/logs/status -name "*.failure"); do sudo mv $f ${f/.failure/.txt} done # append .txt to all config files # (there are some /etc/swift .builder and .ring files that get # caught up which aren't really text, don't worry about that) find $BASE/logs/sudoers.d $BASE/logs/etc -type f -exec mv '{}' '{}'.txt \; # rabbitmq if [ -f $BASE/logs/rabbitmq/ ]; then find $BASE/logs/rabbitmq -type f -exec mv '{}' '{}'.txt \; for X in `find $BASE/logs/rabbitmq -type f` ; do mv "$X" "${X/@/_at_}" done fi # glusterfs logs and config if [ -d /var/log/glusterfs ] ; then sudo cp -r /var/log/glusterfs $BASE/logs/ fi if [ -f /etc/glusterfs/glusterd.vol ] ; then sudo cp /etc/glusterfs/glusterd.vol $BASE/logs/ fi # final memory usage and process list ps -eo user,pid,ppid,lwp,%cpu,%mem,size,rss,cmd > $BASE/logs/ps.txt # Compress all text logs sudo find $BASE/logs -iname '*.txt' -execdir gzip -9 {} \+ sudo find $BASE/logs -iname '*.dat' -execdir gzip -9 {} \+ sudo find $BASE/logs -iname '*.conf' -execdir gzip -9 {} \+ # Disable detailed logging as we return to the main script $xtrace $errexit } function remote_command { local ssh_opts="-tt -o PasswordAuthentication=no -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ConnectionAttempts=4" local dest_host=$1 shift ssh $ssh_opts $dest_host "$@" } function remote_copy_dir { local dest_host=$1 local src_dir=$2 local dest_dir=$3 remote_command "$dest_host" mkdir -p "$dest_dir" rsync -avz "$src_dir" "${dest_host}:$dest_dir" } function remote_copy_file { local ssh_opts="-o PasswordAuthentication=no -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ConnectionAttempts=4" local src=$1 local dest=$2 shift scp $ssh_opts "$src" "$dest" } # enable_netconsole function enable_netconsole { # do nothing if not set if [[ $DEVSTACK_GATE_NETCONSOLE = "" ]]; then return fi local remote_ip=$(echo $DEVSTACK_GATE_NETCONSOLE | awk -F: -e '{print $1}') local remote_port=$(echo $DEVSTACK_GATE_NETCONSOLE | awk -F: -e '{print $2}') # netconsole requires the device to send and the destitation MAC, # which is obviously on the same subnet. The way to get packets # out to the world is specify the default gw as the remote # destination. local default_gw=$(ip route | grep default | awk '{print $3}') local gw_mac=$(arp $default_gw | grep $default_gw | awk '{print $3}') local gw_dev=$(ip route | grep default | awk '{print $5}') # turn up message output sudo dmesg -n 8 sudo modprobe configfs sudo modprobe netconsole sudo mount none -t configfs /sys/kernel/config sudo mkdir /sys/kernel/config/netconsole/target1 pushd /sys/kernel/config/netconsole/target1 echo "$gw_dev" | sudo tee ./dev_name echo "$remote_ip" | sudo tee ./remote_ip echo "$gw_mac" | sudo tee ./remote_mac echo "$remote_port" | sudo tee ./remote_port echo 1 | sudo tee ./enabled popd } # This function creates an internal gre bridge to connect all external # network bridges across the compute and network nodes. # bridge_name: Bridge name on each host for logical l2 network # connectivity. # host_ip: ip address of the bridge host which is reachable for all peer # the hub for all of our spokes. # set_ips: Whether or not to set l3 addresses on our logical l2 network. # This can be helpful for setting up routing tables. # offset: starting value for gre tunnel key and the ip addr suffix # The next two parameters are only used if set_ips is "True". # pub_addr_prefix: The IPv4 address three octet prefix used to give compute # nodes non conflicting addresses on the pub_if_name'd # network. Should be provided as X.Y.Z. Offset will be # applied to this as well as the below mask to get the # resulting address. # pub_addr_mask: the CIDR mask less the '/' for the IPv4 addresses used # above. # every additional parameter is considered as a peer host (spokes) # # For OVS troubleshooting needs: # http://www.yet.org/2014/09/openvswitch-troubleshooting/ # function ovs_gre_bridge { local install_ovs_deps="source $BASE/new/devstack/functions-common; \ install_package openvswitch-switch; \ restart_service openvswitch-switch" local mtu=1450 local bridge_name=$1 local host_ip=$2 local set_ips=$3 local offset=$4 if [[ "$set_ips" == "True" ]] ; then local pub_addr_prefix=$5 local pub_addr_mask=$6 shift 6 else shift 4 fi local peer_ips=$@ eval $install_ovs_deps # create a bridge, just like you would with 'brctl addbr' # if the bridge exists, --may-exist prevents ovs from returning an error sudo ovs-vsctl --may-exist add-br $bridge_name # as for the mtu, look for notes on lp#1301958 in devstack-vm-gate.sh sudo ip link set mtu $mtu dev $bridge_name if [[ "$set_ips" == "True" ]] ; then sudo ip addr add ${pub_addr_prefix}.${offset}/${pub_addr_mask} dev ${bridge_name} fi for node_ip in $peer_ips; do (( offset++ )) # For reference on how to setup a tunnel using OVS see: # http://openvswitch.org/support/config-cookbooks/port-tunneling/ # The command below is equivalent to the sequence of ip/brctl commands # where an interface of gre type is created first, and then plugged into # the bridge; options are command specific configuration key-value pairs. # # Create the gre tunnel for the Controller/Network Node: # This establishes a tunnel between remote $node_ip to local $host_ip # uniquely identified by a key $offset sudo ovs-vsctl add-port $bridge_name \ ${bridge_name}_${node_ip} \ -- set interface ${bridge_name}_${node_ip} type=gre \ options:remote_ip=${node_ip} \ options:key=${offset} \ options:local_ip=${host_ip} # Now complete the gre tunnel setup for the Compute Node: # Similarly this establishes the tunnel in the reverse direction remote_command $node_ip "$install_ovs_deps" remote_command $node_ip sudo ovs-vsctl --may-exist add-br $bridge_name remote_command $node_ip sudo ip link set mtu $mtu dev $bridge_name remote_command $node_ip sudo ovs-vsctl add-port $bridge_name \ ${bridge_name}_${host_ip} \ -- set interface ${bridge_name}_${host_ip} type=gre \ options:remote_ip=${host_ip} \ options:key=${offset} \ options:local_ip=${node_ip} if [[ "$set_ips" == "True" ]] ; then remote_command $node_ip \ sudo ip addr add ${pub_addr_prefix}.${offset}/${pub_addr_mask} \ dev ${bridge_name} fi done }