training-guides/labs/lib/osbash/functions.host
Roger Luethi cf0aa13715 labs: force LC_ALL=C for ssh
Mac OS X exports LC_CTYPE=UTF-8 to our ssh environment which makes the
keystone install fail (results in a Python traceback complaining about
"unknown locale: UTF-8").

This patch uses LC_ALL=C to override all locale settings.

The previous, limited work-arounds for neutron are no longer needed and
removed.

Change-Id: Ic7a2f5547fc4bd5d512da5197e48366c83c21c24
2014-12-22 15:17:41 +01:00

433 lines
12 KiB
Bash

# This file contains bash functions that are used by osbash on the host.
source "$LIB_DIR/functions"
#-------------------------------------------------------------------------------
# Conditional execution
#-------------------------------------------------------------------------------
# TODO: Create a help function and display it under help by default or with
# option --help (-h).
# exec_cmd is used for conditional execution:
#
# OSBASH=exec_cmd
#
# Execute command only if OSBASH is set:
# ${OSBASH:-:} cmd args
#
# Execute command only if OSBASH is not set:
# ${OSBASH:+:} cmd args
#
# Disable actual call to VBoxManage (selectively override configuration):
# OSBASH= cmd args
#
# Enable call to VBoxManage (selectively override configuration):
# OSBASH=exec_cmd cmd args
function exec_cmd {
local cmd=$1
shift
$cmd "$@"
}
#-------------------------------------------------------------------------------
function get_base_disk_name {
echo "base-$VM_ACCESS-$DISTRO.vdi"
}
function get_base_disk_path {
echo "$DISK_DIR/$(get_base_disk_name)"
}
#-------------------------------------------------------------------------------
# ssh
#-------------------------------------------------------------------------------
# Download Vagrant insecure private key if necessary
function check_vagrant_private_key {
local key_name="vagrant"
local key_url=https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/$key_name
local vagrant_key_dir=$LIB_DIR/vagrant-ssh-keys
local vagrant_key_path=$vagrant_key_dir/$key_name
if [ ! -f "$vagrant_key_path" ]; then
download "$key_url" "$vagrant_key_dir" $key_name
fi
if ! ls -l "$vagrant_key_path"|grep -q "^-r--------"; then
echo "Adjusting permissions for $vagrant_key_path"
chmod 400 "$vagrant_key_path"
fi
}
function strip_top_dir {
local full_path=$1
echo "${full_path/$TOP_DIR\//}"
}
# Copy files or directories to VM (incl. implied directories; HOME is TOP_DIR)
function vm_scp_to_vm {
local ssh_port=$1
shift
check_vagrant_private_key
while (($#)); do
local src_path=$1
shift
local target_path=$(strip_top_dir "$src_path")
local target_dir=$(dirname "$target_path")
vm_ssh "$ssh_port" "mkdir -p $target_dir"
scp -q -r \
-i "$LIB_DIR/vagrant-ssh-keys/vagrant" \
-o "UserKnownHostsFile /dev/null" \
-o "StrictHostKeyChecking no" \
-P "$ssh_port" \
"$src_path" "$VM_SHELL_USER@localhost:$target_path"
done
}
# Execute commands via ssh
function vm_ssh {
local ssh_port=$1
shift
check_vagrant_private_key
# Some operating systems (e.g., Mac OS X) export locale settings to the
# target that cause some Python clients to fail. Override with a standard
# setting (LC_ALL=C).
LC_ALL=C ssh -q \
-i "$LIB_DIR/vagrant-ssh-keys/vagrant" \
-o "UserKnownHostsFile /dev/null" \
-o "StrictHostKeyChecking no" \
-p "$ssh_port" \
"$VM_SHELL_USER@localhost" "$@"
}
function wait_for_ssh {
local ssh_port=$1
echo -n "Waiting for ssh server to respond on local port $ssh_port."
while [ : ]; do
if vm_ssh "$ssh_port" exit ; then
break
else
echo -n .
sleep 1
fi
done
echo
}
# Copy one script to VM and execute it via ssh; log output to separate file
function ssh_exec_script {
local ssh_port=$1
local script_path=$2
vm_scp_to_vm "$ssh_port" "$script_path"
local remote_path=$(strip_top_dir "$script_path")
echo -en "\n$(date) start $remote_path"
local script_name="$(basename "$script_path" .sh)"
local prefix=$(get_next_prefix "$LOG_DIR" "auto")
local log_path=$LOG_DIR/${prefix}_${script_name}.auto
local rc=0
vm_ssh "$ssh_port" "bash $remote_path && rm -vf $remote_path" \
> "$log_path" 2>&1 || rc=$?
if [ $rc -ne 0 ]; then
echo >&2
echo "ERROR: ssh returned status $rc for $remote_path" |
tee >&2 -a "$LOG_DIR/error.log"
# kill osbash host scripts
kill -- -$$
fi
echo -en "\n$(date) done"
}
# Wait for sshd, prepare autostart dirs, and execute autostart scripts on VM
function ssh_process_autostart {
local ssh_port=$1
wait_for_ssh "$ssh_port"
vm_ssh "$ssh_port" "rm -rf lib config autostart"
vm_scp_to_vm "$ssh_port" "$TOP_DIR/lib" "$TOP_DIR/config"
local script_path=""
for script_path in "$AUTOSTART_DIR/"*.sh; do
ssh_exec_script "$ssh_port" "$script_path"
rm -f "$script_path" >&2
done
touch "$STATUS_DIR/done"
}
#-------------------------------------------------------------------------------
# Autostart mechanism
#-------------------------------------------------------------------------------
function autostart_reset {
clean_dir "$AUTOSTART_DIR"
clean_dir "$STATUS_DIR"
}
function process_begin_files {
local processing=("$STATUS_DIR"/*.sh.begin)
if [ -n "${processing[0]-}" ]; then
local file
for file in "${processing[@]}"; do
echo >&2 -en "\nVM processing $(basename "$file" .begin)"
rm "$file"
done
fi
}
# Wait until all autofiles are processed (indicated by a "$STATUS_DIR/done"
# file created either by osbashauto or ssh_process_autostart)
function wait_for_autofiles {
shopt -s nullglob
${WBATCH:-:} wbatch_wait_auto
# Remove autostart files and return if we are just faking it for wbatch
${OSBASH:+:} autostart_reset
${OSBASH:+:} return 0
until [ -f "$STATUS_DIR/done" -o -f "$STATUS_DIR/error" ]; do
# Note: begin files (created by indicate_current_auto) are only visible
# if the STATUS_DIR directory is shared between host and VM
${WBATCH:-:} process_begin_files
echo >&2 -n .
sleep 1
done
# Check for remaining *.sh.begin files
${WBATCH:-:} process_begin_files
if [ -f "$STATUS_DIR/done" ]; then
rm "$STATUS_DIR/done"
else
echo -e >&2 "\nERROR occured. Exiting."
kill -- -$$
fi
echo
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Prepending numbers ensures scripts will be executed in the order they
# were added to the queue.
function _autostart_queue {
local src_path=$SCRIPTS_DIR/$1
local src_name=${1##*/}
# If we get a target name, file will be renamed
local target_name=${2:-$src_name}
if [[ $target_name = *.sh ]]; then
# Create target file name like 01_apt_init.sh
local prefix=$(get_next_prefix "$AUTOSTART_DIR" "sh" 2)
target_name="${prefix}_$target_name"
fi
if [ "$src_name" = "$target_name" ]; then
echo >&2 -e "\t$src_name"
else
echo >&2 -e "\t$src_name -> $target_name"
fi
cp -- "$src_path" "$AUTOSTART_DIR/$target_name"
${WBATCH:-:} wbatch_cp_auto "$src_path" "$AUTOSTART_DIR/$target_name"
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Print to the console which file requested guest scripts to run
function log_autostart_source {
# If the caller doesn't provide a config file, log the caller's source file
local src_file=${1:-${BASH_SOURCE[1]##*/}}
echo >&2 "Copying autostart files set in $src_file"
}
# autostart <src_dir> <file> <new_name>
# e.g. autostart osbash init_xxx_node.sh init_controller_node.sh
function autostart_and_rename {
local src_dir=$1
local src_file=$2
local target_file=$3
# Don't log this file -- log our caller's source file
log_autostart_source "${BASH_SOURCE[1]##*/}"
_autostart_queue "$src_dir/$src_file" "$target_file"
}
# autostart <file> [<file> ...]
# e.g. autostart zero_empty.sh osbash/base_fixups.sh
function autostart {
# Don't log this file -- log our caller's source file
log_autostart_source "${BASH_SOURCE[1]##*/}"
while (($#)); do
local src_file=$1
shift
_autostart_queue "$src_file"
done
}
# Parse options given to configuration commands. Return parsed values by
# setting variables to be used by caller.
function get_cmd_options {
local OPTIND
local opt
while getopts :g:n: opt; do
case $opt in
g)
vm_ui=$OPTARG
;;
n)
vm_name=$OPTARG
;;
*)
echo >&2 "Error: bad option $OPTARG."
exit 1
;;
esac
done
shift $((OPTIND-1))
# Assign the remaining arguments back to args
args=$@
}
# Parse command and arguments after a "cmd" token in config/scripts.*
function command_from_config {
local cmd=$1
shift
# Local variables that may be changed by get_cmd_options
local vm_name=${NODE_NAME:-""}
local vm_ui=${VM_UI:-""}
local args=$@
case "$cmd" in
boot)
# Format: boot [-g <gui_type>] [-n <node_name>]
# Boot with queued autostart files now, wait for end of scripts
# processing
get_cmd_options $args
echo >&2 "VM_UI=$vm_ui _vbox_boot_with_autostart $vm_name " \
"$VM_SSH_PORT"
VM_UI=$vm_ui _vbox_boot_with_autostart "$vm_name" "$VM_SSH_PORT"
;;
snapshot)
# Format: snapshot [-n <node_name>] <snapshot_name>
get_cmd_options $args
local shot_name=$args
echo >&2 vm_snapshot "$vm_name" "$shot_name"
vm_snapshot "$vm_name" "$shot_name"
;;
wait_for_shutdown)
# Format: wait_for_shutdown [-n <node_name>]
get_cmd_options $args
echo >&2 vm_wait_for_shutdown "$vm_name"
vm_wait_for_shutdown "$vm_name"
;;
snapshot_cycle)
# Format: snapshot_cycle [-g <gui_type>] [-n <node_name>]
# comprises shutdown, boot, wait_for_shutdown, snapshot
get_cmd_options $args
local shot_name=$args
echo >&2 snapshot_cycle "$vm_name" "$shot_name"
_autostart_queue "osbash/shutdown.sh"
_vbox_boot_with_autostart "$vm_name" "$VM_SSH_PORT"
vm_wait_for_shutdown "$vm_name"
vm_snapshot "$vm_name" "$shot_name"
;;
init_node)
# Format: init_node [-n <node_name>]
get_cmd_options $args
echo >&2 vm_init_node "$vm_name"
vm_init_node "$vm_name"
;;
queue)
# Queue a script for autostart
# Format: queue <script_name>
local script_rel_path=$args
echo >&2 _autostart_queue "$script_rel_path"
_autostart_queue "$script_rel_path"
;;
*)
echo >&2 "Error: invalid cmd: $cmd"
exit 1
;;
esac
}
# Parse config/scripts.* configuration files
function autostart_from_config {
local config_file=$1
local config_path=$CONFIG_DIR/$config_file
if [ ! -f "$config_path" ]; then
echo >&2 "Config file not found: $config_file"
return 1
fi
log_autostart_source "$config_file"
# Open file on file descriptor 3 so programs we call in this loop (ssh)
# are free to mess with the standard file descriptors.
exec 3< "$config_path"
while read -r field_1 field_2 <&3; do
if [[ $field_1 =~ ^# ]]; then
# Skip lines that are commented out
continue
elif [ "$field_1" == "cmd" ]; then
command_from_config $field_2
fi
done
}
#-------------------------------------------------------------------------------
# Functions to get install ISO images
#-------------------------------------------------------------------------------
function download {
local url=$1
local dest_dir=$2
local dest_file=$3
local rc=0
local wget_exe=$(which wget)
mkdir -pv "$dest_dir"
if [ -n "$wget_exe" ]; then
$wget_exe --output-document "$dest_dir/$dest_file" "$url"||rc=$?
else
# Mac OS X has curl instead of wget
local curl_exe=$(which curl)
if [ -n "$curl_exe" ]; then
$curl_exe "$url" -o "$dest_dir/$dest_file"||rc=$?
fi
fi
if [ $rc -ne 0 ]; then
echo >&2 "Unable to download $url, quitting."
exit 1
fi
}
function get_iso_name {
basename "${ISO_URL:-}"
}
function find_install-iso {
local iso_name=$1
if [ ! -f "$ISO_DIR/$iso_name" ]; then
echo >&2 "$iso_name not in $ISO_DIR; downloading"
download "$ISO_URL" "$ISO_DIR" "$iso_name"
fi
}
# vim: set ai ts=4 sw=4 et ft=sh: